Cycles: Make all #include statements relative to cycles source directory
[blender.git] / intern / cycles / blender / blender_shader.cpp
index bce65d081483018751fd77c2365aa67b4e8a291e..0cd4b90340b2fdc016b323aef7c64dc2f1a0b866 100644 (file)
  * limitations under the License.
  */
 
-#include "background.h"
-#include "graph.h"
-#include "light.h"
-#include "nodes.h"
-#include "osl.h"
-#include "scene.h"
-#include "shader.h"
-
-#include "blender_texture.h"
-#include "blender_sync.h"
-#include "blender_util.h"
-
-#include "util_debug.h"
+#include "render/background.h"
+#include "render/graph.h"
+#include "render/light.h"
+#include "render/nodes.h"
+#include "render/osl.h"
+#include "render/scene.h"
+#include "render/shader.h"
+
+#include "blender/blender_texture.h"
+#include "blender/blender_sync.h"
+#include "blender/blender_util.h"
+
+#include "util/util_debug.h"
+#include "util/util_string.h"
+#include "util/util_task.h"
 
 CCL_NAMESPACE_BEGIN
 
 typedef map<void*, ShaderInput*> PtrInputMap;
 typedef map<void*, ShaderOutput*> PtrOutputMap;
-typedef map<std::string, ProxyNode*> ProxyMap;
+typedef map<string, ConvertNode*> ProxyMap;
 
 /* Find */
 
 void BlenderSync::find_shader(BL::ID& id,
-                              vector<uint>& used_shaders,
-                              int default_shader)
+                              vector<Shader*>& used_shaders,
+                              Shader *default_shader)
 {
-       Shader *shader = (id)? shader_map.find(id): scene->shaders[default_shader];
+       Shader *shader = (id)? shader_map.find(id): default_shader;
 
-       for(size_t i = 0; i < scene->shaders.size(); i++) {
-               if(scene->shaders[i] == shader) {
-                       used_shaders.push_back(i);
-                       scene->shaders[i]->tag_used(scene);
-                       break;
-               }
-       }
+       used_shaders.push_back(shader);
+       shader->tag_used(scene);
 }
 
 /* RNA translation utilities */
@@ -69,6 +66,14 @@ static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
                                             VOLUME_INTERPOLATION_LINEAR);
 }
 
+static DisplacementMethod get_displacement_method(PointerRNA& ptr)
+{
+       return (DisplacementMethod)get_enum(ptr,
+                                           "displacement_method",
+                                           DISPLACE_NUM_METHODS,
+                                           DISPLACE_BUMP);
+}
+
 static int validate_enum_value(int value, int num_values, int default_value)
 {
        if(value >= num_values) {
@@ -78,7 +83,7 @@ static int validate_enum_value(int value, int num_values, int default_value)
 }
 
 template<typename NodeType>
-static InterpolationType get_image_interpolation(NodeType b_node)
+static InterpolationType get_image_interpolation(NodeType& b_node)
 {
        int value = b_node.interpolation();
        return (InterpolationType)validate_enum_value(value,
@@ -87,7 +92,7 @@ static InterpolationType get_image_interpolation(NodeType b_node)
 }
 
 template<typename NodeType>
-static ExtensionType get_image_extension(NodeType b_node)
+static ExtensionType get_image_extension(NodeType& b_node)
 {
        int value = b_node.extension();
        return (ExtensionType)validate_enum_value(value,
@@ -132,82 +137,60 @@ static float3 get_node_output_vector(BL::Node& b_node, const string& name)
        return make_float3(value[0], value[1], value[2]);
 }
 
-static ShaderSocketType convert_socket_type(BL::NodeSocket& b_socket)
+static SocketType::Type convert_socket_type(BL::NodeSocket& b_socket)
 {
        switch(b_socket.type()) {
                case BL::NodeSocket::type_VALUE:
-                       return SHADER_SOCKET_FLOAT;
+                       return SocketType::FLOAT;
                case BL::NodeSocket::type_INT:
-                       return SHADER_SOCKET_INT;
+                       return SocketType::INT;
                case BL::NodeSocket::type_VECTOR:
-                       return SHADER_SOCKET_VECTOR;
+                       return SocketType::VECTOR;
                case BL::NodeSocket::type_RGBA:
-                       return SHADER_SOCKET_COLOR;
+                       return SocketType::COLOR;
                case BL::NodeSocket::type_STRING:
-                       return SHADER_SOCKET_STRING;
+                       return SocketType::STRING;
                case BL::NodeSocket::type_SHADER:
-                       return SHADER_SOCKET_CLOSURE;
+                       return SocketType::CLOSURE;
                
                default:
-                       return SHADER_SOCKET_UNDEFINED;
+                       return SocketType::UNDEFINED;
        }
 }
 
-#ifdef WITH_OSL
-static ShaderSocketType convert_osl_socket_type(OSL::OSLQuery& query,
-                                                BL::NodeSocket& b_socket)
-{
-       ShaderSocketType socket_type = convert_socket_type(b_socket);
-       if(socket_type == SHADER_SOCKET_VECTOR) {
-               /* TODO(sergey): Do we need compatible_name() here? */
-               const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name());
-               assert(param != NULL);
-               if(param != NULL) {
-                       if(param->type.vecsemantics == TypeDesc::POINT) {
-                               socket_type = SHADER_SOCKET_POINT;
-                       }
-                       else if(param->type.vecsemantics == TypeDesc::NORMAL) {
-                               socket_type = SHADER_SOCKET_NORMAL;
-                       }
-               }
-       }
-
-       return socket_type;
-}
-#endif  /* WITH_OSL */
-
 static void set_default_value(ShaderInput *input,
                               BL::NodeSocket& b_sock,
                               BL::BlendData& b_data,
                               BL::ID& b_id)
 {
+       Node *node = input->parent;
+       const SocketType& socket = input->socket_type;
+
        /* copy values for non linked inputs */
-       switch(input->type) {
-               case SHADER_SOCKET_FLOAT: {
-                       input->set(get_float(b_sock.ptr, "default_value"));
+       switch(input->type()) {
+               case SocketType::FLOAT: {
+                       node->set(socket, get_float(b_sock.ptr, "default_value"));
                        break;
                }
-               case SHADER_SOCKET_INT: {
-                       input->set((float)get_int(b_sock.ptr, "default_value"));
+               case SocketType::INT: {
+                       node->set(socket, get_int(b_sock.ptr, "default_value"));
                        break;
                }
-               case SHADER_SOCKET_COLOR: {
-                       input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value")));
+               case SocketType::COLOR: {
+                       node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value")));
                        break;
                }
-               case SHADER_SOCKET_NORMAL:
-               case SHADER_SOCKET_POINT:
-               case SHADER_SOCKET_VECTOR: {
-                       input->set(get_float3(b_sock.ptr, "default_value"));
+               case SocketType::NORMAL:
+               case SocketType::POINT:
+               case SocketType::VECTOR: {
+                       node->set(socket, get_float3(b_sock.ptr, "default_value"));
                        break;
                }
-               case SHADER_SOCKET_STRING: {
-                       input->set((ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
+               case SocketType::STRING: {
+                       node->set(socket, (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
                        break;
                }
-
-               case SHADER_SOCKET_CLOSURE:
-               case SHADER_SOCKET_UNDEFINED:
+               default:
                        break;
        }
 }
@@ -291,7 +274,7 @@ static ShaderNode *add_node(Scene *scene,
                RGBRampNode *ramp = new RGBRampNode();
                BL::ShaderNodeValToRGB b_ramp_node(b_node);
                BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
-               colorramp_to_array(b_color_ramp, ramp->ramp, RAMP_TABLE_SIZE);
+               colorramp_to_array(b_color_ramp, ramp->ramp, ramp->ramp_alpha, RAMP_TABLE_SIZE);
                ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT;
                node = ramp;
        }
@@ -320,11 +303,7 @@ static ShaderNode *add_node(Scene *scene,
        else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) {
                BL::ShaderNodeMixRGB b_mix_node(b_node);
                MixNode *mix = new MixNode();
-               mix->type = MixNode::type_enum[b_mix_node.blend_type()];
-               /* Tag if it's Mix */
-               if(b_mix_node.blend_type() == 0) 
-                       mix->special_type = SHADER_SPECIAL_TYPE_MIX_RGB;
-
+               mix->type = (NodeMix)b_mix_node.blend_type();
                mix->use_clamp = b_mix_node.use_clamp();
                node = mix;
        }
@@ -350,27 +329,27 @@ static ShaderNode *add_node(Scene *scene,
                node = new HSVNode();
        }
        else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
-               node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
+               node = new RGBToBWNode();
        }
        else if(b_node.is_a(&RNA_ShaderNodeMath)) {
                BL::ShaderNodeMath b_math_node(b_node);
                MathNode *math = new MathNode();
-               math->type = MathNode::type_enum[b_math_node.operation()];
+               math->type = (NodeMath)b_math_node.operation();
                math->use_clamp = b_math_node.use_clamp();
                node = math;
        }
        else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) {
                BL::ShaderNodeVectorMath b_vector_math_node(b_node);
                VectorMathNode *vmath = new VectorMathNode();
-               vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
+               vmath->type = (NodeVectorMath)b_vector_math_node.operation();
                node = vmath;
        }
        else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
                BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
                VectorTransformNode *vtransform = new VectorTransformNode();
-               vtransform->type = VectorTransformNode::type_enum[b_vector_transform_node.vector_type()];
-               vtransform->convert_from = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_from()];
-               vtransform->convert_to = VectorTransformNode::convert_space_enum[b_vector_transform_node.convert_to()];
+               vtransform->type = (NodeVectorTransformType)b_vector_transform_node.vector_type();
+               vtransform->convert_from = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_from();
+               vtransform->convert_to = (NodeVectorTransformConvertSpace)b_vector_transform_node.convert_to();
                node = vtransform;
        }
        else if(b_node.is_a(&RNA_ShaderNodeNormal)) {
@@ -419,13 +398,16 @@ static ShaderNode *add_node(Scene *scene,
 
                switch(b_aniso_node.distribution()) {
                        case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
-                               aniso->distribution = ustring("Beckmann");
+                               aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
                                break;
                        case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
-                               aniso->distribution = ustring("GGX");
+                               aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID;
+                               break;
+                       case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX:
+                               aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID;
                                break;
                        case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
-                               aniso->distribution = ustring("Ashikhmin-Shirley");
+                               aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
                                break;
                }
 
@@ -441,13 +423,13 @@ static ShaderNode *add_node(Scene *scene,
 
                switch(b_subsurface_node.falloff()) {
                        case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
-                               subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID;
+                               subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID;
                                break;
                        case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
-                               subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
+                               subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID;
                                break;
                        case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
-                               subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID;
+                               subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID;
                                break;
                }
 
@@ -459,16 +441,19 @@ static ShaderNode *add_node(Scene *scene,
                
                switch(b_glossy_node.distribution()) {
                        case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
-                               glossy->distribution = ustring("Sharp");
+                               glossy->distribution = CLOSURE_BSDF_REFLECTION_ID;
                                break;
                        case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
-                               glossy->distribution = ustring("Beckmann");
+                               glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
                                break;
                        case BL::ShaderNodeBsdfGlossy::distribution_GGX:
-                               glossy->distribution = ustring("GGX");
+                               glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
                                break;
                        case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY:
-                               glossy->distribution = ustring("Ashikhmin-Shirley");
+                               glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID;
+                               break;
+                       case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX:
+                               glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID;
                                break;
                }
                node = glossy;
@@ -478,13 +463,16 @@ static ShaderNode *add_node(Scene *scene,
                GlassBsdfNode *glass = new GlassBsdfNode();
                switch(b_glass_node.distribution()) {
                        case BL::ShaderNodeBsdfGlass::distribution_SHARP:
-                               glass->distribution = ustring("Sharp");
+                               glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
                                break;
                        case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
-                               glass->distribution = ustring("Beckmann");
+                               glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID;
                                break;
                        case BL::ShaderNodeBsdfGlass::distribution_GGX:
-                               glass->distribution = ustring("GGX");
+                               glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
+                               break;
+                       case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX:
+                               glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
                                break;
                }
                node = glass;
@@ -494,13 +482,13 @@ static ShaderNode *add_node(Scene *scene,
                RefractionBsdfNode *refraction = new RefractionBsdfNode();
                switch(b_refraction_node.distribution()) {
                        case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
-                               refraction->distribution = ustring("Sharp");
+                               refraction->distribution = CLOSURE_BSDF_REFRACTION_ID;
                                break;
                        case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
-                               refraction->distribution = ustring("Beckmann");
+                               refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
                                break;
                        case BL::ShaderNodeBsdfRefraction::distribution_GGX:
-                               refraction->distribution = ustring("GGX");
+                               refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
                                break;
                }
                node = refraction;
@@ -510,10 +498,10 @@ static ShaderNode *add_node(Scene *scene,
                ToonBsdfNode *toon = new ToonBsdfNode();
                switch(b_toon_node.component()) {
                        case BL::ShaderNodeBsdfToon::component_DIFFUSE:
-                               toon->component = ustring("Diffuse");
+                               toon->component = CLOSURE_BSDF_DIFFUSE_TOON_ID;
                                break;
                        case BL::ShaderNodeBsdfToon::component_GLOSSY:
-                               toon->component = ustring("Glossy");
+                               toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID;
                                break;
                }
                node = toon;
@@ -523,10 +511,10 @@ static ShaderNode *add_node(Scene *scene,
                HairBsdfNode *hair = new HairBsdfNode();
                switch(b_hair_node.component()) {
                        case BL::ShaderNodeBsdfHair::component_Reflection:
-                               hair->component = ustring("Reflection");
+                               hair->component = CLOSURE_BSDF_HAIR_REFLECTION_ID;
                                break;
                        case BL::ShaderNodeBsdfHair::component_Transmission:
-                               hair->component = ustring("Transmission");
+                               hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
                                break;
                }
                node = hair;
@@ -593,62 +581,17 @@ static ShaderNode *add_node(Scene *scene,
                if(scene->shader_manager->use_osl()) {
                        /* create script node */
                        BL::ShaderNodeScript b_script_node(b_node);
-                       OSLScriptNode *script_node = new OSLScriptNode();
 
                        OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
                        string bytecode_hash = b_script_node.bytecode_hash();
 
-                       /* Gather additional information from the shader, such as
-                        * input/output type info needed for proper node construction.
-                        */
-                       OSL::OSLQuery query;
-
-                       if(!bytecode_hash.empty()) {
-                               query.open_bytecode(b_script_node.bytecode());
-                       }
-                       else {
-                               OSLShaderManager::osl_query(query, b_script_node.filepath());
-                       }
-                       /* TODO(sergey): Add proper query info error parsing. */
-
-                       /* Generate inputs/outputs from node sockets
-                        *
-                        * Note: the node sockets are generated from OSL parameters,
-                        * so the names match those of the corresponding parameters exactly.
-                        *
-                        * Note 2: ShaderInput/ShaderOutput store shallow string copies only!
-                        * Socket names must be stored in the extra lists instead. */
-                       BL::Node::inputs_iterator b_input;
-
-                       for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) {
-                               script_node->input_names.push_back(ustring(b_input->name()));
-                               ShaderInput *input = script_node->add_input(script_node->input_names.back().c_str(),
-                                                                           convert_osl_socket_type(query, *b_input));
-                               set_default_value(input, *b_input, b_data, b_ntree);
-                       }
-
-                       BL::Node::outputs_iterator b_output;
-
-                       for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
-                               script_node->output_names.push_back(ustring(b_output->name()));
-                               script_node->add_output(script_node->output_names.back().c_str(),
-                                                       convert_osl_socket_type(query, *b_output));
-                       }
-
-                       /* load bytecode or filepath */
                        if(!bytecode_hash.empty()) {
-                               /* loaded bytecode if not already done */
-                               if(!manager->shader_test_loaded(bytecode_hash))
-                                       manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode());
-
-                               script_node->bytecode_hash = bytecode_hash;
+                               node = manager->osl_node("", bytecode_hash, b_script_node.bytecode());
                        }
                        else {
-                               /* set filepath */
-                               script_node->filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
+                               string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
+                               node = manager->osl_node(absolute_filepath, "");
                        }
-
-                       node = script_node;
                }
 #else
                (void)b_data;
@@ -667,7 +610,8 @@ static ShaderNode *add_node(Scene *scene,
                        bool is_builtin = b_image.packed_file() ||
                                          b_image.source() == BL::Image::source_GENERATED ||
                                          b_image.source() == BL::Image::source_MOVIE ||
-                                         b_engine.is_preview();
+                                         (b_engine.is_preview() &&
+                                          b_image.source() != BL::Image::source_SEQUENCE);
 
                        if(is_builtin) {
                                /* for builtin images we're using image datablock name to find an image to
@@ -695,14 +639,15 @@ static ShaderNode *add_node(Scene *scene,
                        /* TODO(sergey): Does not work properly when we change builtin type. */
                        if(b_image.is_updated()) {
                                scene->image_manager->tag_reload_image(
-                                       image->filename,
+                                       image->filename.string(),
                                        image->builtin_data,
                                        get_image_interpolation(b_image_node),
-                                       get_image_extension(b_image_node));
+                                       get_image_extension(b_image_node),
+                                       image->use_alpha);
                        }
                }
-               image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
-               image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
+               image->color_space = (NodeImageColorSpace)b_image_node.color_space();
+               image->projection = (NodeImageProjection)b_image_node.projection();
                image->interpolation = get_image_interpolation(b_image_node);
                image->extension = get_image_extension(b_image_node);
                image->projection_blend = b_image_node.projection_blend();
@@ -719,7 +664,8 @@ static ShaderNode *add_node(Scene *scene,
                        bool is_builtin = b_image.packed_file() ||
                                          b_image.source() == BL::Image::source_GENERATED ||
                                          b_image.source() == BL::Image::source_MOVIE ||
-                                         b_engine.is_preview();
+                                         (b_engine.is_preview() &&
+                                          b_image.source() != BL::Image::source_SEQUENCE);
 
                        if(is_builtin) {
                                int scene_frame = b_scene.frame_current();
@@ -732,24 +678,25 @@ static ShaderNode *add_node(Scene *scene,
                                env->filename = image_user_file_path(b_image_user,
                                                                     b_image,
                                                                     b_scene.frame_current());
-                               env->animated = b_env_node.image_user().use_auto_refresh();
                                env->builtin_data = NULL;
                        }
 
+                       env->animated = b_env_node.image_user().use_auto_refresh();
                        env->use_alpha = b_image.use_alpha();
 
                        /* TODO(sergey): Does not work properly when we change builtin type. */
                        if(b_image.is_updated()) {
                                scene->image_manager->tag_reload_image(
-                                       env->filename,
+                                       env->filename.string(),
                                        env->builtin_data,
                                        get_image_interpolation(b_env_node),
-                                       EXTENSION_REPEAT);
+                                       EXTENSION_REPEAT,
+                                       env->use_alpha);
                        }
                }
-               env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
+               env->color_space = (NodeImageColorSpace)b_env_node.color_space();
                env->interpolation = get_image_interpolation(b_env_node);
-               env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
+               env->projection = (NodeEnvironmentProjection)b_env_node.projection();
                BL::TexMapping b_texture_mapping(b_env_node.texture_mapping());
                get_tex_mapping(&env->tex_mapping, b_texture_mapping);
                node = env;
@@ -757,7 +704,7 @@ static ShaderNode *add_node(Scene *scene,
        else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) {
                BL::ShaderNodeTexGradient b_gradient_node(b_node);
                GradientTextureNode *gradient = new GradientTextureNode();
-               gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
+               gradient->type = (NodeGradientType)b_gradient_node.gradient_type();
                BL::TexMapping b_texture_mapping(b_gradient_node.texture_mapping());
                get_tex_mapping(&gradient->tex_mapping, b_texture_mapping);
                node = gradient;
@@ -765,7 +712,7 @@ static ShaderNode *add_node(Scene *scene,
        else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
                BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
                VoronoiTextureNode *voronoi = new VoronoiTextureNode();
-               voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
+               voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring();
                BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
                get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
                node = voronoi;
@@ -781,8 +728,8 @@ static ShaderNode *add_node(Scene *scene,
        else if(b_node.is_a(&RNA_ShaderNodeTexWave)) {
                BL::ShaderNodeTexWave b_wave_node(b_node);
                WaveTextureNode *wave = new WaveTextureNode();
-               wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
-               wave->profile = WaveTextureNode::profile_enum[(int)b_wave_node.wave_profile()];
+               wave->type = (NodeWaveType)b_wave_node.wave_type();
+               wave->profile = (NodeWaveProfile)b_wave_node.wave_profile();
                BL::TexMapping b_texture_mapping(b_wave_node.texture_mapping());
                get_tex_mapping(&wave->tex_mapping, b_texture_mapping);
                node = wave;
@@ -815,7 +762,7 @@ static ShaderNode *add_node(Scene *scene,
        else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
                BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
                MusgraveTextureNode *musgrave = new MusgraveTextureNode();
-               musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
+               musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
                BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
                get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping);
                node = musgrave;
@@ -833,7 +780,7 @@ static ShaderNode *add_node(Scene *scene,
        else if(b_node.is_a(&RNA_ShaderNodeTexSky)) {
                BL::ShaderNodeTexSky b_sky_node(b_node);
                SkyTextureNode *sky = new SkyTextureNode();
-               sky->type = SkyTextureNode::type_enum[(int)b_sky_node.sky_type()];
+               sky->type = (NodeSkyType)b_sky_node.sky_type();
                sky->sun_direction = normalize(get_float3(b_sky_node.sun_direction()));
                sky->turbidity = b_sky_node.turbidity();
                sky->ground_albedo = b_sky_node.ground_albedo();
@@ -844,15 +791,15 @@ static ShaderNode *add_node(Scene *scene,
        else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) {
                BL::ShaderNodeNormalMap b_normal_map_node(b_node);
                NormalMapNode *nmap = new NormalMapNode();
-               nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
+               nmap->space = (NodeNormalMapSpace)b_normal_map_node.space();
                nmap->attribute = b_normal_map_node.uv_map();
                node = nmap;
        }
        else if(b_node.is_a(&RNA_ShaderNodeTangent)) {
                BL::ShaderNodeTangent b_tangent_node(b_node);
                TangentNode *tangent = new TangentNode();
-               tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
-               tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
+               tangent->direction_type = (NodeTangentDirectionType)b_tangent_node.direction_type();
+               tangent->axis = (NodeTangentAxis)b_tangent_node.axis();
                tangent->attribute = b_tangent_node.uv_map();
                node = tangent;
        }
@@ -867,8 +814,7 @@ static ShaderNode *add_node(Scene *scene,
                BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
                PointDensityTextureNode *point_density = new PointDensityTextureNode();
                point_density->filename = b_point_density_node.name();
-               point_density->space =
-                       PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
+               point_density->space = (NodeTexVoxelSpace)b_point_density_node.space();
                point_density->interpolation = get_image_interpolation(b_point_density_node);
                point_density->builtin_data = b_point_density_node.ptr.data;
 
@@ -879,10 +825,11 @@ static ShaderNode *add_node(Scene *scene,
                if(true) {
                        b_point_density_node.cache_point_density(b_scene, settings);
                        scene->image_manager->tag_reload_image(
-                               point_density->filename,
+                               point_density->filename.string(),
                                point_density->builtin_data,
                                point_density->interpolation,
-                               EXTENSION_CLIP);
+                               EXTENSION_CLIP,
+                               true);
                }
                node = point_density;
 
@@ -905,8 +852,10 @@ static ShaderNode *add_node(Scene *scene,
                }
        }
 
-       if(node)
+       if(node) {
+               node->name = b_node.name();
                graph->add(node);
+       }
 
        return node;
 }
@@ -1029,7 +978,8 @@ static void add_nodes(Scene *scene,
                        BL::Node::internal_links_iterator b_link;
                        for(b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
                                BL::NodeSocket to_socket(b_link->to_socket());
-                               ProxyNode *proxy = new ProxyNode(convert_socket_type(to_socket));
+                               SocketType::Type to_socket_type = convert_socket_type(to_socket);
+                               ConvertNode *proxy = new ConvertNode(to_socket_type, to_socket_type, true);
 
                                input_map[b_link->from_socket().ptr.data] = proxy->inputs[0];
                                output_map[b_link->to_socket().ptr.data] = proxy->outputs[0];
@@ -1051,7 +1001,8 @@ static void add_nodes(Scene *scene,
                         * so that links have something to connect to and assert won't fail.
                         */
                        for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
-                               ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_input));
+                               SocketType::Type input_type = convert_socket_type(*b_input);
+                               ConvertNode *proxy = new ConvertNode(input_type, input_type, true);
                                graph->add(proxy);
 
                                /* register the proxy node for internal binding */
@@ -1062,7 +1013,8 @@ static void add_nodes(Scene *scene,
                                set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
                        }
                        for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
-                               ProxyNode *proxy = new ProxyNode(convert_socket_type(*b_output));
+                               SocketType::Type output_type = convert_socket_type(*b_output);
+                               ConvertNode *proxy = new ConvertNode(output_type, output_type, true);
                                graph->add(proxy);
 
                                /* register the proxy node for internal binding */
@@ -1088,7 +1040,7 @@ static void add_nodes(Scene *scene,
                        for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
                                ProxyMap::const_iterator proxy_it = proxy_input_map.find(b_output->identifier());
                                if(proxy_it != proxy_input_map.end()) {
-                                       ProxyNode *proxy = proxy_it->second;
+                                       ConvertNode *proxy = proxy_it->second;
 
                                        output_map[b_output->ptr.data] = proxy->outputs[0];
                                }
@@ -1102,7 +1054,7 @@ static void add_nodes(Scene *scene,
                                for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
                                        ProxyMap::const_iterator proxy_it = proxy_output_map.find(b_input->identifier());
                                        if(proxy_it != proxy_output_map.end()) {
-                                               ProxyNode *proxy = proxy_it->second;
+                                               ConvertNode *proxy = proxy_it->second;
 
                                                input_map[b_input->ptr.data] = proxy->inputs[0];
 
@@ -1208,11 +1160,13 @@ static void add_nodes(Scene *scene,
 
 void BlenderSync::sync_materials(bool update_all)
 {
-       shader_map.set_default(scene->shaders[scene->default_surface]);
+       shader_map.set_default(scene->default_surface);
 
        /* material loop */
        BL::BlendData::materials_iterator b_mat;
 
+       TaskPool pool;
+
        for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
                Shader *shader;
 
@@ -1230,13 +1184,12 @@ void BlenderSync::sync_materials(bool update_all)
                                add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
                        }
                        else {
-                               ShaderNode *closure, *out;
-
-                               closure = graph->add(new DiffuseBsdfNode());
-                               closure->input("Color")->value = get_float3(b_mat->diffuse_color());
-                               out = graph->output();
+                               DiffuseBsdfNode *diffuse = new DiffuseBsdfNode();
+                               diffuse->color = get_float3(b_mat->diffuse_color());
+                               graph->add(diffuse);
 
-                               graph->connect(closure->output("BSDF"), out->input("Surface"));
+                               ShaderNode *out = graph->output();
+                               graph->connect(diffuse->output("BSDF"), out->input("Surface"));
                        }
 
                        /* settings */
@@ -1246,11 +1199,25 @@ void BlenderSync::sync_materials(bool update_all)
                        shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
                        shader->volume_sampling_method = get_volume_sampling(cmat);
                        shader->volume_interpolation_method = get_volume_interpolation(cmat);
+                       shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
 
                        shader->set_graph(graph);
+
+                       /* By simplifying the shader graph as soon as possible, some redundant shader nodes
+                        * might be removed which prevents loading unneccessary attributes later.
+                        *
+                        * However, since graph simplification also accounts for e.g. mix weight, this would
+                        * cause frequent expensive resyncs in interactive sessions, so for those sessions
+                        * optimization is only performed right before compiling. */
+                       if(!preview) {
+                               pool.push(function_bind(&ShaderGraph::simplify, shader->graph, scene));
+                       }
+
                        shader->tag_update(scene);
                }
        }
+
+       pool.wait_work();
 }
 
 /* Sync World */
@@ -1263,7 +1230,7 @@ void BlenderSync::sync_world(bool update_all)
        BL::World b_world = b_scene.world();
 
        if(world_recalc || update_all || b_world.ptr.data != world_map) {
-               Shader *shader = scene->shaders[scene->default_background];
+               Shader *shader = scene->default_background;
                ShaderGraph *graph = new ShaderGraph();
 
                /* create nodes */
@@ -1279,13 +1246,12 @@ void BlenderSync::sync_world(bool update_all)
                        shader->volume_interpolation_method = get_volume_interpolation(cworld);
                }
                else if(b_world) {
-                       ShaderNode *closure, *out;
-
-                       closure = graph->add(new BackgroundNode());
-                       closure->input("Color")->value = get_float3(b_world.horizon_color());
-                       out = graph->output();
+                       BackgroundNode *background = new BackgroundNode();
+                       background->color = get_float3(b_world.horizon_color());
+                       graph->add(background);
 
-                       graph->connect(closure->output("Background"), out->input("Surface"));
+                       ShaderNode *out = graph->output();
+                       graph->connect(background->output("Background"), out->input("Surface"));
                }
 
                if(b_world) {
@@ -1343,7 +1309,7 @@ void BlenderSync::sync_world(bool update_all)
 
 void BlenderSync::sync_lamps(bool update_all)
 {
-       shader_map.set_default(scene->shaders[scene->default_light]);
+       shader_map.set_default(scene->default_light);
 
        /* lamp loop */
        BL::BlendData::lamps_iterator b_lamp;
@@ -1364,7 +1330,6 @@ void BlenderSync::sync_lamps(bool update_all)
                                add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
                        }
                        else {
-                               ShaderNode *closure, *out;
                                float strength = 1.0f;
 
                                if(b_lamp->type() == BL::Lamp::type_POINT ||
@@ -1374,12 +1339,13 @@ void BlenderSync::sync_lamps(bool update_all)
                                        strength = 100.0f;
                                }
 
-                               closure = graph->add(new EmissionNode());
-                               closure->input("Color")->value = get_float3(b_lamp->color());
-                               closure->input("Strength")->value.x = strength;
-                               out = graph->output();
+                               EmissionNode *emission = new EmissionNode();
+                               emission->color = get_float3(b_lamp->color());
+                               emission->strength = strength;
+                               graph->add(emission);
 
-                               graph->connect(closure->output("Emission"), out->input("Surface"));
+                               ShaderNode *out = graph->output();
+                               graph->connect(emission->output("Emission"), out->input("Surface"));
                        }
 
                        shader->set_graph(graph);