Cycles: constant folding for RGB/Vector Curves and Color Ramp.
[blender.git] / intern / cycles / render / nodes.cpp
index 1594e8822db452690cd1cdd554bf5d84d1b8318d..b3b010841e99a388378f2f0feb26b37c86f8c2e1 100644 (file)
 #include "nodes.h"
 #include "scene.h"
 #include "svm.h"
 #include "nodes.h"
 #include "scene.h"
 #include "svm.h"
+#include "svm_color_util.h"
+#include "svm_ramp_util.h"
 #include "svm_math_util.h"
 #include "osl.h"
 #include "svm_math_util.h"
 #include "osl.h"
-#include "sky_model.h"
+#include "constant_fold.h"
 
 
+#include "util_sky_model.h"
 #include "util_foreach.h"
 #include "util_transform.h"
 
 #include "util_foreach.h"
 #include "util_transform.h"
 
@@ -30,24 +33,40 @@ CCL_NAMESPACE_BEGIN
 
 /* Texture Mapping */
 
 
 /* Texture Mapping */
 
+#define TEXTURE_MAPPING_DEFINE(TextureNode) \
+       SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \
+       SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f));      \
+       SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f));            \
+       \
+       SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \
+       SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX));    \
+       SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false);                     \
+       \
+       static NodeEnum mapping_axis_enum;                      \
+       mapping_axis_enum.insert("none", TextureMapping::NONE); \
+       mapping_axis_enum.insert("x", TextureMapping::X);       \
+       mapping_axis_enum.insert("y", TextureMapping::Y);       \
+       mapping_axis_enum.insert("z", TextureMapping::Z);       \
+       SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \
+       SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \
+       SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \
+       \
+       static NodeEnum mapping_type_enum;                            \
+       mapping_type_enum.insert("point", TextureMapping::POINT);     \
+       mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \
+       mapping_type_enum.insert("vector", TextureMapping::VECTOR);   \
+       mapping_type_enum.insert("normal", TextureMapping::NORMAL);   \
+       SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \
+       \
+       static NodeEnum mapping_projection_enum;                                                \
+       mapping_projection_enum.insert("flat", TextureMapping::FLAT);                           \
+       mapping_projection_enum.insert("cube", TextureMapping::CUBE);                           \
+       mapping_projection_enum.insert("tube", TextureMapping::TUBE);                           \
+       mapping_projection_enum.insert("sphere", TextureMapping::SPHERE);                       \
+       SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT);
+
 TextureMapping::TextureMapping()
 {
 TextureMapping::TextureMapping()
 {
-       translation = make_float3(0.0f, 0.0f, 0.0f);
-       rotation = make_float3(0.0f, 0.0f, 0.0f);
-       scale = make_float3(1.0f, 1.0f, 1.0f);
-
-       min = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
-       max = make_float3(FLT_MAX, FLT_MAX, FLT_MAX);
-
-       use_minmax = false;
-
-       x_mapping = X;
-       y_mapping = Y;
-       z_mapping = Z;
-
-       type = TEXTURE;
-
-       projection = FLAT;
 }
 
 Transform TextureMapping::compute_transform()
 }
 
 Transform TextureMapping::compute_transform()
@@ -127,9 +146,6 @@ bool TextureMapping::skip()
 
 void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_out)
 {
 
 void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_out)
 {
-       if(offset_in == SVM_STACK_INVALID || offset_out == SVM_STACK_INVALID)
-               return;
-
        compiler.add_node(NODE_MAPPING, offset_in, offset_out);
 
        Transform tfm = compute_transform();
        compiler.add_node(NODE_MAPPING, offset_in, offset_out);
 
        Transform tfm = compute_transform();
@@ -150,6 +166,29 @@ void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_ou
        }
 }
 
        }
 }
 
+/* Convenience function for texture nodes, allocating stack space to output
+ * a modified vector and returning its offset */
+int TextureMapping::compile_begin(SVMCompiler& compiler, ShaderInput *vector_in)
+{
+       if(!skip()) {
+               int offset_in = compiler.stack_assign(vector_in);
+               int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
+
+               compile(compiler, offset_in, offset_out);
+
+               return offset_out;
+       }
+
+       return compiler.stack_assign(vector_in);
+}
+
+void TextureMapping::compile_end(SVMCompiler& compiler, ShaderInput *vector_in, int vector_offset)
+{
+       if(!skip()) {
+               compiler.stack_clear_offset(vector_in->type(), vector_offset);
+       }
+}
+
 void TextureMapping::compile(OSLCompiler &compiler)
 {
        if(!skip()) {
 void TextureMapping::compile(OSLCompiler &compiler)
 {
        if(!skip()) {
@@ -162,72 +201,66 @@ void TextureMapping::compile(OSLCompiler &compiler)
 
 /* Image Texture */
 
 
 /* Image Texture */
 
-static ShaderEnum color_space_init()
+NODE_DEFINE(ImageTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("image_texture", create, NodeType::SHADER);
 
 
-       enm.insert("None", 0);
-       enm.insert("Color", 1);
+       TEXTURE_MAPPING_DEFINE(ImageTextureNode);
 
 
-       return enm;
-}
+       SOCKET_STRING(filename, "Filename", ustring(""));
 
 
-static ShaderEnum image_projection_init()
-{
-       ShaderEnum enm;
+       static NodeEnum color_space_enum;
+       color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
+       color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
+       SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
 
 
-       enm.insert("Flat", NODE_IMAGE_PROJ_FLAT);
-       enm.insert("Box", NODE_IMAGE_PROJ_BOX);
-       enm.insert("Sphere", NODE_IMAGE_PROJ_SPHERE);
-       enm.insert("Tube", NODE_IMAGE_PROJ_TUBE);
+       SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
 
 
-       return enm;
-}
+       static NodeEnum interpolation_enum;
+       interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+       interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+       interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+       interpolation_enum.insert("smart", INTERPOLATION_SMART);
+       SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
 
 
-static const char* get_osl_interpolation_parameter(InterpolationType interpolation)
-{
-       switch(interpolation) {
-               case INTERPOLATION_CLOSEST:
-                       return "closest";
-               case INTERPOLATION_CUBIC:
-                       return "cubic";
-               case INTERPOLATION_SMART:
-                       return "smart";
-               case INTERPOLATION_LINEAR:
-               default:
-                       return "linear";
-       }
-}
+       static NodeEnum extension_enum;
+       extension_enum.insert("periodic", EXTENSION_REPEAT);
+       extension_enum.insert("clamp", EXTENSION_EXTEND);
+       extension_enum.insert("black", EXTENSION_CLIP);
+       SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
+
+       static NodeEnum projection_enum;
+       projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT);
+       projection_enum.insert("box", NODE_IMAGE_PROJ_BOX);
+       projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE);
+       projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE);
+       SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT);
 
 
-ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
-ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
+       SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV);
+
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+       return type;
+}
 
 ImageTextureNode::ImageTextureNode()
 
 ImageTextureNode::ImageTextureNode()
-: ImageSlotTextureNode("image_texture")
+: ImageSlotTextureNode(node_type)
 {
        image_manager = NULL;
        slot = -1;
        is_float = -1;
        is_linear = false;
 {
        image_manager = NULL;
        slot = -1;
        is_float = -1;
        is_linear = false;
-       use_alpha = true;
-       filename = "";
        builtin_data = NULL;
        builtin_data = NULL;
-       color_space = ustring("Color");
-       projection = ustring("Flat");
-       interpolation = INTERPOLATION_LINEAR;
-       extension = EXTENSION_REPEAT;
-       projection_blend = 0.0f;
        animated = false;
        animated = false;
-
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV);
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Alpha", SHADER_SOCKET_FLOAT);
 }
 
 ImageTextureNode::~ImageTextureNode()
 {
        if(image_manager) {
 }
 
 ImageTextureNode::~ImageTextureNode()
 {
        if(image_manager) {
-               image_manager->remove_image(filename,
+               image_manager->remove_image(filename.string(),
                                            builtin_data,
                                            interpolation,
                                            extension);
                                            builtin_data,
                                            interpolation,
                                            extension);
@@ -268,7 +301,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
        image_manager = compiler.image_manager;
        if(is_float == -1) {
                bool is_float_bool;
        image_manager = compiler.image_manager;
        if(is_float == -1) {
                bool is_float_bool;
-               slot = image_manager->add_image(filename,
+               slot = image_manager->add_image(filename.string(),
                                                builtin_data,
                                                animated,
                                                0,
                                                builtin_data,
                                                animated,
                                                0,
@@ -280,56 +313,43 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
                is_float = (int)is_float_bool;
        }
 
                is_float = (int)is_float_bool;
        }
 
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
-       if(!alpha_out->links.empty())
-               compiler.stack_assign(alpha_out);
-
        if(slot != -1) {
        if(slot != -1) {
-               compiler.stack_assign(vector_in);
-
-               int srgb = (is_linear || color_space != "Color")? 0: 1;
-               int vector_offset = vector_in->stack_offset;
-
-               if(!tex_mapping.skip()) {
-                       vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-                       tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-               }
+               int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
+               int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
 
-               if(projection != "Box") {
+               if(projection != NODE_IMAGE_PROJ_BOX) {
                        compiler.add_node(NODE_TEX_IMAGE,
                                slot,
                                compiler.encode_uchar4(
                                        vector_offset,
                        compiler.add_node(NODE_TEX_IMAGE,
                                slot,
                                compiler.encode_uchar4(
                                        vector_offset,
-                                       color_out->stack_offset,
-                                       alpha_out->stack_offset,
+                                       compiler.stack_assign_if_linked(color_out),
+                                       compiler.stack_assign_if_linked(alpha_out),
                                        srgb),
                                        srgb),
-                               projection_enum[projection]);
+                               projection);
                }
                else {
                        compiler.add_node(NODE_TEX_IMAGE_BOX,
                                slot,
                                compiler.encode_uchar4(
                                        vector_offset,
                }
                else {
                        compiler.add_node(NODE_TEX_IMAGE_BOX,
                                slot,
                                compiler.encode_uchar4(
                                        vector_offset,
-                                       color_out->stack_offset,
-                                       alpha_out->stack_offset,
+                                       compiler.stack_assign_if_linked(color_out),
+                                       compiler.stack_assign_if_linked(alpha_out),
                                        srgb),
                                __float_as_int(projection_blend));
                }
 
                                        srgb),
                                __float_as_int(projection_blend));
                }
 
-               if(vector_offset != vector_in->stack_offset)
-                       compiler.stack_clear_offset(vector_in->type, vector_offset);
+               tex_mapping.compile_end(compiler, vector_in, vector_offset);
        }
        else {
                /* image not found */
                if(!color_out->links.empty()) {
        }
        else {
                /* image not found */
                if(!color_out->links.empty()) {
-                       compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
+                       compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
                        compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
                                                                    TEX_IMAGE_MISSING_G,
                                                                    TEX_IMAGE_MISSING_B));
                }
                if(!alpha_out->links.empty())
                        compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
                                                                    TEX_IMAGE_MISSING_G,
                                                                    TEX_IMAGE_MISSING_B));
                }
                if(!alpha_out->links.empty())
-                       compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), alpha_out->stack_offset);
+                       compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out));
        }
 }
 
        }
 }
 
@@ -342,11 +362,14 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
        image_manager = compiler.image_manager;
        if(is_float == -1) {
                if(builtin_data == NULL) {
        image_manager = compiler.image_manager;
        if(is_float == -1) {
                if(builtin_data == NULL) {
-                       is_float = (int)image_manager->is_float_image(filename, NULL, is_linear);
+                       ImageManager::ImageDataType type;
+                       type = image_manager->get_image_metadata(filename.string(), NULL, is_linear);
+                       if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
+                               is_float = 1;
                }
                else {
                        bool is_float_bool;
                }
                else {
                        bool is_float_bool;
-                       slot = image_manager->add_image(filename,
+                       slot = image_manager->add_image(filename.string(),
                                                        builtin_data,
                                                        animated,
                                                        0,
                                                        builtin_data,
                                                        animated,
                                                        0,
@@ -360,7 +383,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
        }
 
        if(slot == -1) {
        }
 
        if(slot == -1) {
-               compiler.parameter("filename", filename.c_str());
+               compiler.parameter(this, "filename");
        }
        else {
                /* TODO(sergey): It's not so simple to pass custom attribute
        }
        else {
                /* TODO(sergey): It's not so simple to pass custom attribute
@@ -371,71 +394,72 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
                 */
                compiler.parameter("filename", string_printf("@%d", slot).c_str());
        }
                 */
                compiler.parameter("filename", string_printf("@%d", slot).c_str());
        }
-       if(is_linear || color_space != "Color")
-               compiler.parameter("color_space", "Linear");
+       if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
+               compiler.parameter("color_space", "linear");
        else
                compiler.parameter("color_space", "sRGB");
        else
                compiler.parameter("color_space", "sRGB");
-       compiler.parameter("projection", projection);
-       compiler.parameter("projection_blend", projection_blend);
+       compiler.parameter(this, "projection");
+       compiler.parameter(this, "projection_blend");
        compiler.parameter("is_float", is_float);
        compiler.parameter("use_alpha", !alpha_out->links.empty());
        compiler.parameter("is_float", is_float);
        compiler.parameter("use_alpha", !alpha_out->links.empty());
-       compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation));
-
-       switch(extension) {
-               case EXTENSION_EXTEND:
-                       compiler.parameter("wrap", "clamp");
-                       break;
-               case EXTENSION_CLIP:
-                       compiler.parameter("wrap", "black");
-                       break;
-               case EXTENSION_REPEAT:
-               default:
-                       compiler.parameter("wrap", "periodic");
-                       break;
-       }
+       compiler.parameter(this, "interpolation");
+       compiler.parameter(this, "extension");
 
        compiler.add(this, "node_image_texture");
 }
 
 /* Environment Texture */
 
 
        compiler.add(this, "node_image_texture");
 }
 
 /* Environment Texture */
 
-static ShaderEnum env_projection_init()
+NODE_DEFINE(EnvironmentTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("environment_texture", create, NodeType::SHADER);
 
 
-       enm.insert("Equirectangular", 0);
-       enm.insert("Mirror Ball", 1);
+       TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
 
 
-       return enm;
-}
+       SOCKET_STRING(filename, "Filename", ustring(""));
+
+       static NodeEnum color_space_enum;
+       color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
+       color_space_enum.insert("color", NODE_COLOR_SPACE_COLOR);
+       SOCKET_ENUM(color_space, "Color Space", color_space_enum, NODE_COLOR_SPACE_COLOR);
+
+       SOCKET_BOOLEAN(use_alpha, "Use Alpha", true);
+
+       static NodeEnum interpolation_enum;
+       interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+       interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+       interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+       interpolation_enum.insert("smart", INTERPOLATION_SMART);
+       SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
+
+       static NodeEnum projection_enum;
+       projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR);
+       projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
+       SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
 
 
-ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
-ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+       return type;
+}
 
 EnvironmentTextureNode::EnvironmentTextureNode()
 
 EnvironmentTextureNode::EnvironmentTextureNode()
-: ImageSlotTextureNode("environment_texture")
+: ImageSlotTextureNode(node_type)
 {
        image_manager = NULL;
        slot = -1;
        is_float = -1;
        is_linear = false;
 {
        image_manager = NULL;
        slot = -1;
        is_float = -1;
        is_linear = false;
-       use_alpha = true;
-       filename = "";
        builtin_data = NULL;
        builtin_data = NULL;
-       color_space = ustring("Color");
-       interpolation = INTERPOLATION_LINEAR;
-       projection = ustring("Equirectangular");
        animated = false;
        animated = false;
-
-       add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Alpha", SHADER_SOCKET_FLOAT);
 }
 
 EnvironmentTextureNode::~EnvironmentTextureNode()
 {
        if(image_manager) {
 }
 
 EnvironmentTextureNode::~EnvironmentTextureNode()
 {
        if(image_manager) {
-               image_manager->remove_image(filename,
+               image_manager->remove_image(filename.string(),
                                            builtin_data,
                                            interpolation,
                                            EXTENSION_REPEAT);
                                            builtin_data,
                                            interpolation,
                                            EXTENSION_REPEAT);
@@ -474,7 +498,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
        image_manager = compiler.image_manager;
        if(slot == -1) {
                bool is_float_bool;
        image_manager = compiler.image_manager;
        if(slot == -1) {
                bool is_float_bool;
-               slot = image_manager->add_image(filename,
+               slot = image_manager->add_image(filename.string(),
                                                builtin_data,
                                                animated,
                                                0,
                                                builtin_data,
                                                animated,
                                                0,
@@ -486,44 +510,31 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
                is_float = (int)is_float_bool;
        }
 
                is_float = (int)is_float_bool;
        }
 
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
-       if(!alpha_out->links.empty())
-               compiler.stack_assign(alpha_out);
-       
        if(slot != -1) {
        if(slot != -1) {
-               compiler.stack_assign(vector_in);
-
-               int srgb = (is_linear || color_space != "Color")? 0: 1;
-               int vector_offset = vector_in->stack_offset;
-
-               if(!tex_mapping.skip()) {
-                       vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-                       tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-               }
+               int srgb = (is_linear || color_space != NODE_COLOR_SPACE_COLOR)? 0: 1;
+               int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
                compiler.add_node(NODE_TEX_ENVIRONMENT,
                        slot,
                        compiler.encode_uchar4(
                                vector_offset,
 
                compiler.add_node(NODE_TEX_ENVIRONMENT,
                        slot,
                        compiler.encode_uchar4(
                                vector_offset,
-                               color_out->stack_offset,
-                               alpha_out->stack_offset,
+                               compiler.stack_assign_if_linked(color_out),
+                               compiler.stack_assign_if_linked(alpha_out),
                                srgb),
                                srgb),
-                       projection_enum[projection]);
+                       projection);
        
        
-               if(vector_offset != vector_in->stack_offset)
-                       compiler.stack_clear_offset(vector_in->type, vector_offset);
+               tex_mapping.compile_end(compiler, vector_in, vector_offset);
        }
        else {
                /* image not found */
                if(!color_out->links.empty()) {
        }
        else {
                /* image not found */
                if(!color_out->links.empty()) {
-                       compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
+                       compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
                        compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
                                                                    TEX_IMAGE_MISSING_G,
                                                                    TEX_IMAGE_MISSING_B));
                }
                if(!alpha_out->links.empty())
                        compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
                                                                    TEX_IMAGE_MISSING_G,
                                                                    TEX_IMAGE_MISSING_B));
                }
                if(!alpha_out->links.empty())
-                       compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), alpha_out->stack_offset);
+                       compiler.add_node(NODE_VALUE_F, __float_as_int(TEX_IMAGE_MISSING_A), compiler.stack_assign(alpha_out));
        }
 }
 
        }
 }
 
@@ -539,11 +550,14 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
        image_manager = compiler.image_manager;
        if(is_float == -1) {
                if(builtin_data == NULL) {
        image_manager = compiler.image_manager;
        if(is_float == -1) {
                if(builtin_data == NULL) {
-                       is_float = (int)image_manager->is_float_image(filename, NULL, is_linear);
+                       ImageManager::ImageDataType type;
+                       type = image_manager->get_image_metadata(filename.string(), NULL, is_linear);
+                       if(type == ImageManager::IMAGE_DATA_TYPE_FLOAT || type == ImageManager::IMAGE_DATA_TYPE_FLOAT4)
+                               is_float = 1;
                }
                else {
                        bool is_float_bool;
                }
                else {
                        bool is_float_bool;
-                       slot = image_manager->add_image(filename,
+                       slot = image_manager->add_image(filename.string(),
                                                        builtin_data,
                                                        animated,
                                                        0,
                                                        builtin_data,
                                                        animated,
                                                        0,
@@ -557,19 +571,18 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
        }
 
        if(slot == -1) {
        }
 
        if(slot == -1) {
-               compiler.parameter("filename", filename.c_str());
+               compiler.parameter(this, "filename");
        }
        else {
                compiler.parameter("filename", string_printf("@%d", slot).c_str());
        }
        }
        else {
                compiler.parameter("filename", string_printf("@%d", slot).c_str());
        }
-       compiler.parameter("projection", projection);
-       if(is_linear || color_space != "Color")
-               compiler.parameter("color_space", "Linear");
+       compiler.parameter(this, "projection");
+       if(is_linear || color_space != NODE_COLOR_SPACE_COLOR)
+               compiler.parameter("color_space", "linear");
        else
                compiler.parameter("color_space", "sRGB");
 
        else
                compiler.parameter("color_space", "sRGB");
 
-       compiler.parameter("interpolation", get_osl_interpolation_parameter(interpolation));
-
+       compiler.parameter(this, "interpolation");
        compiler.parameter("is_float", is_float);
        compiler.parameter("use_alpha", !alpha_out->links.empty());
        compiler.add(this, "node_environment_texture");
        compiler.parameter("is_float", is_float);
        compiler.parameter("use_alpha", !alpha_out->links.empty());
        compiler.add(this, "node_environment_texture");
@@ -600,10 +613,10 @@ static float sky_perez_function(float lam[6], float theta, float gamma)
 static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity)
 {
        /*
 static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity)
 {
        /*
-       * We re-use the SunSky struct of the new model, to avoid extra variables
-       * zenith_Y/x/y is now radiance_x/y/z
-       * perez_Y/x/y is now config_x/y/z
-       */
+        * We re-use the SunSky struct of the new model, to avoid extra variables
+        * zenith_Y/x/y is now radiance_x/y/z
+        * perez_Y/x/y is now config_x/y/z
+        */
        
        float2 spherical = sky_spherical_coordinates(dir);
        float theta = spherical.x;
        
        float2 spherical = sky_spherical_coordinates(dir);
        float theta = spherical.x;
@@ -678,11 +691,11 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi
        sunsky->theta = theta;
        sunsky->phi = phi;
 
        sunsky->theta = theta;
        sunsky->phi = phi;
 
-       double solarElevation = M_PI_2_F - theta;
+       float solarElevation = M_PI_2_F - theta;
 
        /* Initialize Sky Model */
        ArHosekSkyModelState *sky_state;
 
        /* Initialize Sky Model */
        ArHosekSkyModelState *sky_state;
-       sky_state = arhosek_xyz_skymodelstate_alloc_init(turbidity, ground_albedo, solarElevation);
+       sky_state = arhosek_xyz_skymodelstate_alloc_init((double)turbidity, (double)ground_albedo, (double)solarElevation);
 
        /* Copy values from sky_state to SunSky */
        for(int i = 0; i < 9; ++i) {
 
        /* Copy values from sky_state to SunSky */
        for(int i = 0; i < 9; ++i) {
@@ -698,29 +711,31 @@ static void sky_texture_precompute_new(SunSky *sunsky, float3 dir, float turbidi
        arhosekskymodelstate_free(sky_state);
 }
 
        arhosekskymodelstate_free(sky_state);
 }
 
-static ShaderEnum sky_type_init()
+NODE_DEFINE(SkyTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("sky_texture", create, NodeType::SHADER);
 
 
-       enm.insert("Preetham", NODE_SKY_OLD);
-       enm.insert("Hosek / Wilkie", NODE_SKY_NEW);
+       TEXTURE_MAPPING_DEFINE(SkyTextureNode);
 
 
-       return enm;
-}
+       static NodeEnum type_enum;
+       type_enum.insert("preetham", NODE_SKY_OLD);
+       type_enum.insert("hosek_wilkie", NODE_SKY_NEW);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NEW);
+
+       SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
+       SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
+       SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 
 
-ShaderEnum SkyTextureNode::type_enum = sky_type_init();
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
 
 SkyTextureNode::SkyTextureNode()
 
 SkyTextureNode::SkyTextureNode()
-: TextureNode("sky_texture")
+: TextureNode(node_type)
 {
 {
-       type = ustring("Hosek / Wilkie");
-       
-       sun_direction = make_float3(0.0f, 0.0f, 1.0f);
-       turbidity = 2.2f;
-       ground_albedo = 0.3f;
-
-       add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION);
-       add_output("Color", SHADER_SOCKET_COLOR);
 }
 
 void SkyTextureNode::compile(SVMCompiler& compiler)
 }
 
 void SkyTextureNode::compile(SVMCompiler& compiler)
@@ -729,26 +744,17 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
 
        SunSky sunsky;
        ShaderOutput *color_out = output("Color");
 
        SunSky sunsky;
-       if(type_enum[type] == NODE_SKY_OLD)
+       if(type == NODE_SKY_OLD)
                sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
                sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
-       else if(type_enum[type] == NODE_SKY_NEW)
+       else if(type == NODE_SKY_NEW)
                sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
        else
                assert(false);
 
                sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
        else
                assert(false);
 
-       if(vector_in->link)
-               compiler.stack_assign(vector_in);
-
-       int vector_offset = vector_in->stack_offset;
-       int sky_model = type_enum[type];
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.stack_assign(color_out);
 
        compiler.stack_assign(color_out);
-       compiler.add_node(NODE_TEX_SKY, vector_offset, color_out->stack_offset, sky_model);
+       compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type);
        compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y));
        compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2]));
        compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6]));
        compiler.add_node(__float_as_uint(sunsky.phi), __float_as_uint(sunsky.theta), __float_as_uint(sunsky.radiance_x), __float_as_uint(sunsky.radiance_y));
        compiler.add_node(__float_as_uint(sunsky.radiance_z), __float_as_uint(sunsky.config_x[0]), __float_as_uint(sunsky.config_x[1]), __float_as_uint(sunsky.config_x[2]));
        compiler.add_node(__float_as_uint(sunsky.config_x[3]), __float_as_uint(sunsky.config_x[4]), __float_as_uint(sunsky.config_x[5]), __float_as_uint(sunsky.config_x[6]));
@@ -758,8 +764,7 @@ void SkyTextureNode::compile(SVMCompiler& compiler)
        compiler.add_node(__float_as_uint(sunsky.config_z[1]), __float_as_uint(sunsky.config_z[2]), __float_as_uint(sunsky.config_z[3]), __float_as_uint(sunsky.config_z[4]));
        compiler.add_node(__float_as_uint(sunsky.config_z[5]), __float_as_uint(sunsky.config_z[6]), __float_as_uint(sunsky.config_z[7]), __float_as_uint(sunsky.config_z[8]));
 
        compiler.add_node(__float_as_uint(sunsky.config_z[1]), __float_as_uint(sunsky.config_z[2]), __float_as_uint(sunsky.config_z[3]), __float_as_uint(sunsky.config_z[4]));
        compiler.add_node(__float_as_uint(sunsky.config_z[5]), __float_as_uint(sunsky.config_z[6]), __float_as_uint(sunsky.config_z[7]), __float_as_uint(sunsky.config_z[8]));
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void SkyTextureNode::compile(OSLCompiler& compiler)
 }
 
 void SkyTextureNode::compile(OSLCompiler& compiler)
@@ -767,15 +772,14 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
        tex_mapping.compile(compiler);
 
        SunSky sunsky;
        tex_mapping.compile(compiler);
 
        SunSky sunsky;
-
-       if(type_enum[type] == NODE_SKY_OLD)
+       if(type == NODE_SKY_OLD)
                sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
                sky_texture_precompute_old(&sunsky, sun_direction, turbidity);
-       else if(type_enum[type] == NODE_SKY_NEW)
+       else if(type == NODE_SKY_NEW)
                sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
        else
                assert(false);
                
                sky_texture_precompute_new(&sunsky, sun_direction, turbidity, ground_albedo);
        else
                assert(false);
                
-       compiler.parameter("sky_model", type);
+       compiler.parameter(this, "type");
        compiler.parameter("theta", sunsky.theta);
        compiler.parameter("phi", sunsky.phi);
        compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
        compiler.parameter("theta", sunsky.theta);
        compiler.parameter("phi", sunsky.phi);
        compiler.parameter_color("radiance", make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
@@ -787,31 +791,33 @@ void SkyTextureNode::compile(OSLCompiler& compiler)
 
 /* Gradient Texture */
 
 
 /* Gradient Texture */
 
-static ShaderEnum gradient_type_init()
+NODE_DEFINE(GradientTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("gradient_texture", create, NodeType::SHADER);
 
 
-       enm.insert("Linear", NODE_BLEND_LINEAR);
-       enm.insert("Quadratic", NODE_BLEND_QUADRATIC);
-       enm.insert("Easing", NODE_BLEND_EASING);
-       enm.insert("Diagonal", NODE_BLEND_DIAGONAL);
-       enm.insert("Radial", NODE_BLEND_RADIAL);
-       enm.insert("Quadratic Sphere", NODE_BLEND_QUADRATIC_SPHERE);
-       enm.insert("Spherical", NODE_BLEND_SPHERICAL);
+       TEXTURE_MAPPING_DEFINE(GradientTextureNode);
 
 
-       return enm;
-}
+       static NodeEnum type_enum;
+       type_enum.insert("linear", NODE_BLEND_LINEAR);
+       type_enum.insert("quadratic", NODE_BLEND_QUADRATIC);
+       type_enum.insert("easing", NODE_BLEND_EASING);
+       type_enum.insert("diagonal", NODE_BLEND_DIAGONAL);
+       type_enum.insert("radial", NODE_BLEND_RADIAL);
+       type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
+       type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 
 
-ShaderEnum GradientTextureNode::type_enum = gradient_type_init();
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
+
+       return type;
+}
 
 GradientTextureNode::GradientTextureNode()
 
 GradientTextureNode::GradientTextureNode()
-: TextureNode("gradient_texture")
+: TextureNode(node_type)
 {
 {
-       type = ustring("Linear");
-
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
 }
 
 void GradientTextureNode::compile(SVMCompiler& compiler)
 }
 
 void GradientTextureNode::compile(SVMCompiler& compiler)
@@ -820,47 +826,48 @@ void GradientTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
-       if(vector_in->link) compiler.stack_assign(vector_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       if(!fac_out->links.empty())
-               compiler.stack_assign(fac_out);
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_GRADIENT,
 
        compiler.add_node(NODE_TEX_GRADIENT,
-               compiler.encode_uchar4(type_enum[type], vector_offset, fac_out->stack_offset, color_out->stack_offset));
+               compiler.encode_uchar4(
+                       type,
+                       vector_offset,
+                       compiler.stack_assign_if_linked(fac_out),
+                       compiler.stack_assign_if_linked(color_out)));
 
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void GradientTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
 }
 
 void GradientTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
-       compiler.parameter("Type", type);
+       compiler.parameter(this, "type");
        compiler.add(this, "node_gradient_texture");
 }
 
 /* Noise Texture */
 
        compiler.add(this, "node_gradient_texture");
 }
 
 /* Noise Texture */
 
-NoiseTextureNode::NoiseTextureNode()
-: TextureNode("noise_texture")
+NODE_DEFINE(NoiseTextureNode)
 {
 {
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-       add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
-       add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
+       NodeType* type = NodeType::add("noise_texture", create, NodeType::SHADER);
+
+       TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
 
 
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
+       SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+       SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+       SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
+
+       return type;
+}
+
+NoiseTextureNode::NoiseTextureNode()
+: TextureNode(node_type)
+{
 }
 
 void NoiseTextureNode::compile(SVMCompiler& compiler)
 }
 
 void NoiseTextureNode::compile(SVMCompiler& compiler)
@@ -872,33 +879,23 @@ void NoiseTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
-       if(vector_in->link) compiler.stack_assign(vector_in);
-       if(scale_in->link) compiler.stack_assign(scale_in);
-       if(detail_in->link) compiler.stack_assign(detail_in);
-       if(distortion_in->link) compiler.stack_assign(distortion_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       if(!fac_out->links.empty())
-               compiler.stack_assign(fac_out);
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_NOISE,
 
        compiler.add_node(NODE_TEX_NOISE,
-               compiler.encode_uchar4(vector_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset),
-               compiler.encode_uchar4(color_out->stack_offset, fac_out->stack_offset));
+               compiler.encode_uchar4(
+                       vector_offset,
+                       compiler.stack_assign_if_linked(scale_in),
+                       compiler.stack_assign_if_linked(detail_in),
+                       compiler.stack_assign_if_linked(distortion_in)),
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(color_out),
+                       compiler.stack_assign_if_linked(fac_out)));
        compiler.add_node(
        compiler.add_node(
-               __float_as_int(scale_in->value.x),
-               __float_as_int(detail_in->value.x),
-               __float_as_int(distortion_in->value.x));
+               __float_as_int(scale),
+               __float_as_int(detail),
+               __float_as_int(distortion));
 
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void NoiseTextureNode::compile(OSLCompiler& compiler)
 }
 
 void NoiseTextureNode::compile(OSLCompiler& compiler)
@@ -910,28 +907,29 @@ void NoiseTextureNode::compile(OSLCompiler& compiler)
 
 /* Voronoi Texture */
 
 
 /* Voronoi Texture */
 
-static ShaderEnum voronoi_coloring_init()
+NODE_DEFINE(VoronoiTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
 
 
-       enm.insert("Intensity", NODE_VORONOI_INTENSITY);
-       enm.insert("Cells", NODE_VORONOI_CELLS);
+       TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
 
 
-       return enm;
-}
+       static NodeEnum coloring_enum;
+       coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY);
+       coloring_enum.insert("cells", NODE_VORONOI_CELLS);
+       SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY);
 
 
-ShaderEnum VoronoiTextureNode::coloring_enum  = voronoi_coloring_init();
+       SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 
 
-VoronoiTextureNode::VoronoiTextureNode()
-: TextureNode("voronoi_texture")
-{
-       coloring = ustring("Intensity");
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
 
 
-       add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
+       return type;
+}
 
 
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
+VoronoiTextureNode::VoronoiTextureNode()
+: TextureNode(node_type)
+{
 }
 
 void VoronoiTextureNode::compile(SVMCompiler& compiler)
 }
 
 void VoronoiTextureNode::compile(SVMCompiler& compiler)
@@ -941,68 +939,61 @@ void VoronoiTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
-       if(vector_in->link) compiler.stack_assign(vector_in);
-       if(scale_in->link) compiler.stack_assign(scale_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       compiler.stack_assign(color_out);
-       compiler.stack_assign(fac_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_VORONOI,
 
        compiler.add_node(NODE_TEX_VORONOI,
-               coloring_enum[coloring],
-               compiler.encode_uchar4(scale_in->stack_offset, vector_offset, fac_out->stack_offset, color_out->stack_offset),
-               __float_as_int(scale_in->value.x));
+               coloring,
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(scale_in),
+                       vector_offset,
+                       compiler.stack_assign(fac_out),
+                       compiler.stack_assign(color_out)),
+               __float_as_int(scale));
 
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void VoronoiTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
 }
 
 void VoronoiTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
-       compiler.parameter("Coloring", coloring);
+       compiler.parameter(this, "coloring");
        compiler.add(this, "node_voronoi_texture");
 }
 
 /* Musgrave Texture */
 
        compiler.add(this, "node_voronoi_texture");
 }
 
 /* Musgrave Texture */
 
-static ShaderEnum musgrave_type_init()
+NODE_DEFINE(MusgraveTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("musgrave_texture", create, NodeType::SHADER);
 
 
-       enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
-       enm.insert("fBM", NODE_MUSGRAVE_FBM);
-       enm.insert("Hybrid Multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
-       enm.insert("Ridged Multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
-       enm.insert("Hetero Terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
+       TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
 
 
-       return enm;
-}
+       static NodeEnum type_enum;
+       type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
+       type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
+       type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
+       type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
+       type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM);
 
 
-ShaderEnum MusgraveTextureNode::type_enum = musgrave_type_init();
+       SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+       SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+       SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f);
+       SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f);
+       SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
+       SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 
 
-MusgraveTextureNode::MusgraveTextureNode()
-: TextureNode("musgrave_texture")
-{
-       type = ustring("fBM");
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
 
 
-       add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-       add_input("Dimension", SHADER_SOCKET_FLOAT, 2.0f);
-       add_input("Lacunarity", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Offset", SHADER_SOCKET_FLOAT, 0.0f);
-       add_input("Gain", SHADER_SOCKET_FLOAT, 1.0f);
+       return type;
+}
 
 
-       add_output("Fac", SHADER_SOCKET_FLOAT);
-       add_output("Color", SHADER_SOCKET_COLOR);
+MusgraveTextureNode::MusgraveTextureNode()
+: TextureNode(node_type)
+{
 }
 
 void MusgraveTextureNode::compile(SVMCompiler& compiler)
 }
 
 void MusgraveTextureNode::compile(SVMCompiler& compiler)
@@ -1017,77 +1008,73 @@ void MusgraveTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *fac_out = output("Fac");
        ShaderOutput *color_out = output("Color");
 
        ShaderOutput *fac_out = output("Fac");
        ShaderOutput *color_out = output("Color");
 
-       if(vector_in->link) compiler.stack_assign(vector_in);
-       if(dimension_in->link) compiler.stack_assign(dimension_in);
-       if(lacunarity_in->link) compiler.stack_assign(lacunarity_in);
-       if(detail_in->link) compiler.stack_assign(detail_in);
-       if(offset_in->link) compiler.stack_assign(offset_in);
-       if(gain_in->link) compiler.stack_assign(gain_in);
-       if(scale_in->link) compiler.stack_assign(scale_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       if(!fac_out->links.empty())
-               compiler.stack_assign(fac_out);
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_MUSGRAVE,
 
        compiler.add_node(NODE_TEX_MUSGRAVE,
-               compiler.encode_uchar4(type_enum[type], vector_offset, color_out->stack_offset, fac_out->stack_offset),
-               compiler.encode_uchar4(dimension_in->stack_offset, lacunarity_in->stack_offset, detail_in->stack_offset, offset_in->stack_offset),
-               compiler.encode_uchar4(gain_in->stack_offset, scale_in->stack_offset));
-       compiler.add_node(__float_as_int(dimension_in->value.x),
-               __float_as_int(lacunarity_in->value.x),
-               __float_as_int(detail_in->value.x),
-               __float_as_int(offset_in->value.x));
-       compiler.add_node(__float_as_int(gain_in->value.x),
-               __float_as_int(scale_in->value.x));
+               compiler.encode_uchar4(
+                       type,
+                       vector_offset,
+                       compiler.stack_assign_if_linked(color_out),
+                       compiler.stack_assign_if_linked(fac_out)),
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(dimension_in),
+                       compiler.stack_assign_if_linked(lacunarity_in),
+                       compiler.stack_assign_if_linked(detail_in),
+                       compiler.stack_assign_if_linked(offset_in)),
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(gain_in),
+                       compiler.stack_assign_if_linked(scale_in)));
+       compiler.add_node(__float_as_int(dimension),
+               __float_as_int(lacunarity),
+               __float_as_int(detail),
+               __float_as_int(offset));
+       compiler.add_node(__float_as_int(gain),
+               __float_as_int(scale));
 
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void MusgraveTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
 }
 
 void MusgraveTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
-       compiler.parameter("Type", type);
-
+       compiler.parameter(this, "type");
        compiler.add(this, "node_musgrave_texture");
 }
 
 /* Wave Texture */
 
        compiler.add(this, "node_musgrave_texture");
 }
 
 /* Wave Texture */
 
-static ShaderEnum wave_type_init()
+NODE_DEFINE(WaveTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("wave_texture", create, NodeType::SHADER);
 
 
-       enm.insert("Bands", NODE_WAVE_BANDS);
-       enm.insert("Rings", NODE_WAVE_RINGS);
+       TEXTURE_MAPPING_DEFINE(WaveTextureNode);
 
 
-       return enm;
-}
+       static NodeEnum type_enum;
+       type_enum.insert("bands", NODE_WAVE_BANDS);
+       type_enum.insert("rings", NODE_WAVE_RINGS);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS);
 
 
-ShaderEnum WaveTextureNode::type_enum = wave_type_init();
+       static NodeEnum profile_enum;
+       profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN);
+       profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW);
+       SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN);
 
 
-WaveTextureNode::WaveTextureNode()
-: TextureNode("wave_texture")
-{
-       type = ustring("Bands");
+       SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
+       SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
+       SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
+       SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f);
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
 
 
-       add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Distortion", SHADER_SOCKET_FLOAT, 0.0f);
-       add_input("Detail", SHADER_SOCKET_FLOAT, 2.0f);
-       add_input("Detail Scale", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
+       return type;
+}
 
 
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
+WaveTextureNode::WaveTextureNode()
+: TextureNode(node_type)
+{
 }
 
 void WaveTextureNode::compile(SVMCompiler& compiler)
 }
 
 void WaveTextureNode::compile(SVMCompiler& compiler)
@@ -1100,60 +1087,63 @@ void WaveTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *fac_out = output("Fac");
        ShaderOutput *color_out = output("Color");
 
        ShaderOutput *fac_out = output("Fac");
        ShaderOutput *color_out = output("Color");
 
-       if(scale_in->link) compiler.stack_assign(scale_in);
-       if(detail_in->link) compiler.stack_assign(detail_in);
-       if(distortion_in->link) compiler.stack_assign(distortion_in);
-       if(dscale_in->link) compiler.stack_assign(dscale_in);
-       if(vector_in->link) compiler.stack_assign(vector_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       if(!fac_out->links.empty())
-               compiler.stack_assign(fac_out);
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_WAVE,
 
        compiler.add_node(NODE_TEX_WAVE,
-               compiler.encode_uchar4(type_enum[type], color_out->stack_offset, fac_out->stack_offset, dscale_in->stack_offset),
-               compiler.encode_uchar4(vector_offset, scale_in->stack_offset, detail_in->stack_offset, distortion_in->stack_offset));
+               compiler.encode_uchar4(
+                       type,
+                       compiler.stack_assign_if_linked(color_out),
+                       compiler.stack_assign_if_linked(fac_out),
+                       compiler.stack_assign_if_linked(dscale_in)),
+               compiler.encode_uchar4(
+                       vector_offset,
+                       compiler.stack_assign_if_linked(scale_in),
+                       compiler.stack_assign_if_linked(detail_in),
+                       compiler.stack_assign_if_linked(distortion_in)),
+               profile);
 
        compiler.add_node(
 
        compiler.add_node(
-               __float_as_int(scale_in->value.x),
-               __float_as_int(detail_in->value.x),
-               __float_as_int(distortion_in->value.x),
-               __float_as_int(dscale_in->value.x));
+               __float_as_int(scale),
+               __float_as_int(detail),
+               __float_as_int(distortion),
+               __float_as_int(detail_scale));
 
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void WaveTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
 }
 
 void WaveTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
-       compiler.parameter("Type", type);
+       compiler.parameter(this, "type");
+       compiler.parameter(this, "profile");
 
        compiler.add(this, "node_wave_texture");
 }
 
 /* Magic Texture */
 
 
        compiler.add(this, "node_wave_texture");
 }
 
 /* Magic Texture */
 
-MagicTextureNode::MagicTextureNode()
-: TextureNode("magic_texture")
+NODE_DEFINE(MagicTextureNode)
 {
 {
-       depth = 2;
+       NodeType* type = NodeType::add("magic_texture", create, NodeType::SHADER);
+
+       TEXTURE_MAPPING_DEFINE(MagicTextureNode);
+
+       SOCKET_INT(depth, "Depth", 2);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+       SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+       SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f);
+
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
 
 
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-       add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
-       add_input("Distortion", SHADER_SOCKET_FLOAT, 1.0f);
+       return type;
+}
 
 
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
+MagicTextureNode::MagicTextureNode()
+: TextureNode(node_type)
+{
 }
 
 void MagicTextureNode::compile(SVMCompiler& compiler)
 }
 
 void MagicTextureNode::compile(SVMCompiler& compiler)
@@ -1164,53 +1154,54 @@ void MagicTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
-       if(vector_in->link) compiler.stack_assign(vector_in);
-       if(distortion_in->link) compiler.stack_assign(distortion_in);
-       if(scale_in->link) compiler.stack_assign(scale_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       if(!fac_out->links.empty())
-               compiler.stack_assign(fac_out);
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_MAGIC,
 
        compiler.add_node(NODE_TEX_MAGIC,
-               compiler.encode_uchar4(depth, color_out->stack_offset, fac_out->stack_offset),
-               compiler.encode_uchar4(vector_offset, scale_in->stack_offset, distortion_in->stack_offset));
+               compiler.encode_uchar4(
+                       depth,
+                       compiler.stack_assign_if_linked(color_out),
+                       compiler.stack_assign_if_linked(fac_out)),
+               compiler.encode_uchar4(
+                       vector_offset,
+                       compiler.stack_assign_if_linked(scale_in),
+                       compiler.stack_assign_if_linked(distortion_in)));
        compiler.add_node(
        compiler.add_node(
-               __float_as_int(scale_in->value.x),
-               __float_as_int(distortion_in->value.x));
+               __float_as_int(scale),
+               __float_as_int(distortion));
 
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void MagicTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
 }
 
 void MagicTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
-       compiler.parameter("Depth", depth);
+       compiler.parameter(this, "depth");
        compiler.add(this, "node_magic_texture");
 }
 
 /* Checker Texture */
 
        compiler.add(this, "node_magic_texture");
 }
 
 /* Checker Texture */
 
-CheckerTextureNode::CheckerTextureNode()
-: TextureNode("checker_texture")
+NODE_DEFINE(CheckerTextureNode)
 {
 {
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-       add_input("Color1", SHADER_SOCKET_COLOR);
-       add_input("Color2", SHADER_SOCKET_COLOR);
-       add_input("Scale", SHADER_SOCKET_FLOAT, 1.0f);
+       NodeType* type = NodeType::add("checker_texture", create, NodeType::SHADER);
+
+       TEXTURE_MAPPING_DEFINE(CheckerTextureNode);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+       SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 
 
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
+
+       return type;
+}
+
+CheckerTextureNode::CheckerTextureNode()
+: TextureNode(node_type)
+{
 }
 
 void CheckerTextureNode::compile(SVMCompiler& compiler)
 }
 
 void CheckerTextureNode::compile(SVMCompiler& compiler)
@@ -1223,30 +1214,20 @@ void CheckerTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
-       compiler.stack_assign(vector_in);
-       compiler.stack_assign(color1_in);
-       compiler.stack_assign(color2_in);
-       if(scale_in->link) compiler.stack_assign(scale_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
-       if(!fac_out->links.empty())
-               compiler.stack_assign(fac_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_CHECKER,
 
        compiler.add_node(NODE_TEX_CHECKER,
-               compiler.encode_uchar4(vector_offset, color1_in->stack_offset, color2_in->stack_offset, scale_in->stack_offset),
-               compiler.encode_uchar4(color_out->stack_offset, fac_out->stack_offset),
-               __float_as_int(scale_in->value.x));
+               compiler.encode_uchar4(
+                       vector_offset,
+                       compiler.stack_assign(color1_in),
+                       compiler.stack_assign(color2_in),
+                       compiler.stack_assign_if_linked(scale_in)),
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(color_out),
+                       compiler.stack_assign_if_linked(fac_out)),
+               __float_as_int(scale));
 
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void CheckerTextureNode::compile(OSLCompiler& compiler)
 }
 
 void CheckerTextureNode::compile(OSLCompiler& compiler)
@@ -1258,26 +1239,37 @@ void CheckerTextureNode::compile(OSLCompiler& compiler)
 
 /* Brick Texture */
 
 
 /* Brick Texture */
 
-BrickTextureNode::BrickTextureNode()
-: TextureNode("brick_texture")
+NODE_DEFINE(BrickTextureNode)
 {
 {
-       offset = 0.5f;
-       offset_frequency = 2;
-       squash = 1.0f;
-       squash_frequency = 2;
-       
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_GENERATED);
-       add_input("Color1", SHADER_SOCKET_COLOR);
-       add_input("Color2", SHADER_SOCKET_COLOR);
-       add_input("Mortar", SHADER_SOCKET_COLOR);
-       add_input("Scale", SHADER_SOCKET_FLOAT, 5.0f);
-       add_input("Mortar Size", SHADER_SOCKET_FLOAT, 0.02f);
-       add_input("Bias", SHADER_SOCKET_FLOAT, 0.0f);
-       add_input("Brick Width", SHADER_SOCKET_FLOAT, 0.5f);
-       add_input("Row Height", SHADER_SOCKET_FLOAT, 0.25f);
+       NodeType* type = NodeType::add("brick_texture", create, NodeType::SHADER);
+
+       TEXTURE_MAPPING_DEFINE(BrickTextureNode);
+
+       SOCKET_FLOAT(offset, "Offset", 0.5f);
+       SOCKET_INT(offset_frequency, "Offset Frequency", 2);
+       SOCKET_FLOAT(squash, "Squash", 1.0f);
+       SOCKET_INT(squash_frequency, "Squash Frequency", 2);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
+
+       SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
+       SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f);
+       SOCKET_IN_FLOAT(bias, "Bias", 0.0f);
+       SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
+       SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
+
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(fac, "Fac");
+
+       return type;
+}
 
 
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
+BrickTextureNode::BrickTextureNode()
+: TextureNode(node_type)
+{
 }
 
 void BrickTextureNode::compile(SVMCompiler& compiler)
 }
 
 void BrickTextureNode::compile(SVMCompiler& compiler)
@@ -1295,96 +1287,90 @@ void BrickTextureNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
        ShaderOutput *color_out = output("Color");
        ShaderOutput *fac_out = output("Fac");
 
-       compiler.stack_assign(vector_in);
-       compiler.stack_assign(color1_in);
-       compiler.stack_assign(color2_in);
-       compiler.stack_assign(mortar_in);
-       if(scale_in->link) compiler.stack_assign(scale_in);
-       if(mortar_size_in->link) compiler.stack_assign(mortar_size_in);
-       if(bias_in->link) compiler.stack_assign(bias_in);
-       if(brick_width_in->link) compiler.stack_assign(brick_width_in);
-       if(row_height_in->link) compiler.stack_assign(row_height_in);
-
-       int vector_offset = vector_in->stack_offset;
-
-       if(!tex_mapping.skip()) {
-               vector_offset = compiler.stack_find_offset(SHADER_SOCKET_VECTOR);
-               tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
-       }
-
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
-       if(!fac_out->links.empty())
-               compiler.stack_assign(fac_out);
+       int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 
        compiler.add_node(NODE_TEX_BRICK,
 
        compiler.add_node(NODE_TEX_BRICK,
-               compiler.encode_uchar4(vector_offset,
-                       color1_in->stack_offset, color2_in->stack_offset, mortar_in->stack_offset),
-               compiler.encode_uchar4(scale_in->stack_offset,
-                       mortar_size_in->stack_offset, bias_in->stack_offset, brick_width_in->stack_offset),
-               compiler.encode_uchar4(row_height_in->stack_offset,
-                       color_out->stack_offset, fac_out->stack_offset));
+               compiler.encode_uchar4(
+                       vector_offset,
+                       compiler.stack_assign(color1_in),
+                       compiler.stack_assign(color2_in),
+                       compiler.stack_assign(mortar_in)),
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(scale_in),
+                       compiler.stack_assign_if_linked(mortar_size_in),
+                       compiler.stack_assign_if_linked(bias_in),
+                       compiler.stack_assign_if_linked(brick_width_in)),
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(row_height_in),
+                       compiler.stack_assign_if_linked(color_out),
+                       compiler.stack_assign_if_linked(fac_out)));
                        
        compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
                        
        compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
-               __float_as_int(scale_in->value.x),
-               __float_as_int(mortar_size_in->value.x),
-               __float_as_int(bias_in->value.x));
+               __float_as_int(scale),
+               __float_as_int(mortar_size),
+               __float_as_int(bias));
 
 
-       compiler.add_node(__float_as_int(brick_width_in->value.x),
-               __float_as_int(row_height_in->value.x),
+       compiler.add_node(__float_as_int(brick_width),
+               __float_as_int(row_height),
                __float_as_int(offset),
                __float_as_int(squash));
 
                __float_as_int(offset),
                __float_as_int(squash));
 
-       if(vector_offset != vector_in->stack_offset)
-               compiler.stack_clear_offset(vector_in->type, vector_offset);
+       tex_mapping.compile_end(compiler, vector_in, vector_offset);
 }
 
 void BrickTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
 }
 
 void BrickTextureNode::compile(OSLCompiler& compiler)
 {
        tex_mapping.compile(compiler);
 
-       compiler.parameter("Offset", offset);
-       compiler.parameter("OffsetFrequency", offset_frequency);
-       compiler.parameter("Squash", squash);
-       compiler.parameter("SquashFrequency", squash_frequency);
+       compiler.parameter(this, "offset");
+       compiler.parameter(this, "offset_frequency");
+       compiler.parameter(this, "squash");
+       compiler.parameter(this, "squash_frequency");
        compiler.add(this, "node_brick_texture");
 }
 
 /* Point Density Texture */
 
        compiler.add(this, "node_brick_texture");
 }
 
 /* Point Density Texture */
 
-static ShaderEnum point_density_space_init()
+NODE_DEFINE(PointDensityTextureNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER);
 
 
-       enm.insert("Object", NODE_TEX_VOXEL_SPACE_OBJECT);
-       enm.insert("World", NODE_TEX_VOXEL_SPACE_WORLD);
+       SOCKET_STRING(filename, "Filename", ustring(""));
 
 
-       return enm;
-}
+       static NodeEnum space_enum;
+       space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
+       space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD);
+       SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT);
+
+       static NodeEnum interpolation_enum;
+       interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
+       interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
+       interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
+       interpolation_enum.insert("smart", INTERPOLATION_SMART);
+       SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
+
+       SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
 
 
-ShaderEnum PointDensityTextureNode::space_enum = point_density_space_init();
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
+
+       SOCKET_OUT_FLOAT(density, "Density");
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
 
 PointDensityTextureNode::PointDensityTextureNode()
 
 PointDensityTextureNode::PointDensityTextureNode()
-: ShaderNode("point_density")
+: ShaderNode(node_type)
 {
        image_manager = NULL;
        slot = -1;
 {
        image_manager = NULL;
        slot = -1;
-       filename = "";
-       space = ustring("Object");
        builtin_data = NULL;
        builtin_data = NULL;
-       interpolation = INTERPOLATION_LINEAR;
-
-       tfm = transform_identity();
-
-       add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::POSITION);
-       add_output("Density", SHADER_SOCKET_FLOAT);
-       add_output("Color", SHADER_SOCKET_COLOR);
 }
 
 PointDensityTextureNode::~PointDensityTextureNode()
 {
        if(image_manager) {
 }
 
 PointDensityTextureNode::~PointDensityTextureNode()
 {
        if(image_manager) {
-               image_manager->remove_image(filename,
+               image_manager->remove_image(filename.string(),
                                            builtin_data,
                                            interpolation,
                                            EXTENSION_CLIP);
                                            builtin_data,
                                            interpolation,
                                            EXTENSION_CLIP);
@@ -1420,14 +1406,9 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
        image_manager = compiler.image_manager;
 
        if(use_density || use_color) {
        image_manager = compiler.image_manager;
 
        if(use_density || use_color) {
-               if(use_density)
-                       compiler.stack_assign(density_out);
-               if(use_color)
-                       compiler.stack_assign(color_out);
-
                if(slot == -1) {
                        bool is_float, is_linear;
                if(slot == -1) {
                        bool is_float, is_linear;
-                       slot = image_manager->add_image(filename, builtin_data,
+                       slot = image_manager->add_image(filename.string(), builtin_data,
                                                        false, 0,
                                                        is_float, is_linear,
                                                        interpolation,
                                                        false, 0,
                                                        is_float, is_linear,
                                                        interpolation,
@@ -1439,11 +1420,11 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
                        compiler.stack_assign(vector_in);
                        compiler.add_node(NODE_TEX_VOXEL,
                                          slot,
                        compiler.stack_assign(vector_in);
                        compiler.add_node(NODE_TEX_VOXEL,
                                          slot,
-                                         compiler.encode_uchar4(vector_in->stack_offset,
-                                                                density_out->stack_offset,
-                                                                color_out->stack_offset,
-                                                                space_enum[space]));
-                       if(space == "World") {
+                                         compiler.encode_uchar4(compiler.stack_assign(vector_in),
+                                                                compiler.stack_assign_if_linked(density_out),
+                                                                compiler.stack_assign_if_linked(color_out),
+                                                                space));
+                       if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
                                compiler.add_node(tfm.x);
                                compiler.add_node(tfm.y);
                                compiler.add_node(tfm.z);
                                compiler.add_node(tfm.x);
                                compiler.add_node(tfm.y);
                                compiler.add_node(tfm.z);
@@ -1451,13 +1432,17 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler)
                        }
                }
                else {
                        }
                }
                else {
-                       compiler.add_node(NODE_VALUE_F,
-                                         __float_as_int(0.0f),
-                                         density_out->stack_offset);
-                       compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
-                       compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
-                                                                   TEX_IMAGE_MISSING_G,
-                                                                   TEX_IMAGE_MISSING_B));
+                       if(use_density) {
+                               compiler.add_node(NODE_VALUE_F,
+                                                                 __float_as_int(0.0f),
+                                                                 compiler.stack_assign(density_out));
+                       }
+                       if(use_color) {
+                               compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
+                               compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R,
+                                                                                                                       TEX_IMAGE_MISSING_G,
+                                                                                                                       TEX_IMAGE_MISSING_B));
+                       }
                }
        }
 }
                }
        }
 }
@@ -1475,7 +1460,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
        if(use_density || use_color) {
                if(slot == -1) {
                        bool is_float, is_linear;
        if(use_density || use_color) {
                if(slot == -1) {
                        bool is_float, is_linear;
-                       slot = image_manager->add_image(filename, builtin_data,
+                       slot = image_manager->add_image(filename.string(), builtin_data,
                                                        false, 0,
                                                        is_float, is_linear,
                                                        interpolation,
                                                        false, 0,
                                                        is_float, is_linear,
                                                        interpolation,
@@ -1486,37 +1471,34 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler)
                if(slot != -1) {
                        compiler.parameter("filename", string_printf("@%d", slot).c_str());
                }
                if(slot != -1) {
                        compiler.parameter("filename", string_printf("@%d", slot).c_str());
                }
-               if(space == "World") {
+               if(space == NODE_TEX_VOXEL_SPACE_WORLD) {
                        compiler.parameter("mapping", transform_transpose(tfm));
                        compiler.parameter("use_mapping", 1);
                }
                        compiler.parameter("mapping", transform_transpose(tfm));
                        compiler.parameter("use_mapping", 1);
                }
-               switch(interpolation) {
-                       case INTERPOLATION_CLOSEST:
-                               compiler.parameter("interpolation", "closest");
-                               break;
-                       case INTERPOLATION_CUBIC:
-                               compiler.parameter("interpolation", "cubic");
-                               break;
-                       case INTERPOLATION_LINEAR:
-                       default:
-                               compiler.parameter("interpolation", "linear");
-                               break;
-               }
-
+               compiler.parameter(this, "interpolation");
                compiler.add(this, "node_voxel_texture");
        }
 }
 
 /* Normal */
 
                compiler.add(this, "node_voxel_texture");
        }
 }
 
 /* Normal */
 
-NormalNode::NormalNode()
-: ShaderNode("normal")
+NODE_DEFINE(NormalNode)
 {
 {
-       direction = make_float3(0.0f, 0.0f, 1.0f);
+       NodeType* type = NodeType::add("normal", create, NodeType::SHADER);
+
+       SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
 
 
-       add_input("Normal", SHADER_SOCKET_NORMAL);
-       add_output("Normal", SHADER_SOCKET_NORMAL);
-       add_output("Dot",  SHADER_SOCKET_FLOAT);
+       SOCKET_OUT_NORMAL(normal, "Normal");
+       SOCKET_OUT_FLOAT(dot, "Dot");
+
+       return type;
+}
+
+NormalNode::NormalNode()
+: ShaderNode(node_type)
+{
 }
 
 void NormalNode::compile(SVMCompiler& compiler)
 }
 
 void NormalNode::compile(SVMCompiler& compiler)
@@ -1525,11 +1507,10 @@ void NormalNode::compile(SVMCompiler& compiler)
        ShaderOutput *normal_out = output("Normal");
        ShaderOutput *dot_out = output("Dot");
 
        ShaderOutput *normal_out = output("Normal");
        ShaderOutput *dot_out = output("Dot");
 
-       compiler.stack_assign(normal_in);
-       compiler.stack_assign(normal_out);
-       compiler.stack_assign(dot_out);
-
-       compiler.add_node(NODE_NORMAL, normal_in->stack_offset, normal_out->stack_offset, dot_out->stack_offset);
+       compiler.add_node(NODE_NORMAL,
+               compiler.stack_assign(normal_in),
+               compiler.stack_assign(normal_out),
+               compiler.stack_assign(dot_out));
        compiler.add_node(
                __float_as_int(direction.x),
                __float_as_int(direction.y),
        compiler.add_node(
                __float_as_int(direction.x),
                __float_as_int(direction.y),
@@ -1538,17 +1519,27 @@ void NormalNode::compile(SVMCompiler& compiler)
 
 void NormalNode::compile(OSLCompiler& compiler)
 {
 
 void NormalNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter_normal("Direction", direction);
+       compiler.parameter(this, "direction");
        compiler.add(this, "node_normal");
 }
 
 /* Mapping */
 
        compiler.add(this, "node_normal");
 }
 
 /* Mapping */
 
+NODE_DEFINE(MappingNode)
+{
+       NodeType* type = NodeType::add("mapping", create, NodeType::SHADER);
+
+       TEXTURE_MAPPING_DEFINE(MappingNode);
+
+       SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_OUT_POINT(vector, "Vector");
+
+       return type;
+}
+
 MappingNode::MappingNode()
 MappingNode::MappingNode()
-: ShaderNode("mapping")
+: ShaderNode(node_type)
 {
 {
-       add_input("Vector", SHADER_SOCKET_POINT);
-       add_output("Vector", SHADER_SOCKET_POINT);
 }
 
 void MappingNode::compile(SVMCompiler& compiler)
 }
 
 void MappingNode::compile(SVMCompiler& compiler)
@@ -1556,10 +1547,7 @@ void MappingNode::compile(SVMCompiler& compiler)
        ShaderInput *vector_in = input("Vector");
        ShaderOutput *vector_out = output("Vector");
 
        ShaderInput *vector_in = input("Vector");
        ShaderOutput *vector_out = output("Vector");
 
-       compiler.stack_assign(vector_in);
-       compiler.stack_assign(vector_out);
-
-       tex_mapping.compile(compiler, vector_in->stack_offset, vector_out->stack_offset);
+       tex_mapping.compile(compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out));
 }
 
 void MappingNode::compile(OSLCompiler& compiler)
 }
 
 void MappingNode::compile(OSLCompiler& compiler)
@@ -1573,225 +1561,244 @@ void MappingNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_mapping");
 }
 
        compiler.add(this, "node_mapping");
 }
 
-/* Convert */
+/* RGBToBW */
 
 
-ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_, bool autoconvert)
-: ShaderNode("convert")
+NODE_DEFINE(RGBToBWNode)
 {
 {
-       from = from_;
-       to = to_;
+       NodeType* type = NodeType::add("rgb_to_bw", create, NodeType::SHADER);
 
 
-       if(autoconvert)
-               special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
-
-       assert(from != to);
-
-       if(from == SHADER_SOCKET_FLOAT)
-               add_input("Val", SHADER_SOCKET_FLOAT);
-       else if(from == SHADER_SOCKET_INT)
-               add_input("ValInt", SHADER_SOCKET_INT);
-       else if(from == SHADER_SOCKET_COLOR)
-               add_input("Color", SHADER_SOCKET_COLOR);
-       else if(from == SHADER_SOCKET_VECTOR)
-               add_input("Vector", SHADER_SOCKET_VECTOR);
-       else if(from == SHADER_SOCKET_POINT)
-               add_input("Point", SHADER_SOCKET_POINT);
-       else if(from == SHADER_SOCKET_NORMAL)
-               add_input("Normal", SHADER_SOCKET_NORMAL);
-       else if(from == SHADER_SOCKET_STRING)
-               add_input("String", SHADER_SOCKET_STRING);
-       else
-               assert(0);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_OUT_FLOAT(val, "Val");
 
 
-       if(to == SHADER_SOCKET_FLOAT)
-               add_output("Val", SHADER_SOCKET_FLOAT);
-       else if(to == SHADER_SOCKET_INT)
-               add_output("ValInt", SHADER_SOCKET_INT);
-       else if(to == SHADER_SOCKET_COLOR)
-               add_output("Color", SHADER_SOCKET_COLOR);
-       else if(to == SHADER_SOCKET_VECTOR)
-               add_output("Vector", SHADER_SOCKET_VECTOR);
-       else if(to == SHADER_SOCKET_POINT)
-               add_output("Point", SHADER_SOCKET_POINT);
-       else if(to == SHADER_SOCKET_NORMAL)
-               add_output("Normal", SHADER_SOCKET_NORMAL);
-       else if(to == SHADER_SOCKET_STRING)
-               add_output("String", SHADER_SOCKET_STRING);
-       else
-               assert(0);
+       return type;
 }
 
 }
 
-void ConvertNode::compile(SVMCompiler& compiler)
+RGBToBWNode::RGBToBWNode()
+: ShaderNode(node_type)
 {
 {
-       ShaderInput *in = inputs[0];
-       ShaderOutput *out = outputs[0];
-
-       if(from == SHADER_SOCKET_FLOAT) {
-               compiler.stack_assign(in);
-               compiler.stack_assign(out);
+}
 
 
-               if(to == SHADER_SOCKET_INT)
-                       /* float to int */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, in->stack_offset, out->stack_offset);
-               else
-                       /* float to float3 */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, in->stack_offset, out->stack_offset);
+void RGBToBWNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               folder.make_constant(linear_rgb_to_gray(color));
        }
        }
-       else if(from == SHADER_SOCKET_INT) {
-               compiler.stack_assign(in);
-               compiler.stack_assign(out);
+}
 
 
-               if(to == SHADER_SOCKET_FLOAT)
-                       /* int to float */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, in->stack_offset, out->stack_offset);
-               else
-                       /* int to vector/point/normal */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, in->stack_offset, out->stack_offset);
-       }
-       else if(to == SHADER_SOCKET_FLOAT) {
-               compiler.stack_assign(in);
-               compiler.stack_assign(out);
+void RGBToBWNode::compile(SVMCompiler& compiler)
+{
+       compiler.add_node(NODE_CONVERT,
+                        NODE_CONVERT_CF,
+                        compiler.stack_assign(inputs[0]),
+                        compiler.stack_assign(outputs[0]));
+}
 
 
-               if(from == SHADER_SOCKET_COLOR)
-                       /* color to float */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, in->stack_offset, out->stack_offset);
-               else
-                       /* vector/point/normal to float */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, in->stack_offset, out->stack_offset);
-       }
-       else if(to == SHADER_SOCKET_INT) {
-               compiler.stack_assign(in);
-               compiler.stack_assign(out);
+void RGBToBWNode::compile(OSLCompiler& compiler)
+{
+       compiler.add(this, "node_rgb_to_bw");
+}
 
 
-               if(from == SHADER_SOCKET_COLOR)
-                       /* color to int */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, in->stack_offset, out->stack_offset);
-               else
-                       /* vector/point/normal to int */
-                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_VI, in->stack_offset, out->stack_offset);
-       }
-       else {
-               /* float3 to float3 */
-               if(in->link) {
-                       /* no op in SVM */
-                       compiler.stack_link(in, out);
-               }
-               else {
-                       /* set 0,0,0 value */
-                       compiler.stack_assign(in);
-                       compiler.stack_assign(out);
+/* Convert */
 
 
-                       compiler.add_node(NODE_VALUE_V, out->stack_offset);
-                       compiler.add_node(NODE_VALUE_V, in->value);
-               }
-       }
-}
+const NodeType* ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
+bool ConvertNode::initialized = ConvertNode::register_types();
 
 
-void ConvertNode::compile(OSLCompiler& compiler)
+Node* ConvertNode::create(const NodeType *type)
 {
 {
-       if(from == SHADER_SOCKET_FLOAT)
-               compiler.add(this, "node_convert_from_float");
-       else if(from == SHADER_SOCKET_INT)
-               compiler.add(this, "node_convert_from_int");
-       else if(from == SHADER_SOCKET_COLOR)
-               compiler.add(this, "node_convert_from_color");
-       else if(from == SHADER_SOCKET_VECTOR)
-               compiler.add(this, "node_convert_from_vector");
-       else if(from == SHADER_SOCKET_POINT)
-               compiler.add(this, "node_convert_from_point");
-       else if(from == SHADER_SOCKET_NORMAL)
-               compiler.add(this, "node_convert_from_normal");
-       else
-               assert(0);
+       return new ConvertNode(type->inputs[0].type,  type->outputs[0].type);
 }
 
 }
 
-/* Proxy */
-
-ProxyNode::ProxyNode(ShaderSocketType type_)
-: ShaderNode("proxy")
+bool ConvertNode::register_types()
 {
 {
-       type = type_;
-       special_type = SHADER_SPECIAL_TYPE_PROXY;
+       const int num_types = 8;
+       SocketType::Type types[num_types] = {SocketType::FLOAT,
+                                            SocketType::INT,
+                                            SocketType::COLOR,
+                                            SocketType::VECTOR,
+                                            SocketType::POINT,
+                                            SocketType::NORMAL,
+                                            SocketType::STRING,
+                                                                                SocketType::CLOSURE};
+
+       for(size_t i = 0; i < num_types; i++) {
+               SocketType::Type from = types[i];
+               ustring from_name(SocketType::type_name(from));
+               ustring from_value_name("value_" + from_name.string());
+
+               for(size_t j = 0; j < num_types; j++) {
+                       SocketType::Type to = types[j];
+                       ustring to_name(SocketType::type_name(to));
+                       ustring to_value_name("value_" + to_name.string());
+
+                       string node_name = "convert_" + from_name.string() + "_to_" + to_name.string();
+                       NodeType* type = NodeType::add(node_name.c_str(), create, NodeType::SHADER);
+
+                       type->register_input(from_value_name, from_value_name, from,
+                               SOCKET_OFFSETOF(ConvertNode, value_float), SocketType::zero_default_value(),
+                               NULL, NULL, SocketType::LINKABLE);
+                       type->register_output(to_value_name, to_value_name, to);
+
+                       assert(from < MAX_TYPE);
+                       assert(to < MAX_TYPE);
+
+                       node_types[from][to] = type;
+               }
+       }
 
 
-       add_input("Input", type);
-       add_output("Output", type);
+       return true;
 }
 
 }
 
-void ProxyNode::compile(SVMCompiler& /*compiler*/)
+ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
+: ShaderNode(node_types[from_][to_])
 {
 {
+       from = from_;
+       to = to_;
+
+       if(from == to)
+               special_type = SHADER_SPECIAL_TYPE_PROXY;
+       else if(autoconvert)
+               special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
 }
 
 }
 
-void ProxyNode::compile(OSLCompiler& /*compiler*/)
+void ConvertNode::constant_fold(const ConstantFolder& folder)
 {
 {
-}
+       /* proxy nodes should have been removed at this point */
+       assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
 
 
-/* BSDF Closure */
+       /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
+
+       if(folder.all_inputs_constant()) {
+               if(from == SocketType::FLOAT) {
+                       if(SocketType::is_float3(to)) {
+                               folder.make_constant(make_float3(value_float, value_float, value_float));
+                       }
+               }
+               else if(SocketType::is_float3(from)) {
+                       if(to == SocketType::FLOAT) {
+                               if(from == SocketType::COLOR) {
+                                       /* color to float */
+                                       folder.make_constant(linear_rgb_to_gray(value_color));
+                               }
+                               else {
+                                       /* vector/point/normal to float */
+                                       folder.make_constant(average(value_vector));
+                               }
+                       }
+                       else if(SocketType::is_float3(to)) {
+                               folder.make_constant(value_color);
+                       }
+               }
+       }
+}
 
 
-BsdfNode::BsdfNode(bool scattering_)
-: ShaderNode("bsdf"), scattering(scattering_)
+void ConvertNode::compile(SVMCompiler& compiler)
 {
 {
-       special_type = SHADER_SPECIAL_TYPE_CLOSURE;
+       /* proxy nodes should have been removed at this point */
+       assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
 
 
-       add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
-       add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
-       add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+       ShaderInput *in = inputs[0];
+       ShaderOutput *out = outputs[0];
 
 
-       if(scattering) {
-               closure = CLOSURE_BSSRDF_CUBIC_ID;
-               add_output("BSSRDF", SHADER_SOCKET_CLOSURE);
+       if(from == SocketType::FLOAT) {
+               if(to == SocketType::INT)
+                       /* float to int */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
+               else
+                       /* float to float3 */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
+       }
+       else if(from == SocketType::INT) {
+               if(to == SocketType::FLOAT)
+                       /* int to float */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
+               else
+                       /* int to vector/point/normal */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
+       }
+       else if(to == SocketType::FLOAT) {
+               if(from == SocketType::COLOR)
+                       /* color to float */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
+               else
+                       /* vector/point/normal to float */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
+       }
+       else if(to == SocketType::INT) {
+               if(from == SocketType::COLOR)
+                       /* color to int */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
+               else
+                       /* vector/point/normal to int */
+                       compiler.add_node(NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out));
        }
        else {
        }
        else {
-               closure = CLOSURE_BSDF_DIFFUSE_ID;
-               add_output("BSDF", SHADER_SOCKET_CLOSURE);
+               /* float3 to float3 */
+               if(in->link) {
+                       /* no op in SVM */
+                       compiler.stack_link(in, out);
+               }
+               else {
+                       /* set 0,0,0 value */
+                       compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
+                       compiler.add_node(NODE_VALUE_V, value_color);
+               }
        }
 }
 
        }
 }
 
+void ConvertNode::compile(OSLCompiler& compiler)
+{
+       /* proxy nodes should have been removed at this point */
+       assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
+
+       if(from == SocketType::FLOAT)
+               compiler.add(this, "node_convert_from_float");
+       else if(from == SocketType::INT)
+               compiler.add(this, "node_convert_from_int");
+       else if(from == SocketType::COLOR)
+               compiler.add(this, "node_convert_from_color");
+       else if(from == SocketType::VECTOR)
+               compiler.add(this, "node_convert_from_vector");
+       else if(from == SocketType::POINT)
+               compiler.add(this, "node_convert_from_point");
+       else if(from == SocketType::NORMAL)
+               compiler.add(this, "node_convert_from_normal");
+       else
+               assert(0);
+}
+
+/* BSDF Closure */
+
+BsdfNode::BsdfNode(const NodeType *node_type)
+: ShaderNode(node_type)
+{
+       special_type = SHADER_SPECIAL_TYPE_CLOSURE;
+}
+
 void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4)
 {
        ShaderInput *color_in = input("Color");
        ShaderInput *normal_in = input("Normal");
        ShaderInput *tangent_in = input("Tangent");
 
 void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2, ShaderInput *param3, ShaderInput *param4)
 {
        ShaderInput *color_in = input("Color");
        ShaderInput *normal_in = input("Normal");
        ShaderInput *tangent_in = input("Tangent");
 
-       if(color_in->link) {
-               compiler.stack_assign(color_in);
-               compiler.add_node(NODE_CLOSURE_WEIGHT, color_in->stack_offset);
-       }
+       if(color_in->link)
+               compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
        else
        else
-               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
-       
-       if(param1)
-               compiler.stack_assign(param1);
-       if(param2)
-               compiler.stack_assign(param2);
-       if(param3)
-               compiler.stack_assign(param3);
-       if(param4)
-               compiler.stack_assign(param4);
-
-       if(normal_in->link)
-               compiler.stack_assign(normal_in);
+               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
 
 
-       if(tangent_in && tangent_in->link)
-               compiler.stack_assign(tangent_in);
+       int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
+       int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) : SVM_STACK_INVALID;
+       int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
+       int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
 
        compiler.add_node(NODE_CLOSURE_BSDF,
                compiler.encode_uchar4(closure,
 
        compiler.add_node(NODE_CLOSURE_BSDF,
                compiler.encode_uchar4(closure,
-                       (param1)? param1->stack_offset: SVM_STACK_INVALID,
-                       (param2)? param2->stack_offset: SVM_STACK_INVALID,
+                       (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
+                       (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
                        compiler.closure_mix_weight_offset()),
                        compiler.closure_mix_weight_offset()),
-               __float_as_int((param1)? param1->value.x: 0.0f),
-               __float_as_int((param2)? param2->value.x: 0.0f));
+               __float_as_int((param1)? get_float(param1->socket_type): 0.0f),
+               __float_as_int((param2)? get_float(param2->socket_type): 0.0f));
 
 
-       if(tangent_in) {
-               compiler.add_node(normal_in->stack_offset, tangent_in->stack_offset,
-                       (param3)? param3->stack_offset: SVM_STACK_INVALID,
-                       (param4)? param4->stack_offset: SVM_STACK_INVALID);
-       }
-       else {
-               compiler.add_node(normal_in->stack_offset, SVM_STACK_INVALID,
-                       (param3)? param3->stack_offset: SVM_STACK_INVALID,
-                       (param4)? param4->stack_offset: SVM_STACK_INVALID);
-       }
+       compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
 }
 
 void BsdfNode::compile(SVMCompiler& compiler)
 }
 
 void BsdfNode::compile(SVMCompiler& compiler)
@@ -1806,29 +1813,36 @@ void BsdfNode::compile(OSLCompiler& /*compiler*/)
 
 /* Anisotropic BSDF Closure */
 
 
 /* Anisotropic BSDF Closure */
 
-static ShaderEnum aniso_distribution_init()
+NODE_DEFINE(AnisotropicBsdfNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
 
 
-       enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
-       enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
-       enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       return enm;
-}
+       static NodeEnum distribution_enum;
+       distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID);
+       distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
+       distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID);
+       distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID);
+       SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID);
+
+       SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
+
+       SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
+       SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
+       SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
 
 
-ShaderEnum AnisotropicBsdfNode::distribution_enum = aniso_distribution_init();
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
 
 AnisotropicBsdfNode::AnisotropicBsdfNode()
 
 AnisotropicBsdfNode::AnisotropicBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
 {
        closure = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
-       distribution = ustring("GGX");
-
-       add_input("Tangent", SHADER_SOCKET_VECTOR, ShaderInput::TANGENT);
-
-       add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
-       add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.5f);
-       add_input("Rotation", SHADER_SOCKET_FLOAT, 0.0f);
 }
 
 void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 }
 
 void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -1845,45 +1859,54 @@ void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attrib
 
 void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
 {
 
 void AnisotropicBsdfNode::compile(SVMCompiler& compiler)
 {
-       closure = (ClosureType)distribution_enum[distribution];
+       closure = distribution;
 
 
-       BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
+       if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID)
+               BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
+       else
+               BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
 }
 
 void AnisotropicBsdfNode::compile(OSLCompiler& compiler)
 {
 }
 
 void AnisotropicBsdfNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("distribution", distribution);
+       compiler.parameter(this, "distribution");
        compiler.add(this, "node_anisotropic_bsdf");
 }
 
 /* Glossy BSDF Closure */
 
        compiler.add(this, "node_anisotropic_bsdf");
 }
 
 /* Glossy BSDF Closure */
 
-static ShaderEnum glossy_distribution_init()
+NODE_DEFINE(GlossyBsdfNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
 
 
-       enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID);
-       enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
-       enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
-       enm.insert("Ashikhmin-Shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       return enm;
-}
+       static NodeEnum distribution_enum;
+       distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID);
+       distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
+       distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
+       distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
+       distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
+       SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
+       SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f);
 
 
-ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init();
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
 
 GlossyBsdfNode::GlossyBsdfNode()
 
 GlossyBsdfNode::GlossyBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
 {
        closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
-       distribution = ustring("GGX");
-       distribution_orig = ustring("");
-
-       add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
+       distribution_orig = NBUILTIN_CLOSURES;
 }
 
 void GlossyBsdfNode::simplify_settings(Scene *scene)
 {
 }
 
 void GlossyBsdfNode::simplify_settings(Scene *scene)
 {
-       if(distribution_orig == "") {
+       if(distribution_orig == NBUILTIN_CLOSURES) {
                distribution_orig = distribution;
        }
        Integrator *integrator = scene->integrator;
                distribution_orig = distribution;
        }
        Integrator *integrator = scene->integrator;
@@ -1891,68 +1914,76 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
                /* Fallback to Sharp closure for Roughness close to 0.
                 * Note: Keep the epsilon in sync with kernel!
                 */
                /* Fallback to Sharp closure for Roughness close to 0.
                 * Note: Keep the epsilon in sync with kernel!
                 */
-               ShaderInput *roughness_input = get_input("Roughness");
-               if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
-                       distribution = ustring("Sharp");
+               ShaderInput *roughness_input = input("Roughness");
+               if(!roughness_input->link && roughness <= 1e-4f) {
+                       distribution = CLOSURE_BSDF_REFLECTION_ID;
                }
        }
        else {
                /* Rollback to original distribution when filter glossy is used. */
                distribution = distribution_orig;
        }
                }
        }
        else {
                /* Rollback to original distribution when filter glossy is used. */
                distribution = distribution_orig;
        }
-       closure = (ClosureType)distribution_enum[distribution];
+       closure = distribution;
 }
 
 bool GlossyBsdfNode::has_integrator_dependency()
 {
 }
 
 bool GlossyBsdfNode::has_integrator_dependency()
 {
-       ShaderInput *roughness_input = get_input("Roughness");
-       return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+       ShaderInput *roughness_input = input("Roughness");
+       return !roughness_input->link && roughness <= 1e-4f;
 }
 
 void GlossyBsdfNode::compile(SVMCompiler& compiler)
 {
 }
 
 void GlossyBsdfNode::compile(SVMCompiler& compiler)
 {
-       closure = (ClosureType)distribution_enum[distribution];
+       closure = distribution;
 
        if(closure == CLOSURE_BSDF_REFLECTION_ID)
                BsdfNode::compile(compiler, NULL, NULL);
 
        if(closure == CLOSURE_BSDF_REFLECTION_ID)
                BsdfNode::compile(compiler, NULL, NULL);
+       else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
+               BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color"));
        else
                BsdfNode::compile(compiler, input("Roughness"), NULL);
 }
 
 void GlossyBsdfNode::compile(OSLCompiler& compiler)
 {
        else
                BsdfNode::compile(compiler, input("Roughness"), NULL);
 }
 
 void GlossyBsdfNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("distribution", distribution);
+       compiler.parameter(this, "distribution");
        compiler.add(this, "node_glossy_bsdf");
 }
 
 /* Glass BSDF Closure */
 
        compiler.add(this, "node_glossy_bsdf");
 }
 
 /* Glass BSDF Closure */
 
-static ShaderEnum glass_distribution_init()
+NODE_DEFINE(GlassBsdfNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
 
 
-       enm.insert("Sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
-       enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
-       enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       return enm;
-}
+       static NodeEnum distribution_enum;
+       distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
+       distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
+       distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+       distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
+       SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
+       SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+       SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
 
 
-ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init();
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
 
 GlassBsdfNode::GlassBsdfNode()
 
 GlassBsdfNode::GlassBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_SHARP_GLASS_ID;
 {
        closure = CLOSURE_BSDF_SHARP_GLASS_ID;
-       distribution = ustring("Sharp");
-       distribution_orig = ustring("");
-
-       add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
-       add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+       distribution_orig = NBUILTIN_CLOSURES;
 }
 
 void GlassBsdfNode::simplify_settings(Scene *scene)
 {
 }
 
 void GlassBsdfNode::simplify_settings(Scene *scene)
 {
-       if(distribution_orig == "") {
+       if(distribution_orig == NBUILTIN_CLOSURES) {
                distribution_orig = distribution;
        }
        Integrator *integrator = scene->integrator;
                distribution_orig = distribution;
        }
        Integrator *integrator = scene->integrator;
@@ -1960,68 +1991,76 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
                /* Fallback to Sharp closure for Roughness close to 0.
                 * Note: Keep the epsilon in sync with kernel!
                 */
                /* Fallback to Sharp closure for Roughness close to 0.
                 * Note: Keep the epsilon in sync with kernel!
                 */
-               ShaderInput *roughness_input = get_input("Roughness");
-               if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
-                       distribution = ustring("Sharp");
+               ShaderInput *roughness_input = input("Roughness");
+               if(!roughness_input->link && roughness <= 1e-4f) {
+                       distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
                }
        }
        else {
                /* Rollback to original distribution when filter glossy is used. */
                distribution = distribution_orig;
        }
                }
        }
        else {
                /* Rollback to original distribution when filter glossy is used. */
                distribution = distribution_orig;
        }
-       closure = (ClosureType)distribution_enum[distribution];
+       closure = distribution;
 }
 
 bool GlassBsdfNode::has_integrator_dependency()
 {
 }
 
 bool GlassBsdfNode::has_integrator_dependency()
 {
-       ShaderInput *roughness_input = get_input("Roughness");
-       return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+       ShaderInput *roughness_input = input("Roughness");
+       return !roughness_input->link && roughness <= 1e-4f;
 }
 
 void GlassBsdfNode::compile(SVMCompiler& compiler)
 {
 }
 
 void GlassBsdfNode::compile(SVMCompiler& compiler)
 {
-       closure = (ClosureType)distribution_enum[distribution];
+       closure = distribution;
 
        if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
                BsdfNode::compile(compiler, NULL, input("IOR"));
 
        if(closure == CLOSURE_BSDF_SHARP_GLASS_ID)
                BsdfNode::compile(compiler, NULL, input("IOR"));
+       else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
+               BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
        else
                BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
 }
 
 void GlassBsdfNode::compile(OSLCompiler& compiler)
 {
        else
                BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
 }
 
 void GlassBsdfNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("distribution", distribution);
+       compiler.parameter(this, "distribution");
        compiler.add(this, "node_glass_bsdf");
 }
 
 /* Refraction BSDF Closure */
 
        compiler.add(this, "node_glass_bsdf");
 }
 
 /* Refraction BSDF Closure */
 
-static ShaderEnum refraction_distribution_init()
+NODE_DEFINE(RefractionBsdfNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
 
 
-       enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID);
-       enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
-       enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       return enm;
-}
+       static NodeEnum distribution_enum;
+       distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID);
+       distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
+       distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+       SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
+
+       SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+       SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
+
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 
 
-ShaderEnum RefractionBsdfNode::distribution_enum = refraction_distribution_init();
+       return type;
+}
 
 RefractionBsdfNode::RefractionBsdfNode()
 
 RefractionBsdfNode::RefractionBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_REFRACTION_ID;
 {
        closure = CLOSURE_BSDF_REFRACTION_ID;
-       distribution = ustring("Sharp");
-       distribution_orig = ustring("");
-
-       add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
-       add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
+       distribution_orig = NBUILTIN_CLOSURES;
 }
 
 void RefractionBsdfNode::simplify_settings(Scene *scene)
 {
 }
 
 void RefractionBsdfNode::simplify_settings(Scene *scene)
 {
-       if(distribution_orig == "") {
+       if(distribution_orig == NBUILTIN_CLOSURES) {
                distribution_orig = distribution;
        }
        Integrator *integrator = scene->integrator;
                distribution_orig = distribution;
        }
        Integrator *integrator = scene->integrator;
@@ -2029,27 +2068,27 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
                /* Fallback to Sharp closure for Roughness close to 0.
                 * Note: Keep the epsilon in sync with kernel!
                 */
                /* Fallback to Sharp closure for Roughness close to 0.
                 * Note: Keep the epsilon in sync with kernel!
                 */
-               ShaderInput *roughness_input = get_input("Roughness");
-               if(!roughness_input->link && roughness_input->value.x <= 1e-4f) {
-                       distribution = ustring("Sharp");
+               ShaderInput *roughness_input = input("Roughness");
+               if(!roughness_input->link && roughness <= 1e-4f) {
+                       distribution = CLOSURE_BSDF_REFRACTION_ID;
                }
        }
        else {
                /* Rollback to original distribution when filter glossy is used. */
                distribution = distribution_orig;
        }
                }
        }
        else {
                /* Rollback to original distribution when filter glossy is used. */
                distribution = distribution_orig;
        }
-       closure = (ClosureType)distribution_enum[distribution];
+       closure = distribution;
 }
 
 bool RefractionBsdfNode::has_integrator_dependency()
 {
 }
 
 bool RefractionBsdfNode::has_integrator_dependency()
 {
-       ShaderInput *roughness_input = get_input("Roughness");
-       return !roughness_input->link && roughness_input->value.x <= 1e-4f;
+       ShaderInput *roughness_input = input("Roughness");
+       return !roughness_input->link && roughness <= 1e-4f;
 }
 
 void RefractionBsdfNode::compile(SVMCompiler& compiler)
 {
 }
 
 void RefractionBsdfNode::compile(SVMCompiler& compiler)
 {
-       closure = (ClosureType)distribution_enum[distribution];
+       closure = distribution;
 
        if(closure == CLOSURE_BSDF_REFRACTION_ID)
                BsdfNode::compile(compiler, NULL, input("IOR"));
 
        if(closure == CLOSURE_BSDF_REFRACTION_ID)
                BsdfNode::compile(compiler, NULL, input("IOR"));
@@ -2059,53 +2098,71 @@ void RefractionBsdfNode::compile(SVMCompiler& compiler)
 
 void RefractionBsdfNode::compile(OSLCompiler& compiler)
 {
 
 void RefractionBsdfNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("distribution", distribution);
+       compiler.parameter(this, "distribution");
        compiler.add(this, "node_refraction_bsdf");
 }
 
 /* Toon BSDF Closure */
 
        compiler.add(this, "node_refraction_bsdf");
 }
 
 /* Toon BSDF Closure */
 
-static ShaderEnum toon_component_init()
+NODE_DEFINE(ToonBsdfNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
 
 
-       enm.insert("Diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
-       enm.insert("Glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       return enm;
-}
+       static NodeEnum component_enum;
+       component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
+       component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
+       SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID);
+       SOCKET_IN_FLOAT(size, "Size", 0.5f);
+       SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
+
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 
 
-ShaderEnum ToonBsdfNode::component_enum = toon_component_init();
+       return type;
+}
 
 ToonBsdfNode::ToonBsdfNode()
 
 ToonBsdfNode::ToonBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
 {
        closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
-       component = ustring("Diffuse");
-
-       add_input("Size", SHADER_SOCKET_FLOAT, 0.5f);
-       add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
 }
 
 void ToonBsdfNode::compile(SVMCompiler& compiler)
 {
 }
 
 void ToonBsdfNode::compile(SVMCompiler& compiler)
 {
-       closure = (ClosureType)component_enum[component];
+       closure = component;
        
        BsdfNode::compile(compiler, input("Size"), input("Smooth"));
 }
 
 void ToonBsdfNode::compile(OSLCompiler& compiler)
 {
        
        BsdfNode::compile(compiler, input("Size"), input("Smooth"));
 }
 
 void ToonBsdfNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("component", component);
+       compiler.parameter(this, "component");
        compiler.add(this, "node_toon_bsdf");
 }
 
 /* Velvet BSDF Closure */
 
        compiler.add(this, "node_toon_bsdf");
 }
 
 /* Velvet BSDF Closure */
 
+NODE_DEFINE(VelvetBsdfNode)
+{
+       NodeType* type = NodeType::add("velvet_bsdf", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+       SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f);
+
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
+
 VelvetBsdfNode::VelvetBsdfNode()
 VelvetBsdfNode::VelvetBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
 {
        closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
-
-       add_input("Sigma", SHADER_SOCKET_FLOAT, 1.0f);
 }
 
 void VelvetBsdfNode::compile(SVMCompiler& compiler)
 }
 
 void VelvetBsdfNode::compile(SVMCompiler& compiler)
@@ -2120,10 +2177,24 @@ void VelvetBsdfNode::compile(OSLCompiler& compiler)
 
 /* Diffuse BSDF Closure */
 
 
 /* Diffuse BSDF Closure */
 
+NODE_DEFINE(DiffuseBsdfNode)
+{
+       NodeType* type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+       SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
+
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
+
 DiffuseBsdfNode::DiffuseBsdfNode()
 DiffuseBsdfNode::DiffuseBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_DIFFUSE_ID;
 {
        closure = CLOSURE_BSDF_DIFFUSE_ID;
-       add_input("Roughness", SHADER_SOCKET_FLOAT, 0.0f);
 }
 
 void DiffuseBsdfNode::compile(SVMCompiler& compiler)
 }
 
 void DiffuseBsdfNode::compile(SVMCompiler& compiler)
@@ -2138,7 +2209,21 @@ void DiffuseBsdfNode::compile(OSLCompiler& compiler)
 
 /* Translucent BSDF Closure */
 
 
 /* Translucent BSDF Closure */
 
+NODE_DEFINE(TranslucentBsdfNode)
+{
+       NodeType* type = NodeType::add("translucent_bsdf", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
+
 TranslucentBsdfNode::TranslucentBsdfNode()
 TranslucentBsdfNode::TranslucentBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_TRANSLUCENT_ID;
 }
 {
        closure = CLOSURE_BSDF_TRANSLUCENT_ID;
 }
@@ -2155,9 +2240,21 @@ void TranslucentBsdfNode::compile(OSLCompiler& compiler)
 
 /* Transparent BSDF Closure */
 
 
 /* Transparent BSDF Closure */
 
+NODE_DEFINE(TransparentBsdfNode)
+{
+       NodeType* type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
+
 TransparentBsdfNode::TransparentBsdfNode()
 TransparentBsdfNode::TransparentBsdfNode()
+: BsdfNode(node_type)
 {
 {
-       name = "transparent";
        closure = CLOSURE_BSDF_TRANSPARENT_ID;
 }
 
        closure = CLOSURE_BSDF_TRANSPARENT_ID;
 }
 
@@ -2173,38 +2270,45 @@ void TransparentBsdfNode::compile(OSLCompiler& compiler)
 
 /* Subsurface Scattering Closure */
 
 
 /* Subsurface Scattering Closure */
 
-static ShaderEnum subsurface_falloff_init()
+NODE_DEFINE(SubsurfaceScatteringNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
 
 
-       enm.insert("Cubic", CLOSURE_BSSRDF_CUBIC_ID);
-       enm.insert("Gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       return enm;
-}
+       static NodeEnum falloff_enum;
+       falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID);
+       falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
+       falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
+       SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID);
+       SOCKET_IN_FLOAT(scale, "Scale", 0.01f);
+       SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f));
+       SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f);
+       SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f);
 
 
-ShaderEnum SubsurfaceScatteringNode::falloff_enum = subsurface_falloff_init();
+       SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF");
+
+       return type;
+}
 
 SubsurfaceScatteringNode::SubsurfaceScatteringNode()
 
 SubsurfaceScatteringNode::SubsurfaceScatteringNode()
-: BsdfNode(true)
+: BsdfNode(node_type)
 {
 {
-       name = "subsurface_scattering";
-       closure = CLOSURE_BSSRDF_CUBIC_ID;
-
-       add_input("Scale", SHADER_SOCKET_FLOAT, 0.01f);
-       add_input("Radius", SHADER_SOCKET_VECTOR, make_float3(0.1f, 0.1f, 0.1f));
-       add_input("Sharpness", SHADER_SOCKET_FLOAT, 0.0f);
-       add_input("Texture Blur", SHADER_SOCKET_FLOAT, 1.0f);
+       closure = falloff;
 }
 
 void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
 {
 }
 
 void SubsurfaceScatteringNode::compile(SVMCompiler& compiler)
 {
+       closure = falloff;
        BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness"));
 }
 
 void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
 {
        BsdfNode::compile(compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness"));
 }
 
 void SubsurfaceScatteringNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("Falloff", falloff_enum[closure]);
+       closure = falloff;
+       compiler.parameter(this, "falloff");
        compiler.add(this, "node_subsurface_scattering");
 }
 
        compiler.add(this, "node_subsurface_scattering");
 }
 
@@ -2217,16 +2321,22 @@ bool SubsurfaceScatteringNode::has_bssrdf_bump()
 
 /* Emissive Closure */
 
 
 /* Emissive Closure */
 
-EmissionNode::EmissionNode()
-: ShaderNode("emission")
+NODE_DEFINE(EmissionNode)
 {
 {
-       special_type = SHADER_SPECIAL_TYPE_EMISSION;
+       NodeType* type = NodeType::add("emission", create, NodeType::SHADER);
 
 
-       add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
-       add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f);
-       add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_FLOAT(strength, "Strength", 10.0f);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       add_output("Emission", SHADER_SOCKET_CLOSURE);
+       SOCKET_OUT_CLOSURE(emission, "Emission");
+
+       return type;
+}
+
+EmissionNode::EmissionNode()
+: ShaderNode(node_type)
+{
 }
 
 void EmissionNode::compile(SVMCompiler& compiler)
 }
 
 void EmissionNode::compile(SVMCompiler& compiler)
@@ -2235,12 +2345,12 @@ void EmissionNode::compile(SVMCompiler& compiler)
        ShaderInput *strength_in = input("Strength");
 
        if(color_in->link || strength_in->link) {
        ShaderInput *strength_in = input("Strength");
 
        if(color_in->link || strength_in->link) {
-               compiler.stack_assign(color_in);
-               compiler.stack_assign(strength_in);
-               compiler.add_node(NODE_EMISSION_WEIGHT, color_in->stack_offset, strength_in->stack_offset);
+               compiler.add_node(NODE_EMISSION_WEIGHT,
+                                 compiler.stack_assign(color_in),
+                                 compiler.stack_assign(strength_in));
        }
        else
        }
        else
-               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x);
+               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
 
        compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
 }
 
        compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
 }
@@ -2250,18 +2360,35 @@ void EmissionNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_emission");
 }
 
        compiler.add(this, "node_emission");
 }
 
+void EmissionNode::constant_fold(const ConstantFolder& folder)
+{
+       ShaderInput *color_in = input("Color");
+       ShaderInput *strength_in = input("Strength");
+
+       if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+           (!strength_in->link && strength == 0.0f)) {
+               folder.discard();
+       }
+}
+
 /* Background Closure */
 
 /* Background Closure */
 
-BackgroundNode::BackgroundNode()
-: ShaderNode("background")
+NODE_DEFINE(BackgroundNode)
 {
 {
-       special_type = SHADER_SPECIAL_TYPE_BACKGROUND;
+       NodeType* type = NodeType::add("background_shader", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
-       add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+       SOCKET_OUT_CLOSURE(background, "Background");
+
+       return type;
+}
 
 
-       add_output("Background", SHADER_SOCKET_CLOSURE);
+BackgroundNode::BackgroundNode()
+: ShaderNode(node_type)
+{
 }
 
 void BackgroundNode::compile(SVMCompiler& compiler)
 }
 
 void BackgroundNode::compile(SVMCompiler& compiler)
@@ -2270,12 +2397,12 @@ void BackgroundNode::compile(SVMCompiler& compiler)
        ShaderInput *strength_in = input("Strength");
 
        if(color_in->link || strength_in->link) {
        ShaderInput *strength_in = input("Strength");
 
        if(color_in->link || strength_in->link) {
-               compiler.stack_assign(color_in);
-               compiler.stack_assign(strength_in);
-               compiler.add_node(NODE_EMISSION_WEIGHT, color_in->stack_offset, strength_in->stack_offset);
+               compiler.add_node(NODE_EMISSION_WEIGHT,
+                                 compiler.stack_assign(color_in),
+                                                 compiler.stack_assign(strength_in));
        }
        else
        }
        else
-               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x);
+               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength);
 
        compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
 }
 
        compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
 }
@@ -2285,15 +2412,34 @@ void BackgroundNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_background");
 }
 
        compiler.add(this, "node_background");
 }
 
+void BackgroundNode::constant_fold(const ConstantFolder& folder)
+{
+       ShaderInput *color_in = input("Color");
+       ShaderInput *strength_in = input("Strength");
+
+       if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
+           (!strength_in->link && strength == 0.0f)) {
+               folder.discard();
+       }
+}
+
 /* Holdout Closure */
 
 /* Holdout Closure */
 
-HoldoutNode::HoldoutNode()
-: ShaderNode("holdout")
+NODE_DEFINE(HoldoutNode)
 {
 {
-       add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
-       add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+       NodeType* type = NodeType::add("holdout", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+       SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+       SOCKET_OUT_CLOSURE(holdout, "Holdout");
 
 
-       add_output("Holdout", SHADER_SOCKET_CLOSURE);
+       return type;
+}
+
+HoldoutNode::HoldoutNode()
+: ShaderNode(node_type)
+{
 }
 
 void HoldoutNode::compile(SVMCompiler& compiler)
 }
 
 void HoldoutNode::compile(SVMCompiler& compiler)
@@ -2311,26 +2457,32 @@ void HoldoutNode::compile(OSLCompiler& compiler)
 
 /* Ambient Occlusion */
 
 
 /* Ambient Occlusion */
 
-AmbientOcclusionNode::AmbientOcclusionNode()
-: ShaderNode("ambient_occlusion")
+NODE_DEFINE(AmbientOcclusionNode)
 {
 {
-       add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
-       add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
-       add_input("SurfaceMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
+       NodeType* type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
+
+       SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+       SOCKET_OUT_CLOSURE(AO, "AO");
+
+       return type;
+}
 
 
-       add_output("AO", SHADER_SOCKET_CLOSURE);
+AmbientOcclusionNode::AmbientOcclusionNode()
+: ShaderNode(node_type)
+{
 }
 
 void AmbientOcclusionNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *color_in = input("Color");
 
 }
 
 void AmbientOcclusionNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *color_in = input("Color");
 
-       if(color_in->link) {
-               compiler.stack_assign(color_in);
-               compiler.add_node(NODE_CLOSURE_WEIGHT, color_in->stack_offset);
-       }
+       if(color_in->link)
+               compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
        else
        else
-               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
 
        compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset());
 }
 
        compiler.add_node(NODE_CLOSURE_AMBIENT_OCCLUSION, compiler.closure_mix_weight_offset());
 }
@@ -2342,41 +2494,28 @@ void AmbientOcclusionNode::compile(OSLCompiler& compiler)
 
 /* Volume Closure */
 
 
 /* Volume Closure */
 
-VolumeNode::VolumeNode()
-: ShaderNode("volume")
+VolumeNode::VolumeNode(const NodeType *node_type)
+: ShaderNode(node_type)
 {
        closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
 {
        closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-
-       add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
-       add_input("Density", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("VolumeMixWeight", SHADER_SOCKET_FLOAT, 0.0f, ShaderInput::USE_SVM);
-
-       add_output("Volume", SHADER_SOCKET_CLOSURE);
 }
 
 void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2)
 {
        ShaderInput *color_in = input("Color");
 
 }
 
 void VolumeNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2)
 {
        ShaderInput *color_in = input("Color");
 
-       if(color_in->link) {
-               compiler.stack_assign(color_in);
-               compiler.add_node(NODE_CLOSURE_WEIGHT, color_in->stack_offset);
-       }
+       if(color_in->link)
+               compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
        else
        else
-               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value);
+               compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
        
        
-       if(param1)
-               compiler.stack_assign(param1);
-       if(param2)
-               compiler.stack_assign(param2);
-
        compiler.add_node(NODE_CLOSURE_VOLUME,
                compiler.encode_uchar4(closure,
        compiler.add_node(NODE_CLOSURE_VOLUME,
                compiler.encode_uchar4(closure,
-                       (param1)? param1->stack_offset: SVM_STACK_INVALID,
-                       (param2)? param2->stack_offset: SVM_STACK_INVALID,
+                       (param1)? compiler.stack_assign(param1): SVM_STACK_INVALID,
+                       (param2)? compiler.stack_assign(param2): SVM_STACK_INVALID,
                        compiler.closure_mix_weight_offset()),
                        compiler.closure_mix_weight_offset()),
-               __float_as_int((param1)? param1->value.x: 0.0f),
-               __float_as_int((param2)? param2->value.x: 0.0f));
+               __float_as_int((param1)? get_float(param1->socket_type): 0.0f),
+               __float_as_int((param2)? get_float(param2->socket_type): 0.0f));
 }
 
 void VolumeNode::compile(SVMCompiler& compiler)
 }
 
 void VolumeNode::compile(SVMCompiler& compiler)
@@ -2391,7 +2530,21 @@ void VolumeNode::compile(OSLCompiler& /*compiler*/)
 
 /* Absorption Volume Closure */
 
 
 /* Absorption Volume Closure */
 
+NODE_DEFINE(AbsorptionVolumeNode)
+{
+       NodeType* type = NodeType::add("absorption_volume", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_FLOAT(density, "Density", 1.0f);
+       SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+       SOCKET_OUT_CLOSURE(volume, "Volume");
+
+       return type;
+}
+
 AbsorptionVolumeNode::AbsorptionVolumeNode()
 AbsorptionVolumeNode::AbsorptionVolumeNode()
+: VolumeNode(node_type)
 {
        closure = CLOSURE_VOLUME_ABSORPTION_ID;
 }
 {
        closure = CLOSURE_VOLUME_ABSORPTION_ID;
 }
@@ -2408,11 +2561,24 @@ void AbsorptionVolumeNode::compile(OSLCompiler& compiler)
 
 /* Scatter Volume Closure */
 
 
 /* Scatter Volume Closure */
 
+NODE_DEFINE(ScatterVolumeNode)
+{
+       NodeType* type = NodeType::add("scatter_volume", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_FLOAT(density, "Density", 1.0f);
+       SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
+       SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
+
+       SOCKET_OUT_CLOSURE(volume, "Volume");
+
+       return type;
+}
+
 ScatterVolumeNode::ScatterVolumeNode()
 ScatterVolumeNode::ScatterVolumeNode()
+: VolumeNode(node_type)
 {
        closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
 {
        closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
-       
-       add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.0f);
 }
 
 void ScatterVolumeNode::compile(SVMCompiler& compiler)
 }
 
 void ScatterVolumeNode::compile(SVMCompiler& compiler)
@@ -2427,59 +2593,71 @@ void ScatterVolumeNode::compile(OSLCompiler& compiler)
 
 /* Hair BSDF Closure */
 
 
 /* Hair BSDF Closure */
 
-static ShaderEnum hair_component_init()
+NODE_DEFINE(HairBsdfNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
 
 
-       enm.insert("Reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
-       enm.insert("Transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 
 
-       return enm;
-}
+       static NodeEnum component_enum;
+       component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
+       component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
+       SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID);
+       SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
+       SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f);
+       SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f);
+       SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f));
 
 
-ShaderEnum HairBsdfNode::component_enum = hair_component_init();
+       SOCKET_OUT_CLOSURE(BSDF, "BSDF");
+
+       return type;
+}
 
 HairBsdfNode::HairBsdfNode()
 
 HairBsdfNode::HairBsdfNode()
+: BsdfNode(node_type)
 {
        closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
 {
        closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
-       component = ustring("Reflection");
-
-       add_input("Offset", SHADER_SOCKET_FLOAT);
-       add_input("RoughnessU", SHADER_SOCKET_FLOAT);
-       add_input("RoughnessV", SHADER_SOCKET_FLOAT);
-       add_input("Tangent", SHADER_SOCKET_VECTOR);
 }
 
 void HairBsdfNode::compile(SVMCompiler& compiler)
 {
 }
 
 void HairBsdfNode::compile(SVMCompiler& compiler)
 {
-       closure = (ClosureType)component_enum[component];
+       closure = component;
 
        BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
 }
 
 void HairBsdfNode::compile(OSLCompiler& compiler)
 {
 
        BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
 }
 
 void HairBsdfNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("component", component);
-
+       compiler.parameter(this, "component");
        compiler.add(this, "node_hair_bsdf");
 }
 
 /* Geometry */
 
        compiler.add(this, "node_hair_bsdf");
 }
 
 /* Geometry */
 
+NODE_DEFINE(GeometryNode)
+{
+       NodeType* type = NodeType::add("geometry", create, NodeType::SHADER);
+
+       SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+
+       SOCKET_OUT_POINT(position, "Position");
+       SOCKET_OUT_NORMAL(normal, "Normal");
+       SOCKET_OUT_NORMAL(tangent, "Tangent");
+       SOCKET_OUT_NORMAL(true_normal, "True Normal");
+       SOCKET_OUT_VECTOR(incoming, "Incoming");
+       SOCKET_OUT_POINT(parametric, "Parametric");
+       SOCKET_OUT_FLOAT(backfacing, "Backfacing");
+       SOCKET_OUT_FLOAT(pointiness, "Pointiness");
+
+       return type;
+}
+
 GeometryNode::GeometryNode()
 GeometryNode::GeometryNode()
-: ShaderNode("geometry")
+: ShaderNode(node_type)
 {
        special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
 {
        special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
-
-       add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
-       add_output("Position", SHADER_SOCKET_POINT);
-       add_output("Normal", SHADER_SOCKET_NORMAL);
-       add_output("Tangent", SHADER_SOCKET_NORMAL);
-       add_output("True Normal", SHADER_SOCKET_NORMAL);
-       add_output("Incoming", SHADER_SOCKET_VECTOR);
-       add_output("Parametric", SHADER_SOCKET_POINT);
-       add_output("Backfacing", SHADER_SOCKET_FLOAT);
-       add_output("Pointiness", SHADER_SOCKET_FLOAT);
 }
 
 void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 }
 
 void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2499,8 +2677,8 @@ void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 void GeometryNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out;
 void GeometryNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out;
-       NodeType geom_node = NODE_GEOMETRY;
-       NodeType attr_node = NODE_ATTR;
+       ShaderNodeType geom_node = NODE_GEOMETRY;
+       ShaderNodeType attr_node = NODE_ATTR;
 
        if(bump == SHADER_BUMP_DX) {
                geom_node = NODE_GEOMETRY_BUMP_DX;
 
        if(bump == SHADER_BUMP_DX) {
                geom_node = NODE_GEOMETRY_BUMP_DX;
@@ -2513,57 +2691,49 @@ void GeometryNode::compile(SVMCompiler& compiler)
        
        out = output("Position");
        if(!out->links.empty()) {
        
        out = output("Position");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(geom_node, NODE_GEOM_P, out->stack_offset);
+               compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
        }
 
        out = output("Normal");
        if(!out->links.empty()) {
        }
 
        out = output("Normal");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(geom_node, NODE_GEOM_N, out->stack_offset);
+               compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out));
        }
 
        out = output("Tangent");
        if(!out->links.empty()) {
        }
 
        out = output("Tangent");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(geom_node, NODE_GEOM_T, out->stack_offset);
+               compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out));
        }
 
        out = output("True Normal");
        if(!out->links.empty()) {
        }
 
        out = output("True Normal");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(geom_node, NODE_GEOM_Ng, out->stack_offset);
+               compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out));
        }
 
        out = output("Incoming");
        if(!out->links.empty()) {
        }
 
        out = output("Incoming");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(geom_node, NODE_GEOM_I, out->stack_offset);
+               compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
        }
 
        out = output("Parametric");
        if(!out->links.empty()) {
        }
 
        out = output("Parametric");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(geom_node, NODE_GEOM_uv, out->stack_offset);
+               compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out));
        }
 
        out = output("Backfacing");
        if(!out->links.empty()) {
        }
 
        out = output("Backfacing");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out));
        }
 
        out = output("Pointiness");
        if(!out->links.empty()) {
        }
 
        out = output("Pointiness");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
                if(compiler.output_type() != SHADER_TYPE_VOLUME) {
                        compiler.add_node(attr_node,
                                          ATTR_STD_POINTINESS,
                if(compiler.output_type() != SHADER_TYPE_VOLUME) {
                        compiler.add_node(attr_node,
                                          ATTR_STD_POINTINESS,
-                                         out->stack_offset,
+                                         compiler.stack_assign(out),
                                          NODE_ATTR_FLOAT);
                }
                else {
                                          NODE_ATTR_FLOAT);
                }
                else {
-                       compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), out->stack_offset);
+                       compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
                }
        }
 }
                }
        }
 }
@@ -2582,21 +2752,30 @@ void GeometryNode::compile(OSLCompiler& compiler)
 
 /* TextureCoordinate */
 
 
 /* TextureCoordinate */
 
-TextureCoordinateNode::TextureCoordinateNode()
-: ShaderNode("texture_coordinate")
+NODE_DEFINE(TextureCoordinateNode)
 {
 {
-       add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
-       add_output("Generated", SHADER_SOCKET_POINT);
-       add_output("Normal", SHADER_SOCKET_NORMAL);
-       add_output("UV", SHADER_SOCKET_POINT);
-       add_output("Object", SHADER_SOCKET_POINT);
-       add_output("Camera", SHADER_SOCKET_POINT);
-       add_output("Window", SHADER_SOCKET_POINT);
-       add_output("Reflection", SHADER_SOCKET_NORMAL);
+       NodeType* type = NodeType::add("texture_coordinate", create, NodeType::SHADER);
+
+       SOCKET_BOOLEAN(from_dupli, "From Dupli", false);
+       SOCKET_BOOLEAN(use_transform, "Use Transform", false);
+       SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
+
+       SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
 
 
-       from_dupli = false;
-       use_transform = false;
-       ob_tfm = transform_identity();
+       SOCKET_OUT_POINT(generated, "Generated");
+       SOCKET_OUT_NORMAL(normal, "Normal");
+       SOCKET_OUT_POINT(UV, "UV");
+       SOCKET_OUT_POINT(object, "Object");
+       SOCKET_OUT_POINT(camera, "Camera");
+       SOCKET_OUT_POINT(window, "Window");
+       SOCKET_OUT_NORMAL(reflection, "Reflection");
+
+       return type;
+}
+
+TextureCoordinateNode::TextureCoordinateNode()
+: ShaderNode(node_type)
+{
 }
 
 void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 }
 
 void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2624,9 +2803,9 @@ void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attr
 void TextureCoordinateNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out;
 void TextureCoordinateNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out;
-       NodeType texco_node = NODE_TEX_COORD;
-       NodeType attr_node = NODE_ATTR;
-       NodeType geom_node = NODE_GEOMETRY;
+       ShaderNodeType texco_node = NODE_TEX_COORD;
+       ShaderNodeType attr_node = NODE_ATTR;
+       ShaderNodeType geom_node = NODE_GEOMETRY;
 
        if(bump == SHADER_BUMP_DX) {
                texco_node = NODE_TEX_COORD_BUMP_DX;
 
        if(bump == SHADER_BUMP_DX) {
                texco_node = NODE_TEX_COORD_BUMP_DX;
@@ -2642,49 +2821,41 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
        out = output("Generated");
        if(!out->links.empty()) {
                if(compiler.background) {
        out = output("Generated");
        if(!out->links.empty()) {
                if(compiler.background) {
-                       compiler.stack_assign(out);
-                       compiler.add_node(geom_node, NODE_GEOM_P, out->stack_offset);
+                       compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
                }
                else {
                        if(from_dupli) {
                }
                else {
                        if(from_dupli) {
-                               compiler.stack_assign(out);
-                               compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, out->stack_offset);
+                               compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out));
                        }
                        else if(compiler.output_type() == SHADER_TYPE_VOLUME) {
                        }
                        else if(compiler.output_type() == SHADER_TYPE_VOLUME) {
-                               compiler.stack_assign(out);
-                               compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, out->stack_offset);
+                               compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out));
                        }
                        else {
                                int attr = compiler.attribute(ATTR_STD_GENERATED);
                        }
                        else {
                                int attr = compiler.attribute(ATTR_STD_GENERATED);
-                               compiler.stack_assign(out);
-                               compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3);
+                               compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
                        }
                }
        }
 
        out = output("Normal");
        if(!out->links.empty()) {
                        }
                }
        }
 
        out = output("Normal");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(texco_node, NODE_TEXCO_NORMAL, out->stack_offset);
+               compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out));
        }
 
        out = output("UV");
        if(!out->links.empty()) {
                if(from_dupli) {
        }
 
        out = output("UV");
        if(!out->links.empty()) {
                if(from_dupli) {
-                       compiler.stack_assign(out);
-                       compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, out->stack_offset);
+                       compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
                }
                else {
                        int attr = compiler.attribute(ATTR_STD_UV);
                }
                else {
                        int attr = compiler.attribute(ATTR_STD_UV);
-                       compiler.stack_assign(out);
-                       compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3);
+                       compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
                }
        }
 
        out = output("Object");
        if(!out->links.empty()) {
                }
        }
 
        out = output("Object");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(texco_node, NODE_TEXCO_OBJECT, out->stack_offset, use_transform);
+               compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform);
                if(use_transform) {
                        Transform ob_itfm = transform_inverse(ob_tfm);
                        compiler.add_node(ob_itfm.x);
                if(use_transform) {
                        Transform ob_itfm = transform_inverse(ob_tfm);
                        compiler.add_node(ob_itfm.x);
@@ -2696,25 +2867,21 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
 
        out = output("Camera");
        if(!out->links.empty()) {
 
        out = output("Camera");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(texco_node, NODE_TEXCO_CAMERA, out->stack_offset);
+               compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out));
        }
 
        out = output("Window");
        if(!out->links.empty()) {
        }
 
        out = output("Window");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(texco_node, NODE_TEXCO_WINDOW, out->stack_offset);
+               compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out));
        }
 
        out = output("Reflection");
        if(!out->links.empty()) {
                if(compiler.background) {
        }
 
        out = output("Reflection");
        if(!out->links.empty()) {
                if(compiler.background) {
-                       compiler.stack_assign(out);
-                       compiler.add_node(geom_node, NODE_GEOM_I, out->stack_offset);
+                       compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
                }
                else {
                }
                else {
-                       compiler.stack_assign(out);
-                       compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, out->stack_offset);
+                       compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out));
                }
        }
 }
                }
        }
 }
@@ -2732,22 +2899,32 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
                compiler.parameter("is_background", true);
        if(compiler.output_type() == SHADER_TYPE_VOLUME)
                compiler.parameter("is_volume", true);
                compiler.parameter("is_background", true);
        if(compiler.output_type() == SHADER_TYPE_VOLUME)
                compiler.parameter("is_volume", true);
-       compiler.parameter("use_transform", use_transform);
+       compiler.parameter(this, "use_transform");
        Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
        compiler.parameter("object_itfm", ob_itfm);
 
        Transform ob_itfm = transform_transpose(transform_inverse(ob_tfm));
        compiler.parameter("object_itfm", ob_itfm);
 
-       compiler.parameter("from_dupli", from_dupli);
+       compiler.parameter(this, "from_dupli");
 
        compiler.add(this, "node_texture_coordinate");
 }
 
 
        compiler.add(this, "node_texture_coordinate");
 }
 
-UVMapNode::UVMapNode()
-: ShaderNode("uvmap")
+/* UV Map */
+
+NODE_DEFINE(UVMapNode)
 {
 {
-       attribute = "";
-       from_dupli = false;
+       NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER);
+
+       SOCKET_IN_STRING(attribute, "attribute", ustring(""));
+       SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
 
 
-       add_output("UV", SHADER_SOCKET_POINT);
+       SOCKET_OUT_POINT(UV, "UV");
+
+       return type;
+}
+
+UVMapNode::UVMapNode()
+: ShaderNode(node_type)
+{
 }
 
 void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 }
 
 void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -2769,8 +2946,8 @@ void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 void UVMapNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out = output("UV");
 void UVMapNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out = output("UV");
-       NodeType texco_node = NODE_TEX_COORD;
-       NodeType attr_node = NODE_ATTR;
+       ShaderNodeType texco_node = NODE_TEX_COORD;
+       ShaderNodeType attr_node = NODE_ATTR;
        int attr;
 
        if(bump == SHADER_BUMP_DX) {
        int attr;
 
        if(bump == SHADER_BUMP_DX) {
@@ -2784,8 +2961,7 @@ void UVMapNode::compile(SVMCompiler& compiler)
 
        if(!out->links.empty()) {
                if(from_dupli) {
 
        if(!out->links.empty()) {
                if(from_dupli) {
-                       compiler.stack_assign(out);
-                       compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, out->stack_offset);
+                       compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
                }
                else {
                        if(attribute != "")
                }
                else {
                        if(attribute != "")
@@ -2793,8 +2969,7 @@ void UVMapNode::compile(SVMCompiler& compiler)
                        else
                                attr = compiler.attribute(ATTR_STD_UV);
 
                        else
                                attr = compiler.attribute(ATTR_STD_UV);
 
-                       compiler.stack_assign(out);
-                       compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3);
+                       compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
                }
        }
 }
                }
        }
 }
@@ -2808,27 +2983,36 @@ void UVMapNode::compile(OSLCompiler& compiler)
        else
                compiler.parameter("bump_offset", "center");
 
        else
                compiler.parameter("bump_offset", "center");
 
-       compiler.parameter("from_dupli", from_dupli);
-       compiler.parameter("name", attribute.c_str());
+       compiler.parameter(this, "from_dupli");
+       compiler.parameter(this, "attribute");
        compiler.add(this, "node_uv_map");
 }
 
 /* Light Path */
 
        compiler.add(this, "node_uv_map");
 }
 
 /* Light Path */
 
+NODE_DEFINE(LightPathNode)
+{
+       NodeType* type = NodeType::add("light_path", create, NodeType::SHADER);
+
+       SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray");
+       SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray");
+       SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray");
+       SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray");
+       SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray");
+       SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray");
+       SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray");
+       SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray");
+       SOCKET_OUT_FLOAT(ray_length, "Ray Length");
+       SOCKET_OUT_FLOAT(ray_depth, "Ray Depth");
+       SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
+       SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
+
+       return type;
+}
+
 LightPathNode::LightPathNode()
 LightPathNode::LightPathNode()
-: ShaderNode("light_path")
+: ShaderNode(node_type)
 {
 {
-       add_output("Is Camera Ray", SHADER_SOCKET_FLOAT);
-       add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT);
-       add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT);
-       add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT);
-       add_output("Is Singular Ray", SHADER_SOCKET_FLOAT);
-       add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
-       add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
-       add_output("Is Volume Scatter Ray", SHADER_SOCKET_FLOAT);
-       add_output("Ray Length", SHADER_SOCKET_FLOAT);
-       add_output("Ray Depth", SHADER_SOCKET_FLOAT);
-       add_output("Transparent Depth", SHADER_SOCKET_FLOAT);
 }
 
 void LightPathNode::compile(SVMCompiler& compiler)
 }
 
 void LightPathNode::compile(SVMCompiler& compiler)
@@ -2837,69 +3021,63 @@ void LightPathNode::compile(SVMCompiler& compiler)
 
        out = output("Is Camera Ray");
        if(!out->links.empty()) {
 
        out = output("Is Camera Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out));
        }
 
        out = output("Is Shadow Ray");
        if(!out->links.empty()) {
        }
 
        out = output("Is Shadow Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out));
        }
 
        out = output("Is Diffuse Ray");
        if(!out->links.empty()) {
        }
 
        out = output("Is Diffuse Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out));
        }
 
        out = output("Is Glossy Ray");
        if(!out->links.empty()) {
        }
 
        out = output("Is Glossy Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out));
        }
 
        out = output("Is Singular Ray");
        if(!out->links.empty()) {
        }
 
        out = output("Is Singular Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out));
        }
 
        out = output("Is Reflection Ray");
        if(!out->links.empty()) {
        }
 
        out = output("Is Reflection Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out));
        }
 
 
        out = output("Is Transmission Ray");
        if(!out->links.empty()) {
        }
 
 
        out = output("Is Transmission Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out));
        }
        
        out = output("Is Volume Scatter Ray");
        if(!out->links.empty()) {
        }
        
        out = output("Is Volume Scatter Ray");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out));
        }
 
        out = output("Ray Length");
        if(!out->links.empty()) {
        }
 
        out = output("Ray Length");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out));
        }
        
        out = output("Ray Depth");
        if(!out->links.empty()) {
        }
        
        out = output("Ray Depth");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out));
        }
 
        out = output("Transparent Depth");
        if(!out->links.empty()) {
        }
 
        out = output("Transparent Depth");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, out->stack_offset);
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out));
+       }
+
+       out = output("Transmission Depth");
+       if(!out->links.empty()) {
+               compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out));
        }
 }
 
        }
 }
 
@@ -2910,14 +3088,23 @@ void LightPathNode::compile(OSLCompiler& compiler)
 
 /* Light Falloff */
 
 
 /* Light Falloff */
 
+NODE_DEFINE(LightFalloffNode)
+{
+       NodeType* type = NodeType::add("light_fallof", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(strength, "Strength", 100.0f);
+       SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
+
+       SOCKET_OUT_FLOAT(quadratic, "Quadratic");
+       SOCKET_OUT_FLOAT(linear, "Linear");
+       SOCKET_OUT_FLOAT(constant, "Constant");
+
+       return type;
+}
+
 LightFalloffNode::LightFalloffNode()
 LightFalloffNode::LightFalloffNode()
-: ShaderNode("light_fallof")
+: ShaderNode(node_type)
 {
 {
-       add_input("Strength", SHADER_SOCKET_FLOAT, 100.0f);
-       add_input("Smooth", SHADER_SOCKET_FLOAT, 0.0f);
-       add_output("Quadratic", SHADER_SOCKET_FLOAT);
-       add_output("Linear", SHADER_SOCKET_FLOAT);
-       add_output("Constant", SHADER_SOCKET_FLOAT);
 }
 
 void LightFalloffNode::compile(SVMCompiler& compiler)
 }
 
 void LightFalloffNode::compile(SVMCompiler& compiler)
@@ -2925,28 +3112,31 @@ void LightFalloffNode::compile(SVMCompiler& compiler)
        ShaderInput *strength_in = input("Strength");
        ShaderInput *smooth_in = input("Smooth");
 
        ShaderInput *strength_in = input("Strength");
        ShaderInput *smooth_in = input("Smooth");
 
-       compiler.stack_assign(strength_in);
-       compiler.stack_assign(smooth_in);
-
        ShaderOutput *out = output("Quadratic");
        if(!out->links.empty()) {
        ShaderOutput *out = output("Quadratic");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
                compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_QUADRATIC,
                compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_QUADRATIC,
-                       compiler.encode_uchar4(strength_in->stack_offset, smooth_in->stack_offset, out->stack_offset));
+                       compiler.encode_uchar4(
+                               compiler.stack_assign(strength_in),
+                               compiler.stack_assign(smooth_in),
+                               compiler.stack_assign(out)));
        }
 
        out = output("Linear");
        if(!out->links.empty()) {
        }
 
        out = output("Linear");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
                compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_LINEAR,
                compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_LINEAR,
-                       compiler.encode_uchar4(strength_in->stack_offset, smooth_in->stack_offset, out->stack_offset));
+                       compiler.encode_uchar4(
+                               compiler.stack_assign(strength_in),
+                               compiler.stack_assign(smooth_in),
+                               compiler.stack_assign(out)));
        }
 
        out = output("Constant");
        if(!out->links.empty()) {
        }
 
        out = output("Constant");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
                compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_CONSTANT,
                compiler.add_node(NODE_LIGHT_FALLOFF, NODE_LIGHT_FALLOFF_CONSTANT,
-                       compiler.encode_uchar4(strength_in->stack_offset, smooth_in->stack_offset, out->stack_offset));
+                       compiler.encode_uchar4(
+                               compiler.stack_assign(strength_in),
+                               compiler.stack_assign(smooth_in),
+                               compiler.stack_assign(out)));
        }
 }
 
        }
 }
 
@@ -2957,39 +3147,43 @@ void LightFalloffNode::compile(OSLCompiler& compiler)
 
 /* Object Info */
 
 
 /* Object Info */
 
+NODE_DEFINE(ObjectInfoNode)
+{
+       NodeType* type = NodeType::add("object_info", create, NodeType::SHADER);
+
+       SOCKET_OUT_VECTOR(location, "Location");
+       SOCKET_OUT_FLOAT(object_index, "Object Index");
+       SOCKET_OUT_FLOAT(material_index, "Material Index");
+       SOCKET_OUT_FLOAT(random, "Random");
+
+       return type;
+}
+
 ObjectInfoNode::ObjectInfoNode()
 ObjectInfoNode::ObjectInfoNode()
-: ShaderNode("object_info")
+: ShaderNode(node_type)
 {
 {
-       add_output("Location", SHADER_SOCKET_VECTOR);
-       add_output("Object Index", SHADER_SOCKET_FLOAT);
-       add_output("Material Index", SHADER_SOCKET_FLOAT);
-       add_output("Random", SHADER_SOCKET_FLOAT);
 }
 
 void ObjectInfoNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out = output("Location");
        if(!out->links.empty()) {
 }
 
 void ObjectInfoNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out = output("Location");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, out->stack_offset);
+               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out));
        }
 
        out = output("Object Index");
        if(!out->links.empty()) {
        }
 
        out = output("Object Index");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, out->stack_offset);
+               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out));
        }
 
        out = output("Material Index");
        if(!out->links.empty()) {
        }
 
        out = output("Material Index");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, out->stack_offset);
+               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out));
        }
 
        out = output("Random");
        if(!out->links.empty()) {
        }
 
        out = output("Random");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, out->stack_offset);
+               compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out));
        }
 }
 
        }
 }
 
@@ -3000,19 +3194,27 @@ void ObjectInfoNode::compile(OSLCompiler& compiler)
 
 /* Particle Info */
 
 
 /* Particle Info */
 
-ParticleInfoNode::ParticleInfoNode()
-: ShaderNode("particle_info")
+NODE_DEFINE(ParticleInfoNode)
 {
 {
-       add_output("Index", SHADER_SOCKET_FLOAT);
-       add_output("Age", SHADER_SOCKET_FLOAT);
-       add_output("Lifetime", SHADER_SOCKET_FLOAT);
-       add_output("Location", SHADER_SOCKET_POINT);
+       NodeType* type = NodeType::add("particle_info", create, NodeType::SHADER);
+
+       SOCKET_OUT_FLOAT(index, "Index");
+       SOCKET_OUT_FLOAT(age, "Age");
+       SOCKET_OUT_FLOAT(lifetime, "Lifetime");
+       SOCKET_OUT_POINT(location, "Location");
 #if 0  /* not yet supported */
 #if 0  /* not yet supported */
-       add_output("Rotation", SHADER_SOCKET_QUATERNION);
+       SOCKET_OUT_QUATERNION(rotation, "Rotation");
 #endif
 #endif
-       add_output("Size", SHADER_SOCKET_FLOAT);
-       add_output("Velocity", SHADER_SOCKET_VECTOR);
-       add_output("Angular Velocity", SHADER_SOCKET_VECTOR);
+       SOCKET_OUT_FLOAT(size, "Size");
+       SOCKET_OUT_VECTOR(velocity, "Velocity");
+       SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
+
+       return type;
+}
+
+ParticleInfoNode::ParticleInfoNode()
+: ShaderNode(node_type)
+{
 }
 
 void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 }
 
 void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3045,53 +3247,45 @@ void ParticleInfoNode::compile(SVMCompiler& compiler)
        
        out = output("Index");
        if(!out->links.empty()) {
        
        out = output("Index");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out));
        }
        
        out = output("Age");
        if(!out->links.empty()) {
        }
        
        out = output("Age");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out));
        }
        
        out = output("Lifetime");
        if(!out->links.empty()) {
        }
        
        out = output("Lifetime");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out));
        }
        
        out = output("Location");
        if(!out->links.empty()) {
        }
        
        out = output("Location");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out));
        }
        
        /* quaternion data is not yet supported by Cycles */
 #if 0
        out = output("Rotation");
        if(!out->links.empty()) {
        }
        
        /* quaternion data is not yet supported by Cycles */
 #if 0
        out = output("Rotation");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out));
        }
 #endif
        
        out = output("Size");
        if(!out->links.empty()) {
        }
 #endif
        
        out = output("Size");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out));
        }
        
        out = output("Velocity");
        if(!out->links.empty()) {
        }
        
        out = output("Velocity");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out));
        }
        
        out = output("Angular Velocity");
        if(!out->links.empty()) {
        }
        
        out = output("Angular Velocity");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, out->stack_offset);
+               compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out));
        }
 }
 
        }
 }
 
@@ -3102,15 +3296,24 @@ void ParticleInfoNode::compile(OSLCompiler& compiler)
 
 /* Hair Info */
 
 
 /* Hair Info */
 
-HairInfoNode::HairInfoNode()
-: ShaderNode("hair_info")
+NODE_DEFINE(HairInfoNode)
+{
+       NodeType* type = NodeType::add("hair_info", create, NodeType::SHADER);
+
+       SOCKET_OUT_FLOAT(is_strand, "Is Strand");
+       SOCKET_OUT_FLOAT(intercept, "Intercept");
+       SOCKET_OUT_FLOAT(thickness, "Thickness");
+       SOCKET_OUT_NORMAL(tangent Normal, "Tangent Normal");
+#if 0 /*output for minimum hair width transparency - deactivated */
+       SOCKET_OUT_FLOAT(fade, "Fade");
+#endif
+
+       return type;
+}
+
+HairInfoNode::HairInfoNode()
+: ShaderNode(node_type)
 {
 {
-       add_output("Is Strand", SHADER_SOCKET_FLOAT);
-       add_output("Intercept", SHADER_SOCKET_FLOAT);
-       add_output("Thickness", SHADER_SOCKET_FLOAT);
-       add_output("Tangent Normal", SHADER_SOCKET_NORMAL);
-       /*output for minimum hair width transparency - deactivated*/
-       /*add_output("Fade", SHADER_SOCKET_FLOAT);*/
 }
 
 void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 }
 
 void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3131,33 +3334,28 @@ void HairInfoNode::compile(SVMCompiler& compiler)
        
        out = output("Is Strand");
        if(!out->links.empty()) {
        
        out = output("Is Strand");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, out->stack_offset);
+               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out));
        }
 
        out = output("Intercept");
        if(!out->links.empty()) {
                int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
        }
 
        out = output("Intercept");
        if(!out->links.empty()) {
                int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_ATTR, attr, out->stack_offset, NODE_ATTR_FLOAT);
+               compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT);
        }
 
        out = output("Thickness");
        if(!out->links.empty()) {
        }
 
        out = output("Thickness");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, out->stack_offset);
+               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out));
        }
 
        out = output("Tangent Normal");
        if(!out->links.empty()) {
        }
 
        out = output("Tangent Normal");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, out->stack_offset);
+               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out));
        }
 
        /*out = output("Fade");
        if(!out->links.empty()) {
        }
 
        /*out = output("Fade");
        if(!out->links.empty()) {
-               compiler.stack_assign(out);
-               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, out->stack_offset);
+               compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out));
        }*/
 
 }
        }*/
 
 }
@@ -3169,20 +3367,31 @@ void HairInfoNode::compile(OSLCompiler& compiler)
 
 /* Value */
 
 
 /* Value */
 
+NODE_DEFINE(ValueNode)
+{
+       NodeType* type = NodeType::add("value", create, NodeType::SHADER);
+
+       SOCKET_FLOAT(value, "Value", 0.0f);
+       SOCKET_OUT_FLOAT(value, "Value");
+
+       return type;
+}
+
 ValueNode::ValueNode()
 ValueNode::ValueNode()
-: ShaderNode("value")
+: ShaderNode(node_type)
 {
 {
-       value = 0.0f;
+}
 
 
-       add_output("Value", SHADER_SOCKET_FLOAT);
+void ValueNode::constant_fold(const ConstantFolder& folder)
+{
+       folder.make_constant(value);
 }
 
 void ValueNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *val_out = output("Value");
 
 }
 
 void ValueNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *val_out = output("Value");
 
-       compiler.stack_assign(val_out);
-       compiler.add_node(NODE_VALUE_F, __float_as_int(value), val_out->stack_offset);
+       compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out));
 }
 
 void ValueNode::compile(OSLCompiler& compiler)
 }
 
 void ValueNode::compile(OSLCompiler& compiler)
@@ -3193,21 +3402,32 @@ void ValueNode::compile(OSLCompiler& compiler)
 
 /* Color */
 
 
 /* Color */
 
+NODE_DEFINE(ColorNode)
+{
+       NodeType* type = NodeType::add("color", create, NodeType::SHADER);
+
+       SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
+
 ColorNode::ColorNode()
 ColorNode::ColorNode()
-: ShaderNode("color")
+: ShaderNode(node_type)
 {
 {
-       value = make_float3(0.0f, 0.0f, 0.0f);
+}
 
 
-       add_output("Color", SHADER_SOCKET_COLOR);
+void ColorNode::constant_fold(const ConstantFolder& folder)
+{
+       folder.make_constant(value);
 }
 
 void ColorNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *color_out = output("Color");
 
 }
 
 void ColorNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *color_out = output("Color");
 
-       if(color_out && !color_out->links.empty()) {
-               compiler.stack_assign(color_out);
-               compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
+       if(!color_out->links.empty()) {
+               compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
                compiler.add_node(NODE_VALUE_V, value);
        }
 }
                compiler.add_node(NODE_VALUE_V, value);
        }
 }
@@ -3221,12 +3441,21 @@ void ColorNode::compile(OSLCompiler& compiler)
 
 /* Add Closure */
 
 
 /* Add Closure */
 
+NODE_DEFINE(AddClosureNode)
+{
+       NodeType* type = NodeType::add("add_closure", create, NodeType::SHADER);
+
+       SOCKET_IN_CLOSURE(closure1, "Closure1");
+       SOCKET_IN_CLOSURE(closure2, "Closure2");
+       SOCKET_OUT_CLOSURE(closure, "Closure");
+
+       return type;
+}
+
 AddClosureNode::AddClosureNode()
 AddClosureNode::AddClosureNode()
-: ShaderNode("add_closure")
+: ShaderNode(node_type)
 {
 {
-       add_input("Closure1", SHADER_SOCKET_CLOSURE);
-       add_input("Closure2", SHADER_SOCKET_CLOSURE);
-       add_output("Closure",  SHADER_SOCKET_CLOSURE);
+       special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
 }
 
 void AddClosureNode::compile(SVMCompiler& /*compiler*/)
 }
 
 void AddClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3239,17 +3468,39 @@ void AddClosureNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_add_closure");
 }
 
        compiler.add(this, "node_add_closure");
 }
 
+void AddClosureNode::constant_fold(const ConstantFolder& folder)
+{
+       ShaderInput *closure1_in = input("Closure1");
+       ShaderInput *closure2_in = input("Closure2");
+
+       /* remove useless add closures nodes */
+       if(!closure1_in->link) {
+               folder.bypass_or_discard(closure2_in);
+       }
+       else if(!closure2_in->link) {
+               folder.bypass_or_discard(closure1_in);
+       }
+}
+
 /* Mix Closure */
 
 /* Mix Closure */
 
+NODE_DEFINE(MixClosureNode)
+{
+       NodeType* type = NodeType::add("mix_closure", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
+       SOCKET_IN_CLOSURE(closure1, "Closure1");
+       SOCKET_IN_CLOSURE(closure2, "Closure2");
+
+       SOCKET_OUT_CLOSURE(closure, "Closure");
+
+       return type;
+}
+
 MixClosureNode::MixClosureNode()
 MixClosureNode::MixClosureNode()
-: ShaderNode("mix_closure")
+: ShaderNode(node_type)
 {
 {
-       special_type = SHADER_SPECIAL_TYPE_MIX_CLOSURE;
-       
-       add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
-       add_input("Closure1", SHADER_SOCKET_CLOSURE);
-       add_input("Closure2", SHADER_SOCKET_CLOSURE);
-       add_output("Closure",  SHADER_SOCKET_CLOSURE);
+       special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
 }
 
 void MixClosureNode::compile(SVMCompiler& /*compiler*/)
 }
 
 void MixClosureNode::compile(SVMCompiler& /*compiler*/)
@@ -3262,15 +3513,48 @@ void MixClosureNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_mix_closure");
 }
 
        compiler.add(this, "node_mix_closure");
 }
 
+void MixClosureNode::constant_fold(const ConstantFolder& folder)
+{
+       ShaderInput *fac_in = input("Fac");
+       ShaderInput *closure1_in = input("Closure1");
+       ShaderInput *closure2_in = input("Closure2");
+
+       /* remove useless mix closures nodes */
+       if(closure1_in->link == closure2_in->link) {
+               folder.bypass_or_discard(closure1_in);
+       }
+       /* remove unused mix closure input when factor is 0.0 or 1.0
+        * check for closure links and make sure factor link is disconnected */
+       else if(!fac_in->link) {
+               /* factor 0.0 */
+               if(fac <= 0.0f) {
+                       folder.bypass_or_discard(closure1_in);
+               }
+               /* factor 1.0 */
+               else if(fac >= 1.0f) {
+                       folder.bypass_or_discard(closure2_in);
+               }
+       }
+}
+
 /* Mix Closure */
 
 /* Mix Closure */
 
+NODE_DEFINE(MixClosureWeightNode)
+{
+       NodeType* type = NodeType::add("mix_closure_weight", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(weight, "Weight", 1.0f);
+       SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+
+       SOCKET_OUT_FLOAT(weight1, "Weight1");
+       SOCKET_OUT_FLOAT(weight2, "Weight2");
+
+       return type;
+}
+
 MixClosureWeightNode::MixClosureWeightNode()
 MixClosureWeightNode::MixClosureWeightNode()
-: ShaderNode("mix_closure_weight")
+: ShaderNode(node_type)
 {
 {
-       add_input("Weight", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
-       add_output("Weight1", SHADER_SOCKET_FLOAT);
-       add_output("Weight2", SHADER_SOCKET_FLOAT);
 }
 
 void MixClosureWeightNode::compile(SVMCompiler& compiler)
 }
 
 void MixClosureWeightNode::compile(SVMCompiler& compiler)
@@ -3280,14 +3564,12 @@ void MixClosureWeightNode::compile(SVMCompiler& compiler)
        ShaderOutput *weight1_out = output("Weight1");
        ShaderOutput *weight2_out = output("Weight2");
 
        ShaderOutput *weight1_out = output("Weight1");
        ShaderOutput *weight2_out = output("Weight2");
 
-       compiler.stack_assign(weight_in);
-       compiler.stack_assign(fac_in);
-       compiler.stack_assign(weight1_out);
-       compiler.stack_assign(weight2_out);
-
        compiler.add_node(NODE_MIX_CLOSURE,
        compiler.add_node(NODE_MIX_CLOSURE,
-               compiler.encode_uchar4(fac_in->stack_offset, weight_in->stack_offset,
-                       weight1_out->stack_offset, weight2_out->stack_offset));
+               compiler.encode_uchar4(
+                       compiler.stack_assign(fac_in),
+                       compiler.stack_assign(weight_in),
+                       compiler.stack_assign(weight1_out),
+                       compiler.stack_assign(weight2_out)));
 }
 
 void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
 }
 
 void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
@@ -3297,12 +3579,38 @@ void MixClosureWeightNode::compile(OSLCompiler& /*compiler*/)
 
 /* Invert */
 
 
 /* Invert */
 
+NODE_DEFINE(InvertNode)
+{
+       NodeType* type = NodeType::add("invert", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
+
 InvertNode::InvertNode()
 InvertNode::InvertNode()
-: ShaderNode("invert")
+: ShaderNode(node_type)
 {
 {
-       add_input("Fac", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Color", SHADER_SOCKET_COLOR);
-       add_output("Color",  SHADER_SOCKET_COLOR);
+}
+
+void InvertNode::constant_fold(const ConstantFolder& folder)
+{
+       ShaderInput *fac_in = input("Fac");
+       ShaderInput *color_in = input("Color");
+
+       if(!fac_in->link) {
+               /* evaluate fully constant node */
+               if(!color_in->link) {
+                       folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac));
+               }
+               /* remove no-op node */
+               else if(fac == 0.0f) {
+                       folder.bypass(color_in->link);
+               }
+       }
 }
 
 void InvertNode::compile(SVMCompiler& compiler)
 }
 
 void InvertNode::compile(SVMCompiler& compiler)
@@ -3311,11 +3619,10 @@ void InvertNode::compile(SVMCompiler& compiler)
        ShaderInput *color_in = input("Color");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *color_in = input("Color");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(fac_in);
-       compiler.stack_assign(color_in);
-       compiler.stack_assign(color_out);
-
-       compiler.add_node(NODE_INVERT, fac_in->stack_offset, color_in->stack_offset, color_out->stack_offset);
+       compiler.add_node(NODE_INVERT,
+               compiler.stack_assign(fac_in),
+               compiler.stack_assign(color_in),
+               compiler.stack_assign(color_out));
 }
 
 void InvertNode::compile(OSLCompiler& compiler)
 }
 
 void InvertNode::compile(OSLCompiler& compiler)
@@ -3325,46 +3632,46 @@ void InvertNode::compile(OSLCompiler& compiler)
 
 /* Mix */
 
 
 /* Mix */
 
-MixNode::MixNode()
-: ShaderNode("mix")
+NODE_DEFINE(MixNode)
 {
 {
-       type = ustring("Mix");
+       NodeType* type = NodeType::add("mix", create, NodeType::SHADER);
 
 
-       use_clamp = false;
+       static NodeEnum type_enum;
+       type_enum.insert("mix", NODE_MIX_BLEND);
+       type_enum.insert("add", NODE_MIX_ADD);
+       type_enum.insert("multiply", NODE_MIX_MUL);
+       type_enum.insert("screen", NODE_MIX_SCREEN);
+       type_enum.insert("overlay", NODE_MIX_OVERLAY);
+       type_enum.insert("subtract", NODE_MIX_SUB);
+       type_enum.insert("divide", NODE_MIX_DIV);
+       type_enum.insert("difference", NODE_MIX_DIFF);
+       type_enum.insert("darken", NODE_MIX_DARK);
+       type_enum.insert("lighten", NODE_MIX_LIGHT);
+       type_enum.insert("dodge", NODE_MIX_DODGE);
+       type_enum.insert("burn", NODE_MIX_BURN);
+       type_enum.insert("hue", NODE_MIX_HUE);
+       type_enum.insert("saturation", NODE_MIX_SAT);
+       type_enum.insert("value", NODE_MIX_VAL);
+       type_enum.insert("color", NODE_MIX_COLOR);
+       type_enum.insert("soft_light", NODE_MIX_SOFT);
+       type_enum.insert("linear_light", NODE_MIX_LINEAR);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND);
 
 
-       add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f);
-       add_input("Color1", SHADER_SOCKET_COLOR);
-       add_input("Color2", SHADER_SOCKET_COLOR);
-       add_output("Color",  SHADER_SOCKET_COLOR);
-}
+       SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
 
 
-static ShaderEnum mix_type_init()
-{
-       ShaderEnum enm;
+       SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
+       SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
 
 
-       enm.insert("Mix", NODE_MIX_BLEND);
-       enm.insert("Add", NODE_MIX_ADD);
-       enm.insert("Multiply", NODE_MIX_MUL);
-       enm.insert("Screen", NODE_MIX_SCREEN);
-       enm.insert("Overlay", NODE_MIX_OVERLAY);
-       enm.insert("Subtract", NODE_MIX_SUB);
-       enm.insert("Divide", NODE_MIX_DIV);
-       enm.insert("Difference", NODE_MIX_DIFF);
-       enm.insert("Darken", NODE_MIX_DARK);
-       enm.insert("Lighten", NODE_MIX_LIGHT);
-       enm.insert("Dodge", NODE_MIX_DODGE);
-       enm.insert("Burn", NODE_MIX_BURN);
-       enm.insert("Hue", NODE_MIX_HUE);
-       enm.insert("Saturation", NODE_MIX_SAT);
-       enm.insert("Value", NODE_MIX_VAL);
-       enm.insert("Color", NODE_MIX_COLOR);
-       enm.insert("Soft Light", NODE_MIX_SOFT);
-       enm.insert("Linear Light", NODE_MIX_LINEAR);
+       SOCKET_OUT_COLOR(color, "Color");
 
 
-       return enm;
+       return type;
 }
 
 }
 
-ShaderEnum MixNode::type_enum = mix_type_init();
+MixNode::MixNode()
+: ShaderNode(node_type)
+{
+}
 
 void MixNode::compile(SVMCompiler& compiler)
 {
 
 void MixNode::compile(SVMCompiler& compiler)
 {
@@ -3373,35 +3680,93 @@ void MixNode::compile(SVMCompiler& compiler)
        ShaderInput *color2_in = input("Color2");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *color2_in = input("Color2");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(fac_in);
-       compiler.stack_assign(color1_in);
-       compiler.stack_assign(color2_in);
-       compiler.stack_assign(color_out);
-
-       compiler.add_node(NODE_MIX, fac_in->stack_offset, color1_in->stack_offset, color2_in->stack_offset);
-       compiler.add_node(NODE_MIX, type_enum[type], color_out->stack_offset);
+       compiler.add_node(NODE_MIX,
+               compiler.stack_assign(fac_in),
+               compiler.stack_assign(color1_in),
+               compiler.stack_assign(color2_in));
+       compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out));
 
        if(use_clamp) {
 
        if(use_clamp) {
-               compiler.add_node(NODE_MIX, 0, color_out->stack_offset);
-               compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, color_out->stack_offset);
+               compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
+               compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out));
        }
 }
 
 void MixNode::compile(OSLCompiler& compiler)
 {
        }
 }
 
 void MixNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("type", type);
-       compiler.parameter("Clamp", use_clamp);
+       compiler.parameter(this, "type");
+       compiler.parameter(this, "use_clamp");
        compiler.add(this, "node_mix");
 }
 
        compiler.add(this, "node_mix");
 }
 
+void MixNode::constant_fold(const ConstantFolder& folder)
+{
+       ShaderInput *fac_in = input("Fac");
+       ShaderInput *color1_in = input("Color1");
+       ShaderInput *color2_in = input("Color2");
+
+       /* evaluate fully constant node */
+       if(folder.all_inputs_constant()) {
+               folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp);
+               return;
+       }
+
+       /* remove no-op node when factor is 0.0 */
+       if(!fac_in->link && fac <= 0.0f) {
+               /* note that some of the modes will clamp out of bounds values even without use_clamp */
+               if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) {
+                       if(!color1_in->link) {
+                               folder.make_constant_clamp(svm_mix(type, 0.0f, color1, color1), use_clamp);
+                               return;
+                       }
+               }
+               else if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) {
+                       return;
+               }
+       }
+
+       if(type == NODE_MIX_BLEND) {
+               /* remove useless mix colors nodes */
+               if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) {
+                       if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) {
+                               return;
+                       }
+               }
+
+               /* remove no-op mix color node when factor is 1.0 */
+               if(!fac_in->link && fac >= 1.0f) {
+                       if(folder.try_bypass_or_make_constant(color2_in, color2, use_clamp)) {
+                               return;
+                       }
+               }
+       }
+}
+
 /* Combine RGB */
 /* Combine RGB */
+
+NODE_DEFINE(CombineRGBNode)
+{
+       NodeType* type = NodeType::add("combine_rgb", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(r, "R", 0.0f);
+       SOCKET_IN_FLOAT(g, "G", 0.0f);
+       SOCKET_IN_FLOAT(b, "B", 0.0f);
+
+       SOCKET_OUT_COLOR(image, "Image");
+
+       return type;
+}
+
 CombineRGBNode::CombineRGBNode()
 CombineRGBNode::CombineRGBNode()
-: ShaderNode("combine_rgb")
+: ShaderNode(node_type)
+{
+}
+
+void CombineRGBNode::constant_fold(const ConstantFolder& folder)
 {
 {
-       add_input("R", SHADER_SOCKET_FLOAT);
-       add_input("G", SHADER_SOCKET_FLOAT);
-       add_input("B", SHADER_SOCKET_FLOAT);
-       add_output("Image", SHADER_SOCKET_COLOR);
+       if(folder.all_inputs_constant()) {
+               folder.make_constant(make_float3(r, g, b));
+       }
 }
 
 void CombineRGBNode::compile(SVMCompiler& compiler)
 }
 
 void CombineRGBNode::compile(SVMCompiler& compiler)
@@ -3411,16 +3776,17 @@ void CombineRGBNode::compile(SVMCompiler& compiler)
        ShaderInput *blue_in = input("B");
        ShaderOutput *color_out = output("Image");
 
        ShaderInput *blue_in = input("B");
        ShaderOutput *color_out = output("Image");
 
-       compiler.stack_assign(color_out);
-
-       compiler.stack_assign(red_in);
-       compiler.add_node(NODE_COMBINE_VECTOR, red_in->stack_offset, 0, color_out->stack_offset);
+       compiler.add_node(NODE_COMBINE_VECTOR,
+               compiler.stack_assign(red_in), 0,
+               compiler.stack_assign(color_out));
 
 
-       compiler.stack_assign(green_in);
-       compiler.add_node(NODE_COMBINE_VECTOR, green_in->stack_offset, 1, color_out->stack_offset);
+       compiler.add_node(NODE_COMBINE_VECTOR,
+               compiler.stack_assign(green_in), 1,
+               compiler.stack_assign(color_out));
 
 
-       compiler.stack_assign(blue_in);
-       compiler.add_node(NODE_COMBINE_VECTOR, blue_in->stack_offset, 2, color_out->stack_offset);
+       compiler.add_node(NODE_COMBINE_VECTOR,
+               compiler.stack_assign(blue_in), 2,
+               compiler.stack_assign(color_out));
 }
 
 void CombineRGBNode::compile(OSLCompiler& compiler)
 }
 
 void CombineRGBNode::compile(OSLCompiler& compiler)
@@ -3429,13 +3795,30 @@ void CombineRGBNode::compile(OSLCompiler& compiler)
 }
 
 /* Combine XYZ */
 }
 
 /* Combine XYZ */
+
+NODE_DEFINE(CombineXYZNode)
+{
+       NodeType* type = NodeType::add("combine_xyz", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(x, "X", 0.0f);
+       SOCKET_IN_FLOAT(y, "Y", 0.0f);
+       SOCKET_IN_FLOAT(z, "Z", 0.0f);
+
+       SOCKET_OUT_VECTOR(vector, "Vector");
+
+       return type;
+}
+
 CombineXYZNode::CombineXYZNode()
 CombineXYZNode::CombineXYZNode()
-: ShaderNode("combine_xyz")
+: ShaderNode(node_type)
 {
 {
-       add_input("X", SHADER_SOCKET_FLOAT);
-       add_input("Y", SHADER_SOCKET_FLOAT);
-       add_input("Z", SHADER_SOCKET_FLOAT);
-       add_output("Vector", SHADER_SOCKET_VECTOR);
+}
+
+void CombineXYZNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               folder.make_constant(make_float3(x, y, z));
+       }
 }
 
 void CombineXYZNode::compile(SVMCompiler& compiler)
 }
 
 void CombineXYZNode::compile(SVMCompiler& compiler)
@@ -3445,16 +3828,17 @@ void CombineXYZNode::compile(SVMCompiler& compiler)
        ShaderInput *z_in = input("Z");
        ShaderOutput *vector_out = output("Vector");
 
        ShaderInput *z_in = input("Z");
        ShaderOutput *vector_out = output("Vector");
 
-       compiler.stack_assign(vector_out);
-
-       compiler.stack_assign(x_in);
-       compiler.add_node(NODE_COMBINE_VECTOR, x_in->stack_offset, 0, vector_out->stack_offset);
+       compiler.add_node(NODE_COMBINE_VECTOR,
+               compiler.stack_assign(x_in), 0,
+               compiler.stack_assign(vector_out));
 
 
-       compiler.stack_assign(y_in);
-       compiler.add_node(NODE_COMBINE_VECTOR, y_in->stack_offset, 1, vector_out->stack_offset);
+       compiler.add_node(NODE_COMBINE_VECTOR,
+               compiler.stack_assign(y_in), 1,
+               compiler.stack_assign(vector_out));
 
 
-       compiler.stack_assign(z_in);
-       compiler.add_node(NODE_COMBINE_VECTOR, z_in->stack_offset, 2, vector_out->stack_offset);
+       compiler.add_node(NODE_COMBINE_VECTOR,
+               compiler.stack_assign(z_in), 2,
+               compiler.stack_assign(vector_out));
 }
 
 void CombineXYZNode::compile(OSLCompiler& compiler)
 }
 
 void CombineXYZNode::compile(OSLCompiler& compiler)
@@ -3463,13 +3847,30 @@ void CombineXYZNode::compile(OSLCompiler& compiler)
 }
 
 /* Combine HSV */
 }
 
 /* Combine HSV */
+
+NODE_DEFINE(CombineHSVNode)
+{
+       NodeType* type = NodeType::add("combine_hsv", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(h, "H", 0.0f);
+       SOCKET_IN_FLOAT(s, "S", 0.0f);
+       SOCKET_IN_FLOAT(v, "V", 0.0f);
+
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
+
 CombineHSVNode::CombineHSVNode()
 CombineHSVNode::CombineHSVNode()
-: ShaderNode("combine_hsv")
+: ShaderNode(node_type)
 {
 {
-       add_input("H", SHADER_SOCKET_FLOAT);
-       add_input("S", SHADER_SOCKET_FLOAT);
-       add_input("V", SHADER_SOCKET_FLOAT);
-       add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+void CombineHSVNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
+       }
 }
 
 void CombineHSVNode::compile(SVMCompiler& compiler)
 }
 
 void CombineHSVNode::compile(SVMCompiler& compiler)
@@ -3479,13 +3880,12 @@ void CombineHSVNode::compile(SVMCompiler& compiler)
        ShaderInput *value_in = input("V");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *value_in = input("V");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(color_out);
-       compiler.stack_assign(hue_in);
-       compiler.stack_assign(saturation_in);
-       compiler.stack_assign(value_in);
-       
-       compiler.add_node(NODE_COMBINE_HSV, hue_in->stack_offset, saturation_in->stack_offset, value_in->stack_offset);
-       compiler.add_node(NODE_COMBINE_HSV, color_out->stack_offset);
+       compiler.add_node(NODE_COMBINE_HSV,
+               compiler.stack_assign(hue_in),
+               compiler.stack_assign(saturation_in),
+               compiler.stack_assign(value_in));
+       compiler.add_node(NODE_COMBINE_HSV,
+               compiler.stack_assign(color_out));
 }
 
 void CombineHSVNode::compile(OSLCompiler& compiler)
 }
 
 void CombineHSVNode::compile(OSLCompiler& compiler)
@@ -3494,12 +3894,28 @@ void CombineHSVNode::compile(OSLCompiler& compiler)
 }
 
 /* Gamma */
 }
 
 /* Gamma */
+
+NODE_DEFINE(GammaNode)
+{
+       NodeType* type = NodeType::add("gamma", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f);
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
+
 GammaNode::GammaNode()
 GammaNode::GammaNode()
-: ShaderNode("gamma")
+: ShaderNode(node_type)
 {
 {
-       add_input("Color", SHADER_SOCKET_COLOR);
-       add_input("Gamma", SHADER_SOCKET_FLOAT);
-       add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+void GammaNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               folder.make_constant(svm_math_gamma_color(color, gamma));
+       }
 }
 
 void GammaNode::compile(SVMCompiler& compiler)
 }
 
 void GammaNode::compile(SVMCompiler& compiler)
@@ -3508,11 +3924,10 @@ void GammaNode::compile(SVMCompiler& compiler)
        ShaderInput *gamma_in = input("Gamma");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *gamma_in = input("Gamma");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(color_in);
-       compiler.stack_assign(gamma_in);
-       compiler.stack_assign(color_out);
-
-       compiler.add_node(NODE_GAMMA, gamma_in->stack_offset, color_in->stack_offset, color_out->stack_offset);
+       compiler.add_node(NODE_GAMMA,
+               compiler.stack_assign(gamma_in),
+               compiler.stack_assign(color_in),
+               compiler.stack_assign(color_out));
 }
 
 void GammaNode::compile(OSLCompiler& compiler)
 }
 
 void GammaNode::compile(OSLCompiler& compiler)
@@ -3521,13 +3936,30 @@ void GammaNode::compile(OSLCompiler& compiler)
 }
 
 /* Bright Contrast */
 }
 
 /* Bright Contrast */
+
+NODE_DEFINE(BrightContrastNode)
+{
+       NodeType* type = NodeType::add("brightness_contrast", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_FLOAT(bright, "Bright", 0.0f);
+       SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f);
+
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
+
 BrightContrastNode::BrightContrastNode()
 BrightContrastNode::BrightContrastNode()
-: ShaderNode("brightness")
+: ShaderNode(node_type)
 {
 {
-       add_input("Color", SHADER_SOCKET_COLOR);
-       add_input("Bright", SHADER_SOCKET_FLOAT);
-       add_input("Contrast", SHADER_SOCKET_FLOAT);
-       add_output("Color", SHADER_SOCKET_COLOR);
+}
+
+void BrightContrastNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               folder.make_constant(svm_brightness_contrast(color, bright, contrast));
+       }
 }
 
 void BrightContrastNode::compile(SVMCompiler& compiler)
 }
 
 void BrightContrastNode::compile(SVMCompiler& compiler)
@@ -3537,14 +3969,12 @@ void BrightContrastNode::compile(SVMCompiler& compiler)
        ShaderInput *contrast_in = input("Contrast");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *contrast_in = input("Contrast");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(color_in);
-       compiler.stack_assign(bright_in);
-       compiler.stack_assign(contrast_in);
-       compiler.stack_assign(color_out);
-
        compiler.add_node(NODE_BRIGHTCONTRAST,
        compiler.add_node(NODE_BRIGHTCONTRAST,
-               color_in->stack_offset, color_out->stack_offset,
-               compiler.encode_uchar4(bright_in->stack_offset, contrast_in->stack_offset));
+               compiler.stack_assign(color_in),
+               compiler.stack_assign(color_out),
+               compiler.encode_uchar4(
+                       compiler.stack_assign(bright_in),
+                       compiler.stack_assign(contrast_in)));
 }
 
 void BrightContrastNode::compile(OSLCompiler& compiler)
 }
 
 void BrightContrastNode::compile(OSLCompiler& compiler)
@@ -3553,13 +3983,35 @@ void BrightContrastNode::compile(OSLCompiler& compiler)
 }
 
 /* Separate RGB */
 }
 
 /* Separate RGB */
+
+NODE_DEFINE(SeparateRGBNode)
+{
+       NodeType* type = NodeType::add("separate_rgb", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_OUT_FLOAT(g, "R");
+       SOCKET_OUT_FLOAT(g, "G");
+       SOCKET_OUT_FLOAT(b, "B");
+
+       return type;
+}
+
 SeparateRGBNode::SeparateRGBNode()
 SeparateRGBNode::SeparateRGBNode()
-: ShaderNode("separate_rgb")
+: ShaderNode(node_type)
 {
 {
-       add_input("Image", SHADER_SOCKET_COLOR);
-       add_output("R", SHADER_SOCKET_FLOAT);
-       add_output("G", SHADER_SOCKET_FLOAT);
-       add_output("B", SHADER_SOCKET_FLOAT);
+}
+
+void SeparateRGBNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               for(int channel = 0; channel < 3; channel++) {
+                       if(outputs[channel] == folder.output) {
+                               folder.make_constant(color[channel]);
+                               return;
+                       }
+               }
+       }
 }
 
 void SeparateRGBNode::compile(SVMCompiler& compiler)
 }
 
 void SeparateRGBNode::compile(SVMCompiler& compiler)
@@ -3569,16 +4021,17 @@ void SeparateRGBNode::compile(SVMCompiler& compiler)
        ShaderOutput *green_out = output("G");
        ShaderOutput *blue_out = output("B");
 
        ShaderOutput *green_out = output("G");
        ShaderOutput *blue_out = output("B");
 
-       compiler.stack_assign(color_in);
-
-       compiler.stack_assign(red_out);
-       compiler.add_node(NODE_SEPARATE_VECTOR, color_in->stack_offset, 0, red_out->stack_offset);
+       compiler.add_node(NODE_SEPARATE_VECTOR,
+               compiler.stack_assign(color_in), 0,
+               compiler.stack_assign(red_out));
 
 
-       compiler.stack_assign(green_out);
-       compiler.add_node(NODE_SEPARATE_VECTOR, color_in->stack_offset, 1, green_out->stack_offset);
+       compiler.add_node(NODE_SEPARATE_VECTOR,
+               compiler.stack_assign(color_in), 1,
+               compiler.stack_assign(green_out));
 
 
-       compiler.stack_assign(blue_out);
-       compiler.add_node(NODE_SEPARATE_VECTOR, color_in->stack_offset, 2, blue_out->stack_offset);
+       compiler.add_node(NODE_SEPARATE_VECTOR,
+               compiler.stack_assign(color_in), 2,
+               compiler.stack_assign(blue_out));
 }
 
 void SeparateRGBNode::compile(OSLCompiler& compiler)
 }
 
 void SeparateRGBNode::compile(OSLCompiler& compiler)
@@ -3587,13 +4040,35 @@ void SeparateRGBNode::compile(OSLCompiler& compiler)
 }
 
 /* Separate XYZ */
 }
 
 /* Separate XYZ */
+
+NODE_DEFINE(SeparateXYZNode)
+{
+       NodeType* type = NodeType::add("separate_xyz", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_OUT_FLOAT(x, "X");
+       SOCKET_OUT_FLOAT(y, "Y");
+       SOCKET_OUT_FLOAT(z, "Z");
+
+       return type;
+}
+
 SeparateXYZNode::SeparateXYZNode()
 SeparateXYZNode::SeparateXYZNode()
-: ShaderNode("separate_xyz")
+: ShaderNode(node_type)
 {
 {
-       add_input("Vector", SHADER_SOCKET_VECTOR);
-       add_output("X", SHADER_SOCKET_FLOAT);
-       add_output("Y", SHADER_SOCKET_FLOAT);
-       add_output("Z", SHADER_SOCKET_FLOAT);
+}
+
+void SeparateXYZNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               for(int channel = 0; channel < 3; channel++) {
+                       if(outputs[channel] == folder.output) {
+                               folder.make_constant(vector[channel]);
+                               return;
+                       }
+               }
+       }
 }
 
 void SeparateXYZNode::compile(SVMCompiler& compiler)
 }
 
 void SeparateXYZNode::compile(SVMCompiler& compiler)
@@ -3603,16 +4078,17 @@ void SeparateXYZNode::compile(SVMCompiler& compiler)
        ShaderOutput *y_out = output("Y");
        ShaderOutput *z_out = output("Z");
 
        ShaderOutput *y_out = output("Y");
        ShaderOutput *z_out = output("Z");
 
-       compiler.stack_assign(vector_in);
+       compiler.add_node(NODE_SEPARATE_VECTOR,
+               compiler.stack_assign(vector_in), 0,
+               compiler.stack_assign(x_out));
 
 
-       compiler.stack_assign(x_out);
-       compiler.add_node(NODE_SEPARATE_VECTOR, vector_in->stack_offset, 0, x_out->stack_offset);
+       compiler.add_node(NODE_SEPARATE_VECTOR,
+               compiler.stack_assign(vector_in), 1,
+               compiler.stack_assign(y_out));
 
 
-       compiler.stack_assign(y_out);
-       compiler.add_node(NODE_SEPARATE_VECTOR, vector_in->stack_offset, 1, y_out->stack_offset);
-
-       compiler.stack_assign(z_out);
-       compiler.add_node(NODE_SEPARATE_VECTOR, vector_in->stack_offset, 2, z_out->stack_offset);
+       compiler.add_node(NODE_SEPARATE_VECTOR,
+               compiler.stack_assign(vector_in), 2,
+               compiler.stack_assign(z_out));
 }
 
 void SeparateXYZNode::compile(OSLCompiler& compiler)
 }
 
 void SeparateXYZNode::compile(OSLCompiler& compiler)
@@ -3621,13 +4097,37 @@ void SeparateXYZNode::compile(OSLCompiler& compiler)
 }
 
 /* Separate HSV */
 }
 
 /* Separate HSV */
+
+NODE_DEFINE(SeparateHSVNode)
+{
+       NodeType* type = NodeType::add("separate_hsv", create, NodeType::SHADER);
+
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_OUT_FLOAT(h, "H");
+       SOCKET_OUT_FLOAT(s, "S");
+       SOCKET_OUT_FLOAT(v, "V");
+
+       return type;
+}
+
 SeparateHSVNode::SeparateHSVNode()
 SeparateHSVNode::SeparateHSVNode()
-: ShaderNode("separate_hsv")
+: ShaderNode(node_type)
 {
 {
-       add_input("Color", SHADER_SOCKET_COLOR);
-       add_output("H", SHADER_SOCKET_FLOAT);
-       add_output("S", SHADER_SOCKET_FLOAT);
-       add_output("V", SHADER_SOCKET_FLOAT);
+}
+
+void SeparateHSVNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               float3 hsv = rgb_to_hsv(color);
+
+               for(int channel = 0; channel < 3; channel++) {
+                       if(outputs[channel] == folder.output) {
+                               folder.make_constant(hsv[channel]);
+                               return;
+                       }
+               }
+       }
 }
 
 void SeparateHSVNode::compile(SVMCompiler& compiler)
 }
 
 void SeparateHSVNode::compile(SVMCompiler& compiler)
@@ -3637,14 +4137,12 @@ void SeparateHSVNode::compile(SVMCompiler& compiler)
        ShaderOutput *saturation_out = output("S");
        ShaderOutput *value_out = output("V");
 
        ShaderOutput *saturation_out = output("S");
        ShaderOutput *value_out = output("V");
 
-       compiler.stack_assign(color_in);
-       compiler.stack_assign(hue_out);
-       compiler.stack_assign(saturation_out);
-       compiler.stack_assign(value_out);
-       
-       compiler.add_node(NODE_SEPARATE_HSV, color_in->stack_offset, hue_out->stack_offset, saturation_out->stack_offset);
-       compiler.add_node(NODE_SEPARATE_HSV, value_out->stack_offset);
-
+       compiler.add_node(NODE_SEPARATE_HSV,
+               compiler.stack_assign(color_in),
+               compiler.stack_assign(hue_out),
+               compiler.stack_assign(saturation_out));
+       compiler.add_node(NODE_SEPARATE_HSV,
+               compiler.stack_assign(value_out));
 }
 
 void SeparateHSVNode::compile(OSLCompiler& compiler)
 }
 
 void SeparateHSVNode::compile(OSLCompiler& compiler)
@@ -3653,15 +4151,25 @@ void SeparateHSVNode::compile(OSLCompiler& compiler)
 }
 
 /* Hue Saturation Value */
 }
 
 /* Hue Saturation Value */
+
+NODE_DEFINE(HSVNode)
+{
+       NodeType* type = NodeType::add("hsv", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(hue, "Hue", 0.5f);
+       SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f);
+       SOCKET_IN_FLOAT(value, "Value", 1.0f);
+       SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
+
 HSVNode::HSVNode()
 HSVNode::HSVNode()
-: ShaderNode("hsv")
+: ShaderNode(node_type)
 {
 {
-       add_input("Hue", SHADER_SOCKET_FLOAT);
-       add_input("Saturation", SHADER_SOCKET_FLOAT);
-       add_input("Value", SHADER_SOCKET_FLOAT);
-       add_input("Fac", SHADER_SOCKET_FLOAT);
-       add_input("Color", SHADER_SOCKET_COLOR);
-       add_output("Color", SHADER_SOCKET_COLOR);
 }
 
 void HSVNode::compile(SVMCompiler& compiler)
 }
 
 void HSVNode::compile(SVMCompiler& compiler)
@@ -3673,15 +4181,15 @@ void HSVNode::compile(SVMCompiler& compiler)
        ShaderInput *color_in = input("Color");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *color_in = input("Color");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(hue_in);
-       compiler.stack_assign(saturation_in);
-       compiler.stack_assign(value_in);
-       compiler.stack_assign(fac_in);
-       compiler.stack_assign(color_in);
-       compiler.stack_assign(color_out);
-
-       compiler.add_node(NODE_HSV, color_in->stack_offset, fac_in->stack_offset, color_out->stack_offset);
-       compiler.add_node(NODE_HSV, hue_in->stack_offset, saturation_in->stack_offset, value_in->stack_offset);
+       compiler.add_node(NODE_HSV,
+               compiler.encode_uchar4(
+                       compiler.stack_assign(color_in),
+                       compiler.stack_assign(fac_in),
+                       compiler.stack_assign(color_out)),
+               compiler.encode_uchar4(
+                       compiler.stack_assign(hue_in),
+                       compiler.stack_assign(saturation_in),
+                       compiler.stack_assign(value_in)));
 }
 
 void HSVNode::compile(OSLCompiler& compiler)
 }
 
 void HSVNode::compile(OSLCompiler& compiler)
@@ -3691,14 +4199,22 @@ void HSVNode::compile(OSLCompiler& compiler)
 
 /* Attribute */
 
 
 /* Attribute */
 
-AttributeNode::AttributeNode()
-: ShaderNode("attribute")
+NODE_DEFINE(AttributeNode)
 {
 {
-       attribute = "";
+       NodeType* type = NodeType::add("attribute", create, NodeType::SHADER);
+
+       SOCKET_STRING(attribute, "Attribute", ustring(""));
 
 
-       add_output("Color",  SHADER_SOCKET_COLOR);
-       add_output("Vector",  SHADER_SOCKET_VECTOR);
-       add_output("Fac",  SHADER_SOCKET_FLOAT);
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_VECTOR(vector, "Vector");
+       SOCKET_OUT_FLOAT(fac, "Fac");
+
+       return type;
+}
+
+AttributeNode::AttributeNode()
+: ShaderNode(node_type)
+{
 }
 
 void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 }
 
 void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
@@ -3727,7 +4243,7 @@ void AttributeNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *vector_out = output("Vector");
        ShaderOutput *fac_out = output("Fac");
        ShaderOutput *color_out = output("Color");
        ShaderOutput *vector_out = output("Vector");
        ShaderOutput *fac_out = output("Fac");
-       NodeType attr_node = NODE_ATTR;
+       ShaderNodeType attr_node = NODE_ATTR;
        AttributeStandard std = Attribute::name_standard(attribute.c_str());
        int attr;
 
        AttributeStandard std = Attribute::name_standard(attribute.c_str());
        int attr;
 
@@ -3743,18 +4259,15 @@ void AttributeNode::compile(SVMCompiler& compiler)
 
        if(!color_out->links.empty() || !vector_out->links.empty()) {
                if(!color_out->links.empty()) {
 
        if(!color_out->links.empty() || !vector_out->links.empty()) {
                if(!color_out->links.empty()) {
-                       compiler.stack_assign(color_out);
-                       compiler.add_node(attr_node, attr, color_out->stack_offset, NODE_ATTR_FLOAT3);
+                       compiler.add_node(attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_FLOAT3);
                }
                if(!vector_out->links.empty()) {
                }
                if(!vector_out->links.empty()) {
-                       compiler.stack_assign(vector_out);
-                       compiler.add_node(attr_node, attr, vector_out->stack_offset, NODE_ATTR_FLOAT3);
+                       compiler.add_node(attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_FLOAT3);
                }
        }
 
        if(!fac_out->links.empty()) {
                }
        }
 
        if(!fac_out->links.empty()) {
-               compiler.stack_assign(fac_out);
-               compiler.add_node(attr_node, attr, fac_out->stack_offset, NODE_ATTR_FLOAT);
+               compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), NODE_ATTR_FLOAT);
        }
 }
 
        }
 }
 
@@ -3777,12 +4290,20 @@ void AttributeNode::compile(OSLCompiler& compiler)
 
 /* Camera */
 
 
 /* Camera */
 
+NODE_DEFINE(CameraNode)
+{
+       NodeType* type = NodeType::add("camera_info", create, NodeType::SHADER);
+
+       SOCKET_OUT_VECTOR(view_vector, "View Vector");
+       SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth");
+       SOCKET_OUT_FLOAT(view_distance, "View Distance");
+
+       return type;
+}
+
 CameraNode::CameraNode()
 CameraNode::CameraNode()
-: ShaderNode("camera")
+: ShaderNode(node_type)
 {
 {
-       add_output("View Vector",  SHADER_SOCKET_VECTOR);
-       add_output("View Z Depth",  SHADER_SOCKET_FLOAT);
-       add_output("View Distance",  SHADER_SOCKET_FLOAT);
 }
 
 void CameraNode::compile(SVMCompiler& compiler)
 }
 
 void CameraNode::compile(SVMCompiler& compiler)
@@ -3791,10 +4312,10 @@ void CameraNode::compile(SVMCompiler& compiler)
        ShaderOutput *z_depth_out = output("View Z Depth");
        ShaderOutput *distance_out = output("View Distance");
 
        ShaderOutput *z_depth_out = output("View Z Depth");
        ShaderOutput *distance_out = output("View Distance");
 
-       compiler.stack_assign(vector_out);
-       compiler.stack_assign(z_depth_out);
-       compiler.stack_assign(distance_out);
-       compiler.add_node(NODE_CAMERA, vector_out->stack_offset, z_depth_out->stack_offset, distance_out->stack_offset);
+       compiler.add_node(NODE_CAMERA,
+               compiler.stack_assign(vector_out),
+               compiler.stack_assign(z_depth_out),
+               compiler.stack_assign(distance_out));
 }
 
 void CameraNode::compile(OSLCompiler& compiler)
 }
 
 void CameraNode::compile(OSLCompiler& compiler)
@@ -3804,27 +4325,35 @@ void CameraNode::compile(OSLCompiler& compiler)
 
 /* Fresnel */
 
 
 /* Fresnel */
 
+NODE_DEFINE(FresnelNode)
+{
+       NodeType* type = NodeType::add("fresnel", create, NodeType::SHADER);
+
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+       SOCKET_IN_FLOAT(IOR, "IOR", 1.45f);
+
+       SOCKET_OUT_FLOAT(fac, "Fac");
+
+       return type;
+}
+
 FresnelNode::FresnelNode()
 FresnelNode::FresnelNode()
-: ShaderNode("fresnel")
+: ShaderNode(node_type)
 {
 {
-       add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
-       add_input("IOR", SHADER_SOCKET_FLOAT, 1.45f);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
 }
 
 void FresnelNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *normal_in = input("Normal");
 }
 
 void FresnelNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *normal_in = input("Normal");
-       ShaderInput *ior_in = input("IOR");
+       ShaderInput *IOR_in = input("IOR");
        ShaderOutput *fac_out = output("Fac");
 
        ShaderOutput *fac_out = output("Fac");
 
-       compiler.stack_assign(ior_in);
-       compiler.stack_assign(fac_out);
-       
-       if(normal_in->link)
-               compiler.stack_assign(normal_in);
-       
-       compiler.add_node(NODE_FRESNEL, ior_in->stack_offset, __float_as_int(ior_in->value.x), compiler.encode_uchar4(normal_in->stack_offset, fac_out->stack_offset));
+       compiler.add_node(NODE_FRESNEL,
+               compiler.stack_assign(IOR_in),
+               __float_as_int(IOR),
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(normal_in),
+                       compiler.stack_assign(fac_out)));
 }
 
 void FresnelNode::compile(OSLCompiler& compiler)
 }
 
 void FresnelNode::compile(OSLCompiler& compiler)
@@ -3834,39 +4363,47 @@ void FresnelNode::compile(OSLCompiler& compiler)
 
 /* Layer Weight */
 
 
 /* Layer Weight */
 
-LayerWeightNode::LayerWeightNode()
-: ShaderNode("layer_weight")
+NODE_DEFINE(LayerWeightNode)
 {
 {
-       add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
-       add_input("Blend", SHADER_SOCKET_FLOAT, 0.5f);
+       NodeType* type = NodeType::add("layer_weight", create, NodeType::SHADER);
 
 
-       add_output("Fresnel", SHADER_SOCKET_FLOAT);
-       add_output("Facing", SHADER_SOCKET_FLOAT);
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+       SOCKET_IN_FLOAT(blend, "Blend", 0.5f);
+
+       SOCKET_OUT_FLOAT(fresnel, "Fresnel");
+       SOCKET_OUT_FLOAT(facing, "Facing");
+
+       return type;
+}
+
+LayerWeightNode::LayerWeightNode()
+: ShaderNode(node_type)
+{
 }
 
 void LayerWeightNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *normal_in = input("Normal");
        ShaderInput *blend_in = input("Blend");
 }
 
 void LayerWeightNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *normal_in = input("Normal");
        ShaderInput *blend_in = input("Blend");
-
-       if(normal_in->link)
-               compiler.stack_assign(normal_in);
-
-       if(blend_in->link)
-               compiler.stack_assign(blend_in);
-
        ShaderOutput *fresnel_out = output("Fresnel");
        ShaderOutput *fresnel_out = output("Fresnel");
+       ShaderOutput *facing_out = output("Facing");
+
        if(!fresnel_out->links.empty()) {
        if(!fresnel_out->links.empty()) {
-               compiler.stack_assign(fresnel_out);
-               compiler.add_node(NODE_LAYER_WEIGHT, blend_in->stack_offset, __float_as_int(blend_in->value.x),
-                       compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL, normal_in->stack_offset, fresnel_out->stack_offset));
+               compiler.add_node(NODE_LAYER_WEIGHT,
+                       compiler.stack_assign_if_linked(blend_in),
+                       __float_as_int(blend),
+                       compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
+                                              compiler.stack_assign_if_linked(normal_in),
+                                              compiler.stack_assign(fresnel_out)));
        }
 
        }
 
-       ShaderOutput *facing_out = output("Facing");
        if(!facing_out->links.empty()) {
        if(!facing_out->links.empty()) {
-               compiler.stack_assign(facing_out);
-               compiler.add_node(NODE_LAYER_WEIGHT, blend_in->stack_offset, __float_as_int(blend_in->value.x),
-                       compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING, normal_in->stack_offset, facing_out->stack_offset));
+               compiler.add_node(NODE_LAYER_WEIGHT,
+                       compiler.stack_assign_if_linked(blend_in),
+                       __float_as_int(blend),
+                       compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
+                                              compiler.stack_assign_if_linked(normal_in),
+                                              compiler.stack_assign(facing_out)));
        }
 }
 
        }
 }
 
@@ -3877,13 +4414,20 @@ void LayerWeightNode::compile(OSLCompiler& compiler)
 
 /* Wireframe */
 
 
 /* Wireframe */
 
+NODE_DEFINE(WireframeNode)
+{
+       NodeType* type = NodeType::add("wireframe", create, NodeType::SHADER);
+
+       SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false);
+       SOCKET_IN_FLOAT(size, "Size", 0.01f);
+       SOCKET_OUT_FLOAT(fac, "Fac");
+
+       return type;
+}
+
 WireframeNode::WireframeNode()
 WireframeNode::WireframeNode()
-: ShaderNode("wireframe")
+: ShaderNode(node_type)
 {
 {
-       add_input("Size", SHADER_SOCKET_FLOAT, 0.01f);
-       add_output("Fac", SHADER_SOCKET_FLOAT);
-       
-       use_pixel_size = false;
 }
 
 void WireframeNode::compile(SVMCompiler& compiler)
 }
 
 void WireframeNode::compile(SVMCompiler& compiler)
@@ -3897,11 +4441,9 @@ void WireframeNode::compile(SVMCompiler& compiler)
        else if(bump == SHADER_BUMP_DY) {
                bump_offset = NODE_BUMP_OFFSET_DY;
        }
        else if(bump == SHADER_BUMP_DY) {
                bump_offset = NODE_BUMP_OFFSET_DY;
        }
-       compiler.stack_assign(size_in);
-       compiler.stack_assign(fac_out);
        compiler.add_node(NODE_WIREFRAME,
        compiler.add_node(NODE_WIREFRAME,
-                         size_in->stack_offset,
-                         fac_out->stack_offset,
+                         compiler.stack_assign(size_in),
+                         compiler.stack_assign(fac_out),
                          compiler.encode_uchar4(use_pixel_size,
                                                 bump_offset,
                                                 0, 0));
                          compiler.encode_uchar4(use_pixel_size,
                                                 bump_offset,
                                                 0, 0));
@@ -3918,17 +4460,25 @@ void WireframeNode::compile(OSLCompiler& compiler)
        else {
                compiler.parameter("bump_offset", "center");
        }
        else {
                compiler.parameter("bump_offset", "center");
        }
-       compiler.parameter("use_pixel_size", use_pixel_size);
+       compiler.parameter(this, "use_pixel_size");
        compiler.add(this, "node_wireframe");
 }
 
 /* Wavelength */
 
        compiler.add(this, "node_wireframe");
 }
 
 /* Wavelength */
 
+NODE_DEFINE(WavelengthNode)
+{
+       NodeType* type = NodeType::add("wavelength", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
+}
+
 WavelengthNode::WavelengthNode()
 WavelengthNode::WavelengthNode()
-: ShaderNode("wavelength")
+: ShaderNode(node_type)
 {
 {
-       add_input("Wavelength", SHADER_SOCKET_FLOAT, 500.0f);
-       add_output("Color", SHADER_SOCKET_COLOR);
 }
 
 void WavelengthNode::compile(SVMCompiler& compiler)
 }
 
 void WavelengthNode::compile(SVMCompiler& compiler)
@@ -3936,9 +4486,9 @@ void WavelengthNode::compile(SVMCompiler& compiler)
        ShaderInput *wavelength_in = input("Wavelength");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *wavelength_in = input("Wavelength");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(wavelength_in);
-       compiler.stack_assign(color_out);
-       compiler.add_node(NODE_WAVELENGTH, wavelength_in->stack_offset, color_out->stack_offset);
+       compiler.add_node(NODE_WAVELENGTH,
+               compiler.stack_assign(wavelength_in),
+               compiler.stack_assign(color_out));
 }
 
 void WavelengthNode::compile(OSLCompiler& compiler)
 }
 
 void WavelengthNode::compile(OSLCompiler& compiler)
@@ -3948,26 +4498,26 @@ void WavelengthNode::compile(OSLCompiler& compiler)
 
 /* Blackbody */
 
 
 /* Blackbody */
 
-BlackbodyNode::BlackbodyNode()
-: ShaderNode("blackbody")
+NODE_DEFINE(BlackbodyNode)
 {
 {
-       add_input("Temperature", SHADER_SOCKET_FLOAT, 1200.0f);
-       add_output("Color", SHADER_SOCKET_COLOR);
+       NodeType* type = NodeType::add("blackbody", create, NodeType::SHADER);
+
+       SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
+       SOCKET_OUT_COLOR(color, "Color");
+
+       return type;
 }
 
 }
 
-bool BlackbodyNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+BlackbodyNode::BlackbodyNode()
+: ShaderNode(node_type)
 {
 {
-       ShaderInput *temperature_in = input("Temperature");
-
-       if(socket == output("Color")) {
-               if(temperature_in->link == NULL) {
-                       *optimized_value = svm_math_blackbody_color(temperature_in->value.x);
+}
 
 
-                       return true;
-               }
+void BlackbodyNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               folder.make_constant(svm_math_blackbody_color(temperature));
        }
        }
-
-       return false;
 }
 
 void BlackbodyNode::compile(SVMCompiler& compiler)
 }
 
 void BlackbodyNode::compile(SVMCompiler& compiler)
@@ -3975,10 +4525,9 @@ void BlackbodyNode::compile(SVMCompiler& compiler)
        ShaderInput *temperature_in = input("Temperature");
        ShaderOutput *color_out = output("Color");
 
        ShaderInput *temperature_in = input("Temperature");
        ShaderOutput *color_out = output("Color");
 
-       compiler.stack_assign(color_out);
-
-       compiler.stack_assign(temperature_in);
-       compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset);
+       compiler.add_node(NODE_BLACKBODY,
+               compiler.stack_assign(temperature_in),
+               compiler.stack_assign(color_out));
 }
 
 void BlackbodyNode::compile(OSLCompiler& compiler)
 }
 
 void BlackbodyNode::compile(OSLCompiler& compiler)
@@ -3988,13 +4537,22 @@ void BlackbodyNode::compile(OSLCompiler& compiler)
 
 /* Output */
 
 
 /* Output */
 
+NODE_DEFINE(OutputNode)
+{
+       NodeType* type = NodeType::add("output", create, NodeType::SHADER);
+
+       SOCKET_IN_CLOSURE(surface, "Surface");
+       SOCKET_IN_CLOSURE(volume, "Volume");
+       SOCKET_IN_FLOAT(displacement, "Displacement", 0.0f);
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
+
+       return type;
+}
+
 OutputNode::OutputNode()
 OutputNode::OutputNode()
-: ShaderNode("output")
+: ShaderNode(node_type)
 {
 {
-       add_input("Surface", SHADER_SOCKET_CLOSURE);
-       add_input("Volume", SHADER_SOCKET_CLOSURE);
-       add_input("Displacement", SHADER_SOCKET_FLOAT);
-       add_input("Normal", SHADER_SOCKET_NORMAL);
+       special_type = SHADER_SPECIAL_TYPE_OUTPUT;
 }
 
 void OutputNode::compile(SVMCompiler& compiler)
 }
 
 void OutputNode::compile(SVMCompiler& compiler)
@@ -4003,8 +4561,7 @@ void OutputNode::compile(SVMCompiler& compiler)
                ShaderInput *displacement_in = input("Displacement");
 
                if(displacement_in->link) {
                ShaderInput *displacement_in = input("Displacement");
 
                if(displacement_in->link) {
-                       compiler.stack_assign(displacement_in);
-                       compiler.add_node(NODE_SET_DISPLACEMENT, displacement_in->stack_offset);
+                       compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in));
                }
        }
 }
                }
        }
 }
@@ -4021,68 +4578,52 @@ void OutputNode::compile(OSLCompiler& compiler)
 
 /* Math */
 
 
 /* Math */
 
-MathNode::MathNode()
-: ShaderNode("math")
+NODE_DEFINE(MathNode)
 {
 {
-       type = ustring("Add");
+       NodeType* type = NodeType::add("math", create, NodeType::SHADER);
 
 
-       use_clamp = false;
+       static NodeEnum type_enum;
+       type_enum.insert("add", NODE_MATH_ADD);
+       type_enum.insert("subtract", NODE_MATH_SUBTRACT);
+       type_enum.insert("multiply", NODE_MATH_MULTIPLY);
+       type_enum.insert("divide", NODE_MATH_DIVIDE);
+       type_enum.insert("sine", NODE_MATH_SINE);
+       type_enum.insert("cosine", NODE_MATH_COSINE);
+       type_enum.insert("tangent", NODE_MATH_TANGENT);
+       type_enum.insert("arcsine", NODE_MATH_ARCSINE);
+       type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
+       type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
+       type_enum.insert("power", NODE_MATH_POWER);
+       type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
+       type_enum.insert("minimum", NODE_MATH_MINIMUM);
+       type_enum.insert("maximum", NODE_MATH_MAXIMUM);
+       type_enum.insert("round", NODE_MATH_ROUND);
+       type_enum.insert("less_than", NODE_MATH_LESS_THAN);
+       type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
+       type_enum.insert("modulo", NODE_MATH_MODULO);
+       type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
 
 
-       add_input("Value1", SHADER_SOCKET_FLOAT);
-       add_input("Value2", SHADER_SOCKET_FLOAT);
-       add_output("Value",  SHADER_SOCKET_FLOAT);
-}
+       SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
 
 
-static ShaderEnum math_type_init()
-{
-       ShaderEnum enm;
+       SOCKET_IN_FLOAT(value1, "Value1", 0.0f);
+       SOCKET_IN_FLOAT(value2, "Value2", 0.0f);
 
 
-       enm.insert("Add", NODE_MATH_ADD);
-       enm.insert("Subtract", NODE_MATH_SUBTRACT);
-       enm.insert("Multiply", NODE_MATH_MULTIPLY);
-       enm.insert("Divide", NODE_MATH_DIVIDE);
-       enm.insert("Sine", NODE_MATH_SINE);
-       enm.insert("Cosine", NODE_MATH_COSINE);
-       enm.insert("Tangent", NODE_MATH_TANGENT);
-       enm.insert("Arcsine", NODE_MATH_ARCSINE);
-       enm.insert("Arccosine", NODE_MATH_ARCCOSINE);
-       enm.insert("Arctangent", NODE_MATH_ARCTANGENT);
-       enm.insert("Power", NODE_MATH_POWER);
-       enm.insert("Logarithm", NODE_MATH_LOGARITHM);
-       enm.insert("Minimum", NODE_MATH_MINIMUM);
-       enm.insert("Maximum", NODE_MATH_MAXIMUM);
-       enm.insert("Round", NODE_MATH_ROUND);
-       enm.insert("Less Than", NODE_MATH_LESS_THAN);
-       enm.insert("Greater Than", NODE_MATH_GREATER_THAN);
-       enm.insert("Modulo", NODE_MATH_MODULO);
-       enm.insert("Absolute", NODE_MATH_ABSOLUTE);
+       SOCKET_OUT_FLOAT(value, "Value");
 
 
-       return enm;
+       return type;
 }
 
 }
 
-ShaderEnum MathNode::type_enum = math_type_init();
-
-bool MathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+MathNode::MathNode()
+: ShaderNode(node_type)
 {
 {
-       ShaderInput *value1_in = input("Value1");
-       ShaderInput *value2_in = input("Value2");
-
-       if(socket == output("Value")) {
-               /* Optimize math node without links to a single value. */
-               if(value1_in->link == NULL && value2_in->link == NULL) {
-                       optimized_value->x = svm_math((NodeMath)type_enum[type],
-                                                     value1_in->value.x,
-                                                     value2_in->value.x);
-
-                       if(use_clamp) {
-                               optimized_value->x = saturate(optimized_value->x);
-                       }
+}
 
 
-                       return true;
-               }
+void MathNode::constant_fold(const ConstantFolder& folder)
+{
+       if(folder.all_inputs_constant()) {
+               folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp);
        }
        }
-
-       return false;
 }
 
 void MathNode::compile(SVMCompiler& compiler)
 }
 
 void MathNode::compile(SVMCompiler& compiler)
@@ -4091,82 +4632,70 @@ void MathNode::compile(SVMCompiler& compiler)
        ShaderInput *value2_in = input("Value2");
        ShaderOutput *value_out = output("Value");
 
        ShaderInput *value2_in = input("Value2");
        ShaderOutput *value_out = output("Value");
 
-       compiler.stack_assign(value_out);
-       compiler.stack_assign(value1_in);
-       compiler.stack_assign(value2_in);
-
-       compiler.add_node(NODE_MATH, type_enum[type], value1_in->stack_offset, value2_in->stack_offset);
-       compiler.add_node(NODE_MATH, value_out->stack_offset);
+       compiler.add_node(NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in));
+       compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
 
        if(use_clamp) {
 
        if(use_clamp) {
-               compiler.add_node(NODE_MATH, NODE_MATH_CLAMP, value_out->stack_offset);
-               compiler.add_node(NODE_MATH, value_out->stack_offset);
+               compiler.add_node(NODE_MATH, NODE_MATH_CLAMP, compiler.stack_assign(value_out));
+               compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
        }
 }
 
 void MathNode::compile(OSLCompiler& compiler)
 {
        }
 }
 
 void MathNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("type", type);
-       compiler.parameter("Clamp", use_clamp);
+       compiler.parameter(this, "type");
+       compiler.parameter(this, "use_clamp");
        compiler.add(this, "node_math");
 }
 
 /* VectorMath */
 
        compiler.add(this, "node_math");
 }
 
 /* VectorMath */
 
-VectorMathNode::VectorMathNode()
-: ShaderNode("vector_math")
+NODE_DEFINE(VectorMathNode)
 {
 {
-       type = ustring("Add");
+       NodeType* type = NodeType::add("vector_math", create, NodeType::SHADER);
 
 
-       add_input("Vector1", SHADER_SOCKET_VECTOR);
-       add_input("Vector2", SHADER_SOCKET_VECTOR);
-       add_output("Value",  SHADER_SOCKET_FLOAT);
-       add_output("Vector",  SHADER_SOCKET_VECTOR);
-}
+       static NodeEnum type_enum;
+       type_enum.insert("add", NODE_VECTOR_MATH_ADD);
+       type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
+       type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE);
+       type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
+       type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
+       type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
 
 
-static ShaderEnum vector_math_type_init()
-{
-       ShaderEnum enm;
+       SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f));
 
 
-       enm.insert("Add", NODE_VECTOR_MATH_ADD);
-       enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT);
-       enm.insert("Average", NODE_VECTOR_MATH_AVERAGE);
-       enm.insert("Dot Product", NODE_VECTOR_MATH_DOT_PRODUCT);
-       enm.insert("Cross Product", NODE_VECTOR_MATH_CROSS_PRODUCT);
-       enm.insert("Normalize", NODE_VECTOR_MATH_NORMALIZE);
+       SOCKET_OUT_FLOAT(value, "Value");
+       SOCKET_OUT_VECTOR(vector, "Vector");
 
 
-       return enm;
+       return type;
 }
 
 }
 
-ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
-
-bool VectorMathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+VectorMathNode::VectorMathNode()
+: ShaderNode(node_type)
 {
 {
-       ShaderInput *vector1_in = input("Vector1");
-       ShaderInput *vector2_in = input("Vector2");
+}
 
 
+void VectorMathNode::constant_fold(const ConstantFolder& folder)
+{
        float value;
        float3 vector;
 
        float value;
        float3 vector;
 
-       /* Optimize vector math node without links to a single value node. */
-       if(vector1_in->link == NULL && vector2_in->link == NULL) {
+       if(folder.all_inputs_constant()) {
                svm_vector_math(&value,
                svm_vector_math(&value,
-                                               &vector,
-                                               (NodeVectorMath)type_enum[type],
-                                               vector1_in->value,
-                                               vector2_in->value);
-
-               if(socket == output("Value")) {
-                       optimized_value->x = value;
-                       return true;
+                               &vector,
+                               type,
+                               vector1,
+                               vector2);
+
+               if(folder.output == output("Value")) {
+                       folder.make_constant(value);
                }
                }
-               else if(socket == output("Vector")) {
-                       *optimized_value = vector;
-                       return true;
+               else if(folder.output == output("Vector")) {
+                       folder.make_constant(vector);
                }
        }
                }
        }
-
-       return false;
 }
 
 void VectorMathNode::compile(SVMCompiler& compiler)
 }
 
 void VectorMathNode::compile(SVMCompiler& compiler)
@@ -4176,102 +4705,98 @@ void VectorMathNode::compile(SVMCompiler& compiler)
        ShaderOutput *value_out = output("Value");
        ShaderOutput *vector_out = output("Vector");
 
        ShaderOutput *value_out = output("Value");
        ShaderOutput *vector_out = output("Vector");
 
-       compiler.stack_assign(value_out);
-       compiler.stack_assign(vector_out);
-
-       compiler.stack_assign(vector1_in);
-       compiler.stack_assign(vector2_in);
-
-       compiler.add_node(NODE_VECTOR_MATH, type_enum[type], vector1_in->stack_offset, vector2_in->stack_offset);
-       compiler.add_node(NODE_VECTOR_MATH, value_out->stack_offset, vector_out->stack_offset);
+       compiler.add_node(NODE_VECTOR_MATH,
+               type,
+               compiler.stack_assign(vector1_in),
+               compiler.stack_assign(vector2_in));
+       compiler.add_node(NODE_VECTOR_MATH,
+               compiler.stack_assign(value_out),
+               compiler.stack_assign(vector_out));
 }
 
 void VectorMathNode::compile(OSLCompiler& compiler)
 {
 }
 
 void VectorMathNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("type", type);
+       compiler.parameter(this, "type");
        compiler.add(this, "node_vector_math");
 }
 
 /* VectorTransform */
 
        compiler.add(this, "node_vector_math");
 }
 
 /* VectorTransform */
 
-VectorTransformNode::VectorTransformNode()
-: ShaderNode("vector_transform")
+NODE_DEFINE(VectorTransformNode)
 {
 {
-       type = ustring("Vector");
-       convert_from = ustring("world");
-       convert_to = ustring("object");
+       NodeType* type = NodeType::add("vector_transform", create, NodeType::SHADER);
 
 
-       add_input("Vector", SHADER_SOCKET_VECTOR);
-       add_output("Vector",  SHADER_SOCKET_VECTOR);
-}
+       static NodeEnum type_enum;
+       type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
+       type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
+       type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
+       SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
 
 
-static ShaderEnum vector_transform_type_init()
-{
-       ShaderEnum enm;
+       static NodeEnum space_enum;
+       space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
+       space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
+       space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
+       SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
+       SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
 
 
-       enm.insert("Vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
-       enm.insert("Point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
-       enm.insert("Normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
+       SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_OUT_VECTOR(vector, "Vector");
 
 
-       return enm;
+       return type;
 }
 
 }
 
-static ShaderEnum vector_transform_convert_space_init()
+VectorTransformNode::VectorTransformNode()
+: ShaderNode(node_type)
 {
 {
-       ShaderEnum enm;
-
-       enm.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
-       enm.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
-       enm.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
-
-       return enm;
 }
 
 }
 
-ShaderEnum VectorTransformNode::type_enum = vector_transform_type_init();
-ShaderEnum VectorTransformNode::convert_space_enum = vector_transform_convert_space_init();
-
 void VectorTransformNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *vector_in = input("Vector");
        ShaderOutput *vector_out = output("Vector");
 
 void VectorTransformNode::compile(SVMCompiler& compiler)
 {
        ShaderInput *vector_in = input("Vector");
        ShaderOutput *vector_out = output("Vector");
 
-       compiler.stack_assign(vector_in);
-       compiler.stack_assign(vector_out);
-
        compiler.add_node(NODE_VECTOR_TRANSFORM,
        compiler.add_node(NODE_VECTOR_TRANSFORM,
-               compiler.encode_uchar4(type_enum[type], convert_space_enum[convert_from], convert_space_enum[convert_to]),
-               compiler.encode_uchar4(vector_in->stack_offset, vector_out->stack_offset));
+               compiler.encode_uchar4(type, convert_from, convert_to),
+               compiler.encode_uchar4(compiler.stack_assign(vector_in),
+                                      compiler.stack_assign(vector_out)));
 }
 
 void VectorTransformNode::compile(OSLCompiler& compiler)
 {
 }
 
 void VectorTransformNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("type", type);
-       compiler.parameter("convert_from", convert_from);
-       compiler.parameter("convert_to", convert_to);
+       compiler.parameter(this, "type");
+       compiler.parameter(this, "convert_from");
+       compiler.parameter(this, "convert_to");
        compiler.add(this, "node_vector_transform");
 }
 
 /* BumpNode */
 
        compiler.add(this, "node_vector_transform");
 }
 
 /* BumpNode */
 
-BumpNode::BumpNode()
-: ShaderNode("bump")
+NODE_DEFINE(BumpNode)
 {
 {
-       invert = false;
+       NodeType* type = NodeType::add("bump", create, NodeType::SHADER);
 
 
-       special_type = SHADER_SPECIAL_TYPE_BUMP;
+       SOCKET_BOOLEAN(invert, "Invert", false);
 
        /* this input is used by the user, but after graph transform it is no longer
         * used and moved to sampler center/x/y instead */
 
        /* this input is used by the user, but after graph transform it is no longer
         * used and moved to sampler center/x/y instead */
-       add_input("Height", SHADER_SOCKET_FLOAT);
+       SOCKET_IN_FLOAT(height, "Height", 1.0f);
 
 
-       add_input("SampleCenter", SHADER_SOCKET_FLOAT);
-       add_input("SampleX", SHADER_SOCKET_FLOAT);
-       add_input("SampleY", SHADER_SOCKET_FLOAT);
-       add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL);
-       add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Distance", SHADER_SOCKET_FLOAT, 0.1f);
+       SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f);
+       SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f);
+       SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f);
+       SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
+       SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+       SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
 
 
-       add_output("Normal", SHADER_SOCKET_NORMAL);
+       SOCKET_OUT_NORMAL(normal, "Normal");
+
+       return type;
+}
+
+BumpNode::BumpNode()
+: ShaderNode(node_type)
+{
+       special_type = SHADER_SPECIAL_TYPE_BUMP;
 }
 
 void BumpNode::compile(SVMCompiler& compiler)
 }
 
 void BumpNode::compile(SVMCompiler& compiler)
@@ -4284,167 +4809,289 @@ void BumpNode::compile(SVMCompiler& compiler)
        ShaderInput *distance_in = input("Distance");
        ShaderOutput *normal_out = output("Normal");
 
        ShaderInput *distance_in = input("Distance");
        ShaderOutput *normal_out = output("Normal");
 
-       compiler.stack_assign(center_in);
-       compiler.stack_assign(dx_in);
-       compiler.stack_assign(dy_in);
-       compiler.stack_assign(strength_in);
-       compiler.stack_assign(distance_in);
-       compiler.stack_assign(normal_out);
-
-       if(normal_in->link)
-               compiler.stack_assign(normal_in);
-       
        /* pack all parameters in the node */
        compiler.add_node(NODE_SET_BUMP,
        /* pack all parameters in the node */
        compiler.add_node(NODE_SET_BUMP,
-               compiler.encode_uchar4(normal_in->stack_offset, distance_in->stack_offset, invert),
-               compiler.encode_uchar4(center_in->stack_offset, dx_in->stack_offset,
-                       dy_in->stack_offset, strength_in->stack_offset),
-               normal_out->stack_offset);
+               compiler.encode_uchar4(
+                       compiler.stack_assign_if_linked(normal_in),
+                       compiler.stack_assign(distance_in),
+                       invert),
+               compiler.encode_uchar4(
+                       compiler.stack_assign(center_in),
+                       compiler.stack_assign(dx_in),
+                       compiler.stack_assign(dy_in),
+                       compiler.stack_assign(strength_in)),
+               compiler.stack_assign(normal_out));
 }
 
 void BumpNode::compile(OSLCompiler& compiler)
 {
 }
 
 void BumpNode::compile(OSLCompiler& compiler)
 {
-       compiler.parameter("invert", invert);
+       compiler.parameter(this, "invert");
        compiler.add(this, "node_bump");
 }
 
        compiler.add(this, "node_bump");
 }
 
-/* RGBCurvesNode */
+void BumpNode::constant_fold(const ConstantFolder& folder)
+{
+       ShaderInput *height_in = input("Height");
+       ShaderInput *normal_in = input("Normal");
 
 
-RGBCurvesNode::RGBCurvesNode()
-: ShaderNode("rgb_curves")
+       if(height_in->link == NULL) {
+               if(normal_in->link == NULL) {
+                       GeometryNode *geom = new GeometryNode();
+                       folder.graph->add(geom);
+                       folder.bypass(geom->output("Normal"));
+               }
+               else {
+                       folder.bypass(normal_in->link);
+               }
+       }
+
+       /* TODO(sergey): Ignore bump with zero strength. */
+}
+
+
+/* Curve node */
+
+CurvesNode::CurvesNode(const NodeType *node_type)
+: ShaderNode(node_type)
 {
 {
-       add_input("Fac", SHADER_SOCKET_FLOAT);
-       add_input("Color", SHADER_SOCKET_COLOR);
-       add_output("Color", SHADER_SOCKET_COLOR);
 }
 
 }
 
-void RGBCurvesNode::compile(SVMCompiler& compiler)
+void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_in)
 {
        ShaderInput *fac_in = input("Fac");
 {
        ShaderInput *fac_in = input("Fac");
-       ShaderInput *color_in = input("Color");
-       ShaderOutput *color_out = output("Color");
 
 
-       compiler.stack_assign(fac_in);
-       compiler.stack_assign(color_in);
-       compiler.stack_assign(color_out);
+       /* remove no-op node */
+       if(!fac_in->link && fac == 0.0f) {
+               folder.bypass(value_in->link);
+       }
+       /* evaluate fully constant node */
+       else if(folder.all_inputs_constant()) {
+               if (curves.size() == 0)
+                       return;
+
+               float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
+               float3 result;
+
+               result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x;
+               result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y;
+               result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z;
 
 
-       compiler.add_node(NODE_RGB_CURVES, fac_in->stack_offset, color_in->stack_offset, color_out->stack_offset);
-       compiler.add_array(curves, RAMP_TABLE_SIZE);
+               folder.make_constant(interp(value, result, fac));
+       }
 }
 
 }
 
-void RGBCurvesNode::compile(OSLCompiler& compiler)
+void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out)
 {
 {
-       float ramp[RAMP_TABLE_SIZE][3];
+       if(curves.size() == 0)
+               return;
 
 
-       for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
-               ramp[i][0] = curves[i].x;
-               ramp[i][1] = curves[i].y;
-               ramp[i][2] = curves[i].z;
-       }
+       ShaderInput *fac_in = input("Fac");
+
+       compiler.add_node(type,
+                         compiler.encode_uchar4(compiler.stack_assign(fac_in),
+                                                compiler.stack_assign(value_in),
+                                                compiler.stack_assign(value_out)),
+                         __float_as_int(min_x),
+                         __float_as_int(max_x));
 
 
-       compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE);
-       compiler.add(this, "node_rgb_curves");
+       compiler.add_node(curves.size());
+       for(int i = 0; i < curves.size(); i++)
+               compiler.add_node(float3_to_float4(curves[i]));
 }
 
 }
 
-/* VectorCurvesNode */
+void CurvesNode::compile(OSLCompiler& compiler, const char* name)
+{
+       if(curves.size() == 0)
+               return;
 
 
-VectorCurvesNode::VectorCurvesNode()
-: ShaderNode("vector_curves")
+       compiler.parameter_color_array("ramp", curves);
+       compiler.parameter(this, "min_x");
+       compiler.parameter(this, "max_x");
+       compiler.add(this, name);
+}
+
+void CurvesNode::compile(SVMCompiler& /*compiler*/)
 {
 {
-       add_input("Fac", SHADER_SOCKET_FLOAT);
-       add_input("Vector", SHADER_SOCKET_VECTOR);
-       add_output("Vector", SHADER_SOCKET_VECTOR);
+       assert(0);
 }
 
 }
 
-void VectorCurvesNode::compile(SVMCompiler& compiler)
+void CurvesNode::compile(OSLCompiler& /*compiler*/)
 {
 {
-       ShaderInput *fac_in = input("Fac");
-       ShaderInput *vector_in = input("Vector");
-       ShaderOutput *vector_out = output("Vector");
+       assert(0);
+}
 
 
-       compiler.stack_assign(fac_in);
-       compiler.stack_assign(vector_in);
-       compiler.stack_assign(vector_out);
+/* RGBCurvesNode */
+
+NODE_DEFINE(RGBCurvesNode)
+{
+       NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER);
+
+       SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
+       SOCKET_FLOAT(min_x, "Min X", 0.0f);
+       SOCKET_FLOAT(max_x, "Max X", 1.0f);
 
 
-       compiler.add_node(NODE_VECTOR_CURVES, fac_in->stack_offset, vector_in->stack_offset, vector_out->stack_offset);
-       compiler.add_array(curves, RAMP_TABLE_SIZE);
+       SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+       SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_OUT_COLOR(value, "Color");
+
+       return type;
 }
 
 }
 
-void VectorCurvesNode::compile(OSLCompiler& compiler)
+RGBCurvesNode::RGBCurvesNode()
+: CurvesNode(node_type)
 {
 {
-       float ramp[RAMP_TABLE_SIZE][3];
+}
 
 
-       for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
-               ramp[i][0] = curves[i].x;
-               ramp[i][1] = curves[i].y;
-               ramp[i][2] = curves[i].z;
-       }
+void RGBCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+       CurvesNode::constant_fold(folder, input("Color"));
+}
+
+void RGBCurvesNode::compile(SVMCompiler& compiler)
+{
+       CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
+}
+
+void RGBCurvesNode::compile(OSLCompiler& compiler)
+{
+       CurvesNode::compile(compiler, "node_rgb_curves");
+}
+
+/* VectorCurvesNode */
 
 
-       compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE);
-       compiler.add(this, "node_vector_curves");
+NODE_DEFINE(VectorCurvesNode)
+{
+       NodeType* type = NodeType::add("vector_curves", create, NodeType::SHADER);
+
+       SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
+       SOCKET_FLOAT(min_x, "Min X", 0.0f);
+       SOCKET_FLOAT(max_x, "Max X", 1.0f);
+
+       SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+       SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+
+       SOCKET_OUT_VECTOR(value, "Vector");
+
+       return type;
+}
+
+VectorCurvesNode::VectorCurvesNode()
+: CurvesNode(node_type)
+{
+}
+
+void VectorCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+       CurvesNode::constant_fold(folder, input("Vector"));
+}
+
+void VectorCurvesNode::compile(SVMCompiler& compiler)
+{
+       CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
+}
+
+void VectorCurvesNode::compile(OSLCompiler& compiler)
+{
+       CurvesNode::compile(compiler, "node_vector_curves");
 }
 
 /* RGBRampNode */
 
 }
 
 /* RGBRampNode */
 
+NODE_DEFINE(RGBRampNode)
+{
+       NodeType* type = NodeType::add("rgb_ramp", create, NodeType::SHADER);
+
+       SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>());
+       SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>());
+       SOCKET_BOOLEAN(interpolate, "Interpolate", true);
+
+       SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
+
+       SOCKET_OUT_COLOR(color, "Color");
+       SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+       return type;
+}
+
 RGBRampNode::RGBRampNode()
 RGBRampNode::RGBRampNode()
-: ShaderNode("rgb_ramp")
+: ShaderNode(node_type)
+{
+}
+
+void RGBRampNode::constant_fold(const ConstantFolder& folder)
 {
 {
-       add_input("Fac", SHADER_SOCKET_FLOAT);
-       add_output("Color", SHADER_SOCKET_COLOR);
-       add_output("Alpha", SHADER_SOCKET_FLOAT);
+       if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+               return;
+
+       if(folder.all_inputs_constant()) {
+               float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1);
+
+               /* clamp int as well in case of NaN */
+               int i = clamp((int)f, 0, ramp.size()-1);
+               float t = f - (float)i;
+
+               bool use_lerp = interpolate && t > 0.0f;
 
 
-       interpolate = true;
+               if(folder.output == output("Color")) {
+                       float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size());
+                       folder.make_constant(color);
+               }
+               else if(folder.output == output("Alpha")) {
+                       float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size());
+                       folder.make_constant(alpha);
+               }
+       }
 }
 
 void RGBRampNode::compile(SVMCompiler& compiler)
 {
 }
 
 void RGBRampNode::compile(SVMCompiler& compiler)
 {
+       if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+               return;
+
        ShaderInput *fac_in = input("Fac");
        ShaderOutput *color_out = output("Color");
        ShaderOutput *alpha_out = output("Alpha");
 
        ShaderInput *fac_in = input("Fac");
        ShaderOutput *color_out = output("Color");
        ShaderOutput *alpha_out = output("Alpha");
 
-       compiler.stack_assign(fac_in);
-       if(!color_out->links.empty())
-               compiler.stack_assign(color_out);
-       if(!alpha_out->links.empty())
-               compiler.stack_assign(alpha_out);
-
        compiler.add_node(NODE_RGB_RAMP,
                compiler.encode_uchar4(
        compiler.add_node(NODE_RGB_RAMP,
                compiler.encode_uchar4(
-                       fac_in->stack_offset,
-                       color_out->stack_offset,
-                       alpha_out->stack_offset),
+                       compiler.stack_assign(fac_in),
+                       compiler.stack_assign_if_linked(color_out),
+                       compiler.stack_assign_if_linked(alpha_out)),
                interpolate);
                interpolate);
-       compiler.add_array(ramp, RAMP_TABLE_SIZE);
+
+       compiler.add_node(ramp.size());
+       for(int i = 0; i < ramp.size(); i++)
+               compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i]));
 }
 
 void RGBRampNode::compile(OSLCompiler& compiler)
 {
 }
 
 void RGBRampNode::compile(OSLCompiler& compiler)
 {
-       /* OSL shader only takes separate RGB and A array, split the RGBA base array */
-       /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */
-       float ramp_color[RAMP_TABLE_SIZE][3];
-       float ramp_alpha[RAMP_TABLE_SIZE];
-
-       for(int i = 0; i < RAMP_TABLE_SIZE; ++i) {
-               ramp_color[i][0] = ramp[i].x;
-               ramp_color[i][1] = ramp[i].y;
-               ramp_color[i][2] = ramp[i].z;
-               ramp_alpha[i] = ramp[i].w;
-       }
+       if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+               return;
 
 
-       compiler.parameter_color_array("ramp_color", ramp_color, RAMP_TABLE_SIZE);
-       compiler.parameter_array("ramp_alpha", ramp_alpha, RAMP_TABLE_SIZE);
-       compiler.parameter("ramp_interpolate", interpolate);
+       compiler.parameter_color_array("ramp_color", ramp);
+       compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
+       compiler.parameter(this, "interpolate");
        
        compiler.add(this, "node_rgb_ramp");
 }
 
 /* Set Normal Node */
 
        
        compiler.add(this, "node_rgb_ramp");
 }
 
 /* Set Normal Node */
 
+NODE_DEFINE(SetNormalNode)
+{
+       NodeType* type = NodeType::add("set_normal", create, NodeType::SHADER);
+
+       SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f));
+       SOCKET_OUT_NORMAL(normal, "Normal");
+
+       return type;
+}
+
 SetNormalNode::SetNormalNode()
 SetNormalNode::SetNormalNode()
-: ShaderNode("set_normal")
+: ShaderNode(node_type)
 {
 {
-       add_input("Direction", SHADER_SOCKET_VECTOR);
-       add_output("Normal", SHADER_SOCKET_NORMAL);
 }
 
 void SetNormalNode::compile(SVMCompiler& compiler)
 }
 
 void SetNormalNode::compile(SVMCompiler& compiler)
@@ -4452,10 +5099,9 @@ void SetNormalNode::compile(SVMCompiler& compiler)
        ShaderInput  *direction_in = input("Direction");
        ShaderOutput *normal_out = output("Normal");
 
        ShaderInput  *direction_in = input("Direction");
        ShaderOutput *normal_out = output("Normal");
 
-       compiler.stack_assign(direction_in);
-       compiler.stack_assign(normal_out);
-
-       compiler.add_node(NODE_CLOSURE_SET_NORMAL, direction_in->stack_offset, normal_out->stack_offset);
+       compiler.add_node(NODE_CLOSURE_SET_NORMAL,
+               compiler.stack_assign(direction_in),
+               compiler.stack_assign(normal_out));
 }
 
 void SetNormalNode::compile(OSLCompiler& compiler)
 }
 
 void SetNormalNode::compile(OSLCompiler& compiler)
@@ -4463,41 +5109,74 @@ void SetNormalNode::compile(OSLCompiler& compiler)
        compiler.add(this, "node_set_normal"); 
 }
 
        compiler.add(this, "node_set_normal"); 
 }
 
-/* OSLScriptNode */
+/* OSLNode */
 
 
-OSLScriptNode::OSLScriptNode()
-: ShaderNode("osl_script")
+OSLNode::OSLNode()
+: ShaderNode(new NodeType(NodeType::SHADER))
 {
        special_type = SHADER_SPECIAL_TYPE_SCRIPT;
 }
 
 {
        special_type = SHADER_SPECIAL_TYPE_SCRIPT;
 }
 
-void OSLScriptNode::compile(SVMCompiler& /*compiler*/)
+OSLNode::~OSLNode()
 {
 {
-       /* doesn't work for SVM, obviously ... */
+       delete type;
 }
 
 }
 
-void OSLScriptNode::compile(OSLCompiler& compiler)
+ShaderNode *OSLNode::clone() const
 {
 {
-       /* XXX fix for #36790:
-        * point and normal parameters are reflected as generic SOCK_VECTOR sockets
-        * on the node. Socket fixed input values need to be copied explicitly here for
-        * vector sockets, otherwise OSL will reject the value due to mismatching type.
-        */
-       foreach(ShaderInput *input, this->inputs) {
-               if(!input->link) {
-                       /* no need for compatible_name here, OSL parameter names are always unique */
-                       string param_name(input->name);
-                       switch(input->type) {
-                               case SHADER_SOCKET_VECTOR:
-                                       compiler.parameter_point(param_name.c_str(), input->value);
-                                       compiler.parameter_normal(param_name.c_str(), input->value);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
+       return OSLNode::create(this->inputs.size(), this);
+}
+
+OSLNode* OSLNode::create(size_t num_inputs, const OSLNode *from)
+{
+       /* allocate space for the node itself and parameters, aligned to 16 bytes
+        * assuming that's the most parameter types need */
+       size_t node_size = align_up(sizeof(OSLNode), 16);
+       size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
+
+       char *node_memory = (char*) operator new(node_size + inputs_size);
+       memset(node_memory, 0, node_size + inputs_size);
+
+       if (!from) {
+               return new(node_memory) OSLNode();
+       }
+       else {
+               /* copy input default values and node type for cloning */
+               memcpy(node_memory + node_size, (char*)from + node_size, inputs_size);
+
+               OSLNode *node = new(node_memory) OSLNode(*from);
+               node->type = new NodeType(*(from->type));
+               return node;
        }
        }
+}
+
+char* OSLNode::input_default_value()
+{
+       /* pointer to default value storage, which is the same as our actual value */
+       size_t num_inputs = type->inputs.size();
+       size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
+       return (char*)this + align_up(sizeof(OSLNode), 16) + inputs_size;
+}
+
+void OSLNode::add_input(ustring name, SocketType::Type socket_type)
+{
+    char *memory = input_default_value();
+       size_t offset = memory - (char*)this;
+       const_cast<NodeType*>(type)->register_input(name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE);
+}
+
+void OSLNode::add_output(ustring name, SocketType::Type socket_type)
+{
+       const_cast<NodeType*>(type)->register_output(name, name, socket_type);
+}
+
+void OSLNode::compile(SVMCompiler&)
+{
+       /* doesn't work for SVM, obviously ... */
+}
 
 
+void OSLNode::compile(OSLCompiler& compiler)
+{
        if(!filepath.empty())
                compiler.add(this, filepath.c_str(), true);
        else
        if(!filepath.empty())
                compiler.add(this, filepath.c_str(), true);
        else
@@ -4506,37 +5185,37 @@ void OSLScriptNode::compile(OSLCompiler& compiler)
 
 /* Normal Map */
 
 
 /* Normal Map */
 
-static ShaderEnum normal_map_space_init()
+NODE_DEFINE(NormalMapNode)
 {
 {
-       ShaderEnum enm;
+       NodeType* type = NodeType::add("normal_map", create, NodeType::SHADER);
 
 
-       enm.insert("Tangent", NODE_NORMAL_MAP_TANGENT);
-       enm.insert("Object", NODE_NORMAL_MAP_OBJECT);
-       enm.insert("World", NODE_NORMAL_MAP_WORLD);
-       enm.insert("Blender Object", NODE_NORMAL_MAP_BLENDER_OBJECT);
-       enm.insert("Blender World", NODE_NORMAL_MAP_BLENDER_WORLD);
+       static NodeEnum space_enum;
+       space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
+       space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
+       space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
+       space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT);
+       space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
+       SOCKET_ENUM(space, "Space", space_enum, NODE_TANGENT_RADIAL);
 
 
-       return enm;
-}
+       SOCKET_STRING(attribute, "Attribute", ustring(""));
 
 
-ShaderEnum NormalMapNode::space_enum = normal_map_space_init();
+       SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
+       SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
+       SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f));
 
 
-NormalMapNode::NormalMapNode()
-: ShaderNode("normal_map")
-{
-       space = ustring("Tangent");
-       attribute = ustring("");
+       SOCKET_OUT_NORMAL(normal, "Normal");
 
 
-       add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, ShaderInput::USE_OSL);
-       add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f);
-       add_input("Color", SHADER_SOCKET_COLOR);
+       return type;
+}
 
 
-       add_output("Normal", SHADER_SOCKET_NORMAL);
+NormalMapNode::NormalMapNode()
+: ShaderNode(node_type)
+{
 }
 
 void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 {
 }
 
 void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 {
-       if(shader->has_surface && space == ustring("Tangent")) {
+       if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
                if(attribute == ustring("")) {
                        attributes->add(ATTR_STD_UV_TANGENT);
                        attributes->add(ATTR_STD_UV_TANGENT_SIGN);
                if(attribute == ustring("")) {
                        attributes->add(ATTR_STD_UV_TANGENT);
                        attributes->add(ATTR_STD_UV_TANGENT_SIGN);
@@ -4559,7 +5238,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
        ShaderOutput *normal_out = output("Normal");
 &n