Cycles: Make all #include statements relative to cycles source directory
[blender.git] / intern / cycles / blender / blender_shader.cpp
index ed00e88e1b169e8ec9980218ecacdd1829a5d936..0cd4b90340b2fdc016b323aef7c64dc2f1a0b866 100644 (file)
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * 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 "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_sync.h"
-#include "blender_util.h"
+#include "blender/blender_texture.h"
+#include "blender/blender_sync.h"
+#include "blender/blender_util.h"
 
-#include "util_debug.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)
+void BlenderSync::find_shader(BL::ID& id,
+                              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 */
+
+static VolumeSampling get_volume_sampling(PointerRNA& ptr)
+{
+       return (VolumeSampling)get_enum(ptr,
+                                       "volume_sampling",
+                                       VOLUME_NUM_SAMPLING,
+                                       VOLUME_SAMPLING_DISTANCE);
+}
+
+static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
+{
+       return (VolumeInterpolation)get_enum(ptr,
+                                            "volume_interpolation",
+                                            VOLUME_NUM_INTERPOLATION,
+                                            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) {
+               return default_value;
        }
+       return value;
+}
+
+template<typename NodeType>
+static InterpolationType get_image_interpolation(NodeType& b_node)
+{
+       int value = b_node.interpolation();
+       return (InterpolationType)validate_enum_value(value,
+                                                     INTERPOLATION_NUM_TYPES,
+                                                     INTERPOLATION_LINEAR);
+}
+
+template<typename NodeType>
+static ExtensionType get_image_extension(NodeType& b_node)
+{
+       int value = b_node.extension();
+       return (ExtensionType)validate_enum_value(value,
+                                                 EXTENSION_NUM_TYPES,
+                                                 EXTENSION_REPEAT);
 }
 
 /* Graph */
 
-static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
+static BL::NodeSocket get_node_output(BL::Node& b_node, const string& name)
 {
        BL::Node::outputs_iterator b_out;
-       
+
        for(b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
                if(b_out->name() == name)
                        return *b_out;
-       
+
        assert(0);
-       
+
        return *b_out;
 }
 
-static float3 get_node_output_rgba(BL::Node b_node, const string& name)
+static float3 get_node_output_rgba(BL::Node& b_node, const string& name)
 {
        BL::NodeSocket b_sock = get_node_output(b_node, name);
        float value[4];
@@ -71,13 +123,13 @@ static float3 get_node_output_rgba(BL::Node b_node, const string& name)
        return make_float3(value[0], value[1], value[2]);
 }
 
-static float get_node_output_value(BL::Node b_node, const string& name)
+static float get_node_output_value(BL::Node& b_node, const string& name)
 {
        BL::NodeSocket b_sock = get_node_output(b_node, name);
        return RNA_float_get(&b_sock.ptr, "default_value");
 }
 
-static float3 get_node_output_vector(BL::Node b_node, const string& name)
+static float3 get_node_output_vector(BL::Node& b_node, const string& name)
 {
        BL::NodeSocket b_sock = get_node_output(b_node, name);
        float value[3];
@@ -85,61 +137,65 @@ 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()) {
+       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;
        }
 }
 
-static void set_default_value(ShaderInput *input, BL::Node b_node, BL::NodeSocket b_sock, BL::BlendData b_data, BL::ID b_id)
+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"));
-               break;
-       }
-       case SHADER_SOCKET_INT: {
-               input->set((float)get_int(b_sock.ptr, "default_value"));
-               break;
-       }
-       case SHADER_SOCKET_COLOR: {
-               input->set(float4_to_float3(get_float4(b_sock.ptr, "default_value")));
-               break;
-       }
-       case SHADER_SOCKET_NORMAL:
-       case SHADER_SOCKET_POINT:
-       case SHADER_SOCKET_VECTOR: {
-               input->set(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")));
-               break;
-       }
-       
-       case SHADER_SOCKET_CLOSURE:
-       case SHADER_SOCKET_UNDEFINED:
-               break;
+       switch(input->type()) {
+               case SocketType::FLOAT: {
+                       node->set(socket, get_float(b_sock.ptr, "default_value"));
+                       break;
+               }
+               case SocketType::INT: {
+                       node->set(socket, get_int(b_sock.ptr, "default_value"));
+                       break;
+               }
+               case SocketType::COLOR: {
+                       node->set(socket, float4_to_float3(get_float4(b_sock.ptr, "default_value")));
+                       break;
+               }
+               case SocketType::NORMAL:
+               case SocketType::POINT:
+               case SocketType::VECTOR: {
+                       node->set(socket, get_float3(b_sock.ptr, "default_value"));
+                       break;
+               }
+               case SocketType::STRING: {
+                       node->set(socket, (ustring)blender_absolute_path(b_data, b_id, get_string(b_sock.ptr, "default_value")));
+                       break;
+               }
+               default:
+                       break;
        }
 }
 
-static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping b_mapping)
+static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping& b_mapping)
 {
        if(!b_mapping)
                return;
@@ -154,7 +210,8 @@ static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping b_mapping)
        mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
 }
 
-static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping b_mapping)
+static void get_tex_mapping(TextureMapping *mapping,
+                            BL::ShaderNodeMapping& b_mapping)
 {
        if(!b_mapping)
                return;
@@ -172,352 +229,379 @@ static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping b_map
                mapping->max = get_float3(b_mapping.max());
 }
 
-static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::ShaderNode b_node)
+static bool is_output_node(BL::Node& b_node)
+{
+       return (b_node.is_a(&RNA_ShaderNodeOutputMaterial)
+                   || b_node.is_a(&RNA_ShaderNodeOutputWorld)
+                   || b_node.is_a(&RNA_ShaderNodeOutputLamp));
+}
+
+static ShaderNode *add_node(Scene *scene,
+                            BL::RenderEngine& b_engine,
+                            BL::BlendData& b_data,
+                            BL::Scene& b_scene,
+                            const bool background,
+                            ShaderGraph *graph,
+                            BL::ShaderNodeTree& b_ntree,
+                            BL::ShaderNode& b_node)
 {
        ShaderNode *node = NULL;
 
        /* existing blender nodes */
-       if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
+       if(b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
                BL::ShaderNodeRGBCurve b_curve_node(b_node);
+               BL::CurveMapping mapping(b_curve_node.mapping());
                RGBCurvesNode *curves = new RGBCurvesNode();
-               curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true);
+               curvemapping_color_to_array(mapping,
+                                           curves->curves,
+                                           RAMP_TABLE_SIZE,
+                                           true);
+               curvemapping_minmax(mapping, true, &curves->min_x, &curves->max_x);
                node = curves;
        }
-       if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
+       if(b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
                BL::ShaderNodeVectorCurve b_curve_node(b_node);
+               BL::CurveMapping mapping(b_curve_node.mapping());
                VectorCurvesNode *curves = new VectorCurvesNode();
-               curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false);
+               curvemapping_color_to_array(mapping,
+                                           curves->curves,
+                                           RAMP_TABLE_SIZE,
+                                           false);
+               curvemapping_minmax(mapping, false, &curves->min_x, &curves->max_x);
                node = curves;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
+       else if(b_node.is_a(&RNA_ShaderNodeValToRGB)) {
                RGBRampNode *ramp = new RGBRampNode();
                BL::ShaderNodeValToRGB b_ramp_node(b_node);
-               colorramp_to_array(b_ramp_node.color_ramp(), ramp->ramp, RAMP_TABLE_SIZE);
-               ramp->interpolate = b_ramp_node.color_ramp().interpolation() != BL::ColorRamp::interpolation_CONSTANT;
+               BL::ColorRamp b_color_ramp(b_ramp_node.color_ramp());
+               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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
+       else if(b_node.is_a(&RNA_ShaderNodeRGB)) {
                ColorNode *color = new ColorNode();
                color->value = get_node_output_rgba(b_node, "Color");
                node = color;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeValue)) {
+       else if(b_node.is_a(&RNA_ShaderNodeValue)) {
                ValueNode *value = new ValueNode();
                value->value = get_node_output_value(b_node, "Value");
                node = value;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
+       else if(b_node.is_a(&RNA_ShaderNodeCameraData)) {
                node = new CameraNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeInvert)) {
+       else if(b_node.is_a(&RNA_ShaderNodeInvert)) {
                node = new InvertNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeGamma)) {
+       else if(b_node.is_a(&RNA_ShaderNodeGamma)) {
                node = new GammaNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
                node = new BrightContrastNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
+       else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) {
                BL::ShaderNodeMixRGB b_mix_node(b_node);
                MixNode *mix = new MixNode();
-               mix->type = MixNode::type_enum[b_mix_node.blend_type()];
-                       mix->use_clamp = b_mix_node.use_clamp();
+               mix->type = (NodeMix)b_mix_node.blend_type();
+               mix->use_clamp = b_mix_node.use_clamp();
                node = mix;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
+       else if(b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
                node = new SeparateRGBNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
+       else if(b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
                node = new CombineRGBNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
+       else if(b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
                node = new SeparateHSVNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
+       else if(b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
                node = new CombineHSVNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
+       else if(b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
+               node = new SeparateXYZNode();
+       }
+       else if(b_node.is_a(&RNA_ShaderNodeCombineXYZ)) {
+               node = new CombineXYZNode();
+       }
+       else if(b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
                node = new HSVNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
-               node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
+       else if(b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
+               node = new RGBToBWNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeMath)) {
+       else if(b_node.is_a(&RNA_ShaderNodeMath)) {
                BL::ShaderNodeMath b_math_node(b_node);
                MathNode *math = new MathNode();
-               math->type = MathNode::type_enum[b_math_node.operation()];
-                       math->use_clamp = b_math_node.use_clamp();
+               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)) {
+       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)) {
+       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.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)) {
+       else if(b_node.is_a(&RNA_ShaderNodeNormal)) {
                BL::Node::outputs_iterator out_it;
                b_node.outputs.begin(out_it);
-               
+
                NormalNode *norm = new NormalNode();
                norm->direction = get_node_output_vector(b_node, "Normal");
                node = norm;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
+       else if(b_node.is_a(&RNA_ShaderNodeMapping)) {
                BL::ShaderNodeMapping b_mapping_node(b_node);
                MappingNode *mapping = new MappingNode();
-               
+
                get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
-               
+
                node = mapping;
        }
-       /* new nodes */
-       else if (b_node.is_a(&RNA_ShaderNodeOutputMaterial)
-             || b_node.is_a(&RNA_ShaderNodeOutputWorld)
-             || b_node.is_a(&RNA_ShaderNodeOutputLamp)) {
-               node = graph->output();
-       }
-       else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
+       else if(b_node.is_a(&RNA_ShaderNodeFresnel)) {
                node = new FresnelNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
+       else if(b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
                node = new LayerWeightNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeAddShader)) {
+       else if(b_node.is_a(&RNA_ShaderNodeAddShader)) {
                node = new AddClosureNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeMixShader)) {
+       else if(b_node.is_a(&RNA_ShaderNodeMixShader)) {
                node = new MixClosureNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
+       else if(b_node.is_a(&RNA_ShaderNodeAttribute)) {
                BL::ShaderNodeAttribute b_attr_node(b_node);
                AttributeNode *attr = new AttributeNode();
                attr->attribute = b_attr_node.attribute_name();
                node = attr;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBackground)) {
                node = new BackgroundNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
+       else if(b_node.is_a(&RNA_ShaderNodeHoldout)) {
                node = new HoldoutNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
-               node = new WardBsdfNode();
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
+               BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
+               AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode();
+
+               switch(b_aniso_node.distribution()) {
+                       case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
+                               aniso->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID;
+                               break;
+                       case BL::ShaderNodeBsdfAnisotropic::distribution_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 = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
+                               break;
+               }
+
+               node = aniso;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
                node = new DiffuseBsdfNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
+       else if(b_node.is_a(&RNA_ShaderNodeSubsurfaceScattering)) {
                BL::ShaderNodeSubsurfaceScattering b_subsurface_node(b_node);
 
                SubsurfaceScatteringNode *subsurface = new SubsurfaceScatteringNode();
 
                switch(b_subsurface_node.falloff()) {
-               case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
-                       subsurface->closure = CLOSURE_BSSRDF_CUBIC_ID;
-                       break;
-               case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
-                       subsurface->closure = CLOSURE_BSSRDF_GAUSSIAN_ID;
-                       break;
+                       case BL::ShaderNodeSubsurfaceScattering::falloff_CUBIC:
+                               subsurface->falloff = CLOSURE_BSSRDF_CUBIC_ID;
+                               break;
+                       case BL::ShaderNodeSubsurfaceScattering::falloff_GAUSSIAN:
+                               subsurface->falloff = CLOSURE_BSSRDF_GAUSSIAN_ID;
+                               break;
+                       case BL::ShaderNodeSubsurfaceScattering::falloff_BURLEY:
+                               subsurface->falloff = CLOSURE_BSSRDF_BURLEY_ID;
+                               break;
                }
 
                node = subsurface;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfGlossy)) {
                BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
                GlossyBsdfNode *glossy = new GlossyBsdfNode();
                
                switch(b_glossy_node.distribution()) {
-               case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
-                       glossy->distribution = ustring("Sharp");
-                       break;
-               case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
-                       glossy->distribution = ustring("Beckmann");
-                       break;
-               case BL::ShaderNodeBsdfGlossy::distribution_GGX:
-                       glossy->distribution = ustring("GGX");
-                       break;
+                       case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
+                               glossy->distribution = CLOSURE_BSDF_REFLECTION_ID;
+                               break;
+                       case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
+                               glossy->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
+                               break;
+                       case BL::ShaderNodeBsdfGlossy::distribution_GGX:
+                               glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
+                               break;
+                       case BL::ShaderNodeBsdfGlossy::distribution_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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
                BL::ShaderNodeBsdfGlass b_glass_node(b_node);
                GlassBsdfNode *glass = new GlassBsdfNode();
                switch(b_glass_node.distribution()) {
-               case BL::ShaderNodeBsdfGlass::distribution_SHARP:
-                       glass->distribution = ustring("Sharp");
-                       break;
-               case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
-                       glass->distribution = ustring("Beckmann");
-                       break;
-               case BL::ShaderNodeBsdfGlass::distribution_GGX:
-                       glass->distribution = ustring("GGX");
-                       break;
+                       case BL::ShaderNodeBsdfGlass::distribution_SHARP:
+                               glass->distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
+                               break;
+                       case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
+                               glass->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID;
+                               break;
+                       case BL::ShaderNodeBsdfGlass::distribution_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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
                BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
                RefractionBsdfNode *refraction = new RefractionBsdfNode();
                switch(b_refraction_node.distribution()) {
                        case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
-                               refraction->distribution = ustring("Sharp");
+                               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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfToon)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfToon)) {
                BL::ShaderNodeBsdfToon b_toon_node(b_node);
                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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfHair)) {
                BL::ShaderNodeBsdfHair b_hair_node(b_node);
                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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
                node = new TranslucentBsdfNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
                node = new TransparentBsdfNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
                node = new VelvetBsdfNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeEmission)) {
+       else if(b_node.is_a(&RNA_ShaderNodeEmission)) {
                node = new EmissionNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
+       else if(b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
                node = new AmbientOcclusionNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
+       else if(b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
                node = new ScatterVolumeNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
+       else if(b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
                node = new AbsorptionVolumeNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
+       else if(b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
                node = new GeometryNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeWireframe)) {
+       else if(b_node.is_a(&RNA_ShaderNodeWireframe)) {
                BL::ShaderNodeWireframe b_wireframe_node(b_node);
                WireframeNode *wire = new WireframeNode();
                wire->use_pixel_size = b_wireframe_node.use_pixel_size();
                node = wire;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeWavelength)) {
+       else if(b_node.is_a(&RNA_ShaderNodeWavelength)) {
                node = new WavelengthNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBlackbody)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBlackbody)) {
                node = new BlackbodyNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeLightPath)) {
+       else if(b_node.is_a(&RNA_ShaderNodeLightPath)) {
                node = new LightPathNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
+       else if(b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
                node = new LightFalloffNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
+       else if(b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
                node = new ObjectInfoNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
+       else if(b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
                node = new ParticleInfoNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
+       else if(b_node.is_a(&RNA_ShaderNodeHairInfo)) {
                node = new HairInfoNode();
        }
-       else if (b_node.is_a(&RNA_ShaderNodeBump)) {
+       else if(b_node.is_a(&RNA_ShaderNodeBump)) {
                BL::ShaderNodeBump b_bump_node(b_node);
                BumpNode *bump = new BumpNode();
                bump->invert = b_bump_node.invert();
                node = bump;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeScript)) {
+       else if(b_node.is_a(&RNA_ShaderNodeScript)) {
 #ifdef WITH_OSL
                if(scene->shader_manager->use_osl()) {
                        /* create script node */
                        BL::ShaderNodeScript b_script_node(b_node);
-                       OSLScriptNode *script_node = new OSLScriptNode();
-                       
-                       /* 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_socket_type(*b_input));
-                               set_default_value(input, b_node, *b_input, b_data, b_ntree);
-                       }
-                       
-                       BL::Node::outputs_iterator b_output;
-                       
-                       for (b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) {
-                               script_node->output_names.push_back(ustring(b_output->name()));
-                               script_node->add_output(script_node->output_names.back().c_str(),
-                                                       convert_socket_type(*b_output));
-                       }
-                       
-                       /* load bytecode or filepath */
+
                        OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
                        string bytecode_hash = b_script_node.bytecode_hash();
-                       
+
                        if(!bytecode_hash.empty()) {
-                               /* loaded bytecode if not already done */
-                               if(!manager->shader_test_loaded(bytecode_hash))
-                                       manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode());
-                               
-                               script_node->bytecode_hash = bytecode_hash;
+                               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;
+               (void)b_ntree;
 #endif
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexImage)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexImage)) {
                BL::ShaderNodeTexImage b_image_node(b_node);
                BL::Image b_image(b_image_node.image());
+               BL::ImageUser b_image_user(b_image_node.image_user());
                ImageTextureNode *image = new ImageTextureNode();
                if(b_image) {
                        /* builtin images will use callback-based reading because
@@ -525,7 +609,9 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
                         */
                        bool is_builtin = b_image.packed_file() ||
                                          b_image.source() == BL::Image::source_GENERATED ||
-                                         b_image.source() == BL::Image::source_MOVIE;
+                                         b_image.source() == BL::Image::source_MOVIE ||
+                                         (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
@@ -535,316 +621,486 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
                                 * builtin names for packed images and movies
                                 */
                                int scene_frame = b_scene.frame_current();
-                               int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
+                               int image_frame = image_user_frame_number(b_image_user,
+                                                                         scene_frame);
                                image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
                                image->builtin_data = b_image.ptr.data;
                        }
                        else {
-                               image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
+                               image->filename = image_user_file_path(b_image_user,
+                                                                      b_image,
+                                                                      b_scene.frame_current());
                                image->builtin_data = NULL;
                        }
 
                        image->animated = b_image_node.image_user().use_auto_refresh();
+                       image->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(
+                                       image->filename.string(),
+                                       image->builtin_data,
+                                       get_image_interpolation(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();
-               get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
+               BL::TexMapping b_texture_mapping(b_image_node.texture_mapping());
+               get_tex_mapping(&image->tex_mapping, b_texture_mapping);
                node = image;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
                BL::ShaderNodeTexEnvironment b_env_node(b_node);
                BL::Image b_image(b_env_node.image());
+               BL::ImageUser b_image_user(b_env_node.image_user());
                EnvironmentTextureNode *env = new EnvironmentTextureNode();
                if(b_image) {
                        bool is_builtin = b_image.packed_file() ||
                                          b_image.source() == BL::Image::source_GENERATED ||
-                                         b_image.source() == BL::Image::source_MOVIE;
+                                         b_image.source() == BL::Image::source_MOVIE ||
+                                         (b_engine.is_preview() &&
+                                          b_image.source() != BL::Image::source_SEQUENCE);
 
                        if(is_builtin) {
                                int scene_frame = b_scene.frame_current();
-                               int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
+                               int image_frame = image_user_frame_number(b_image_user,
+                                                                         scene_frame);
                                env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
                                env->builtin_data = b_image.ptr.data;
                        }
                        else {
-                               env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
-                               env->animated = b_env_node.image_user().use_auto_refresh();
+                               env->filename = image_user_file_path(b_image_user,
+                                                                    b_image,
+                                                                    b_scene.frame_current());
                                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.string(),
+                                       env->builtin_data,
+                                       get_image_interpolation(b_env_node),
+                                       EXTENSION_REPEAT,
+                                       env->use_alpha);
+                       }
                }
-               env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
-               env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
-               get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
+               env->color_space = (NodeImageColorSpace)b_env_node.color_space();
+               env->interpolation = get_image_interpolation(b_env_node);
+               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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexGradient)) {
                BL::ShaderNodeTexGradient b_gradient_node(b_node);
                GradientTextureNode *gradient = new GradientTextureNode();
-               gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
-               get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
+               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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
                BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
                VoronoiTextureNode *voronoi = new VoronoiTextureNode();
-               voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
-               get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
+               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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexMagic)) {
                BL::ShaderNodeTexMagic b_magic_node(b_node);
                MagicTextureNode *magic = new MagicTextureNode();
                magic->depth = b_magic_node.turbulence_depth();
-               get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
+               BL::TexMapping b_texture_mapping(b_magic_node.texture_mapping());
+               get_tex_mapping(&magic->tex_mapping, b_texture_mapping);
                node = magic;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexWave)) {
                BL::ShaderNodeTexWave b_wave_node(b_node);
                WaveTextureNode *wave = new WaveTextureNode();
-               wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
-               get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
+               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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexChecker)) {
                BL::ShaderNodeTexChecker b_checker_node(b_node);
                CheckerTextureNode *checker = new CheckerTextureNode();
-               get_tex_mapping(&checker->tex_mapping, b_checker_node.texture_mapping());
+               BL::TexMapping b_texture_mapping(b_checker_node.texture_mapping());
+               get_tex_mapping(&checker->tex_mapping, b_texture_mapping);
                node = checker;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexBrick)) {
                BL::ShaderNodeTexBrick b_brick_node(b_node);
                BrickTextureNode *brick = new BrickTextureNode();
                brick->offset = b_brick_node.offset();
                brick->offset_frequency = b_brick_node.offset_frequency();
                brick->squash = b_brick_node.squash();
                brick->squash_frequency = b_brick_node.squash_frequency();
-               get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
+               BL::TexMapping b_texture_mapping(b_brick_node.texture_mapping());
+               get_tex_mapping(&brick->tex_mapping, b_texture_mapping);
                node = brick;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexNoise)) {
                BL::ShaderNodeTexNoise b_noise_node(b_node);
                NoiseTextureNode *noise = new NoiseTextureNode();
-               get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
+               BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping());
+               get_tex_mapping(&noise->tex_mapping, b_texture_mapping);
                node = noise;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
                BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
                MusgraveTextureNode *musgrave = new MusgraveTextureNode();
-               musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
-               get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
+               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;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
+       else if(b_node.is_a(&RNA_ShaderNodeTexCoord)) {
                BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
                TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
                tex_coord->from_dupli = b_tex_coord_node.from_dupli();
+               if(b_tex_coord_node.object()) {
+                       tex_coord->use_transform = true;
+                       tex_coord->ob_tfm = get_transform(b_tex_coord_node.object().matrix_world());
+               }
                node = tex_coord;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
+       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->sun_direction = get_float3(b_sky_node.sun_direction());
+               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();
-               get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
+               BL::TexMapping b_texture_mapping(b_sky_node.texture_mapping());
+               get_tex_mapping(&sky->tex_mapping, b_texture_mapping);
                node = sky;
        }
-       else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
+       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)) {
+       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;
        }
+       else if(b_node.is_a(&RNA_ShaderNodeUVMap)) {
+               BL::ShaderNodeUVMap b_uvmap_node(b_node);
+               UVMapNode *uvm = new UVMapNode();
+               uvm->attribute = b_uvmap_node.uv_map();
+               uvm->from_dupli = b_uvmap_node.from_dupli();
+               node = uvm;
+       }
+       else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
+               BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
+               PointDensityTextureNode *point_density = new PointDensityTextureNode();
+               point_density->filename = b_point_density_node.name();
+               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;
+
+               /* 1 - render settings, 0 - vewport settings. */
+               int settings = background ? 1 : 0;
+
+               /* TODO(sergey): Use more proper update flag. */
+               if(true) {
+                       b_point_density_node.cache_point_density(b_scene, settings);
+                       scene->image_manager->tag_reload_image(
+                               point_density->filename.string(),
+                               point_density->builtin_data,
+                               point_density->interpolation,
+                               EXTENSION_CLIP,
+                               true);
+               }
+               node = point_density;
+
+               /* Transformation form world space to texture space.
+                *
+                * NOTE: Do this after the texture is cached, this is because getting
+                * min/max will need to access this cache.
+                */
+               BL::Object b_ob(b_point_density_node.object());
+               if(b_ob) {
+                       float3 loc, size;
+                       point_density_texture_space(b_scene,
+                                                   b_point_density_node,
+                                                   settings,
+                                                   loc,
+                                                   size);
+                       point_density->tfm =
+                               transform_translate(-loc) * transform_scale(size) *
+                               transform_inverse(get_transform(b_ob.matrix_world()));
+               }
+       }
 
-       if(node && node != graph->output())
+       if(node) {
+               node->name = b_node.name();
                graph->add(node);
+       }
 
        return node;
 }
 
 static bool node_use_modified_socket_name(ShaderNode *node)
 {
-       if (node->special_type == SHADER_SPECIAL_TYPE_SCRIPT)
+       if(node->special_type == SHADER_SPECIAL_TYPE_SCRIPT)
                return false;
-       
+
        return true;
 }
 
-static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::Node b_node, BL::NodeSocket b_socket)
+static ShaderInput *node_find_input_by_name(ShaderNode *node,
+                                            BL::Node& b_node,
+                                            BL::NodeSocket& b_socket)
 {
        string name = b_socket.name();
        
-       if (node_use_modified_socket_name(node)) {
+       if(node_use_modified_socket_name(node)) {
                BL::Node::inputs_iterator b_input;
                bool found = false;
                int counter = 0, total = 0;
-               
-               for (b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
-                       if (b_input->name() == name) {
-                               if (!found)
+
+               for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
+                       if(b_input->name() == name) {
+                               if(!found)
                                        counter++;
                                total++;
                        }
-                       
+
                        if(b_input->ptr.data == b_socket.ptr.data)
                                found = true;
                }
-               
+
                /* rename if needed */
-               if (name == "Shader")
+               if(name == "Shader")
                        name = "Closure";
-               
-               if (total > 1)
+
+               if(total > 1)
                        name = string_printf("%s%d", name.c_str(), counter);
        }
-       
+
        return node->input(name.c_str());
 }
 
-static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::Node b_node, BL::NodeSocket b_socket)
+static ShaderOutput *node_find_output_by_name(ShaderNode *node,
+                                              BL::Node& b_node,
+                                              BL::NodeSocket& b_socket)
 {
        string name = b_socket.name();
-       
-       if (node_use_modified_socket_name(node)) {
+
+       if(node_use_modified_socket_name(node)) {
                BL::Node::outputs_iterator b_output;
                bool found = false;
                int counter = 0, total = 0;
-               
-               for (b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
-                       if (b_output->name() == name) {
-                               if (!found)
+
+               for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
+                       if(b_output->name() == name) {
+                               if(!found)
                                        counter++;
                                total++;
                        }
-                       
+
                        if(b_output->ptr.data == b_socket.ptr.data)
                                found = true;
                }
-               
+
                /* rename if needed */
-               if (name == "Shader")
+               if(name == "Shader")
                        name = "Closure";
-               
-               if (total > 1)
+
+               if(total > 1)
                        name = string_printf("%s%d", name.c_str(), counter);
        }
-       
+
        return node->output(name.c_str());
 }
 
-static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree,
-                      const ProxyMap &proxy_input_map, const ProxyMap &proxy_output_map)
+static void add_nodes(Scene *scene,
+                      BL::RenderEngine& b_engine,
+                      BL::BlendData& b_data,
+                      BL::Scene& b_scene,
+                      const bool background,
+                      ShaderGraph *graph,
+                      BL::ShaderNodeTree& b_ntree,
+                      const ProxyMap &proxy_input_map,
+                      const ProxyMap &proxy_output_map)
 {
        /* add nodes */
        BL::ShaderNodeTree::nodes_iterator b_node;
        PtrInputMap input_map;
        PtrOutputMap output_map;
-       
+
        BL::Node::inputs_iterator b_input;
        BL::Node::outputs_iterator b_output;
 
+       /* find the node to use for output if there are multiple */
+       bool found_active_output = false;
+       BL::ShaderNode output_node(PointerRNA_NULL);
+
+       for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
+               if(is_output_node(*b_node)) {
+                       BL::ShaderNodeOutputMaterial b_output_node(*b_node);
+
+                       if(b_output_node.is_active_output()) {
+                               output_node = b_output_node;
+                               found_active_output = true;
+                               break;
+                       }
+                       else if(!output_node.ptr.data && !found_active_output) {
+                               output_node = b_output_node;
+                       }
+               }
+       }
+
+       /* add nodes */
        for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
-               if (b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
+               if(b_node->mute() || b_node->is_a(&RNA_NodeReroute)) {
                        /* replace muted node with internal links */
                        BL::Node::internal_links_iterator b_link;
-                       for (b_node->internal_links.begin(b_link); b_link != b_node->internal_links.end(); ++b_link) {
-                               ProxyNode *proxy = new ProxyNode(convert_socket_type(b_link->to_socket()));
-                               
+                       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());
+                               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];
-                               
+
                                graph->add(proxy);
                        }
                }
-               else if (b_node->is_a(&RNA_ShaderNodeGroup) || b_node->is_a(&RNA_NodeCustomGroup)) {
+               else if(b_node->is_a(&RNA_ShaderNodeGroup) || b_node->is_a(&RNA_NodeCustomGroup)) {
                        
                        BL::ShaderNodeTree b_group_ntree(PointerRNA_NULL);
-                       if (b_node->is_a(&RNA_ShaderNodeGroup))
+                       if(b_node->is_a(&RNA_ShaderNodeGroup))
                                b_group_ntree = BL::ShaderNodeTree(((BL::NodeGroup)(*b_node)).node_tree());
                        else
                                b_group_ntree = BL::ShaderNodeTree(((BL::NodeCustomGroup)(*b_node)).node_tree());
                        ProxyMap group_proxy_input_map, group_proxy_output_map;
-                       
+
                        /* Add a proxy node for each socket
                         * Do this even if the node group has no internal tree,
                         * 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 */
                                group_proxy_input_map[b_input->identifier()] = proxy;
-                               
+
                                input_map[b_input->ptr.data] = proxy->inputs[0];
-                               
-                               set_default_value(proxy->inputs[0], *b_node, *b_input, b_data, b_ntree);
+
+                               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 */
                                group_proxy_output_map[b_output->identifier()] = proxy;
-                               
+
                                output_map[b_output->ptr.data] = proxy->outputs[0];
                        }
                        
-                       if (b_group_ntree)
-                               add_nodes(scene, b_data, b_scene, graph, b_group_ntree, group_proxy_input_map, group_proxy_output_map);
+                       if(b_group_ntree) {
+                               add_nodes(scene,
+                                         b_engine,
+                                         b_data,
+                                         b_scene,
+                                         background,
+                                         graph,
+                                         b_group_ntree,
+                                         group_proxy_input_map,
+                                         group_proxy_output_map);
+                       }
                }
-               else if (b_node->is_a(&RNA_NodeGroupInput)) {
+               else if(b_node->is_a(&RNA_NodeGroupInput)) {
                        /* map each socket to a proxy node */
                        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;
-                                       
+                               if(proxy_it != proxy_input_map.end()) {
+                                       ConvertNode *proxy = proxy_it->second;
+
                                        output_map[b_output->ptr.data] = proxy->outputs[0];
                                }
                        }
                }
-               else if (b_node->is_a(&RNA_NodeGroupOutput)) {
+               else if(b_node->is_a(&RNA_NodeGroupOutput)) {
                        BL::NodeGroupOutput b_output_node(*b_node);
                        /* only the active group output is used */
-                       if (b_output_node.is_active_output()) {
+                       if(b_output_node.is_active_output()) {
                                /* map each socket to a proxy node */
                                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;
-                                               
+                                       if(proxy_it != proxy_output_map.end()) {
+                                               ConvertNode *proxy = proxy_it->second;
+
                                                input_map[b_input->ptr.data] = proxy->inputs[0];
-                                               
-                                               set_default_value(proxy->inputs[0], *b_node, *b_input, b_data, b_ntree);
+
+                                               set_default_value(proxy->inputs[0], *b_input, b_data, b_ntree);
                                        }
                                }
                        }
                }
                else {
-                       ShaderNode *node = add_node(scene, b_data, b_scene, graph, b_ntree, BL::ShaderNode(*b_node));
-                       
+                       ShaderNode *node = NULL;
+
+                       if(is_output_node(*b_node)) {
+                               if(b_node->ptr.data == output_node.ptr.data) {
+                                       node = graph->output();
+                               }
+                       }
+                       else {
+                               BL::ShaderNode b_shader_node(*b_node);
+                               node = add_node(scene,
+                                               b_engine,
+                                               b_data,
+                                               b_scene,
+                                               background,
+                                               graph,
+                                               b_ntree,
+                                               b_shader_node);
+                       }
+
                        if(node) {
                                /* map node sockets for linking */
                                for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
                                        ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input);
+                                       if(!input) {
+                                               /* XXX should not happen, report error? */
+                                               continue;
+                                       }
                                        input_map[b_input->ptr.data] = input;
-                                       
-                                       set_default_value(input, *b_node, *b_input, b_data, b_ntree);
+
+                                       set_default_value(input, *b_input, b_data, b_ntree);
                                }
                                for(b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
                                        ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output);
+                                       if(!output) {
+                                               /* XXX should not happen, report error? */
+                                               continue;
+                                       }
                                        output_map[b_output->ptr.data] = output;
                                }
                        }
@@ -855,18 +1111,22 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
        BL::NodeTree::links_iterator b_link;
 
        for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
+               /* Ignore invalid links to avoid unwanted cycles created in graph. */
+               if(!b_link->is_valid()) {
+                       continue;
+               }
                /* get blender link data */
                BL::NodeSocket b_from_sock = b_link->from_socket();
                BL::NodeSocket b_to_sock = b_link->to_socket();
 
                ShaderOutput *output = 0;
                ShaderInput *input = 0;
-               
+
                PtrOutputMap::iterator output_it = output_map.find(b_from_sock.ptr.data);
-               if (output_it != output_map.end())
+               if(output_it != output_map.end())
                        output = output_it->second;
                PtrInputMap::iterator input_it = input_map.find(b_to_sock.ptr.data);
-               if (input_it != input_map.end())
+               if(input_it != input_map.end())
                        input = input_it->second;
 
                /* either node may be NULL when the node was not exported, typically
@@ -876,24 +1136,40 @@ static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, Sha
        }
 }
 
-static void add_nodes(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree)
+static void add_nodes(Scene *scene,
+                      BL::RenderEngine& b_engine,
+                      BL::BlendData& b_data,
+                      BL::Scene& b_scene,
+                      const bool background,
+                      ShaderGraph *graph,
+                      BL::ShaderNodeTree& b_ntree)
 {
        static const ProxyMap empty_proxy_map;
-       add_nodes(scene, b_data, b_scene, graph, b_ntree, empty_proxy_map, empty_proxy_map);
+       add_nodes(scene,
+                 b_engine,
+                 b_data,
+                 b_scene,
+                 background,
+                 graph,
+                 b_ntree,
+                 empty_proxy_map,
+                 empty_proxy_map);
 }
 
 /* Sync Materials */
 
 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;
-               
+
                /* test if we need to sync */
                if(shader_map.sync(&shader, *b_mat) || update_all) {
                        ShaderGraph *graph = new ShaderGraph();
@@ -905,16 +1181,15 @@ void BlenderSync::sync_materials(bool update_all)
                        if(b_mat->use_nodes() && b_mat->node_tree()) {
                                BL::ShaderNodeTree b_ntree(b_mat->node_tree());
 
-                               add_nodes(scene, b_data, b_scene, graph, b_ntree);
+                               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 */
@@ -922,11 +1197,27 @@ void BlenderSync::sync_materials(bool update_all)
                        shader->use_mis = get_boolean(cmat, "sample_as_light");
                        shader->use_transparent_shadow = get_boolean(cmat, "use_transparent_shadow");
                        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 */
@@ -939,26 +1230,28 @@ 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 */
                if(b_world && b_world.use_nodes() && b_world.node_tree()) {
                        BL::ShaderNodeTree b_ntree(b_world.node_tree());
 
-                       add_nodes(scene, b_data, b_scene, graph, b_ntree);
-               }
-               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();
-
-                       graph->connect(closure->output("Background"), out->input("Surface"));
+                       add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
 
+                       /* volume */
                        PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
                        shader->heterogeneous_volume = !get_boolean(cworld, "homogeneous_volume");
+                       shader->volume_sampling_method = get_volume_sampling(cworld);
+                       shader->volume_interpolation_method = get_volume_interpolation(cworld);
+               }
+               else if(b_world) {
+                       BackgroundNode *background = new BackgroundNode();
+                       background->color = get_float3(b_world.horizon_color());
+                       graph->add(background);
+
+                       ShaderNode *out = graph->output();
+                       graph->connect(background->output("Background"), out->input("Surface"));
                }
 
                if(b_world) {
@@ -980,18 +1273,24 @@ void BlenderSync::sync_world(bool update_all)
                        visibility |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
                        visibility |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
                        visibility |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
+                       visibility |= get_boolean(cvisibility, "scatter")? PATH_RAY_VOLUME_SCATTER: 0;
 
                        background->visibility = visibility;
                }
+               else {
+                       background->ao_factor = 0.0f;
+                       background->ao_distance = FLT_MAX;
+               }
 
                shader->set_graph(graph);
                shader->tag_update(scene);
+               background->tag_update(scene);
        }
 
        PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
 
        /* when doing preview render check for BI's transparency settings,
-        * this is so because bledner's preview render routines are not able
+        * this is so because Blender's preview render routines are not able
         * to tweak all cycles's settings depending on different circumstances
         */
        if(b_engine.is_preview() == false)
@@ -999,7 +1298,8 @@ void BlenderSync::sync_world(bool update_all)
        else
                background->transparent = b_scene.render().alpha_mode() == BL::RenderSettings::alpha_mode_TRANSPARENT;
 
-       background->use = render_layer.use_background;
+       background->use_shader = render_layer.use_background_shader;
+       background->use_ao = render_layer.use_background_ao;
 
        if(background->modified(prevbackground))
                background->tag_update(scene);
@@ -1009,14 +1309,14 @@ 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;
 
        for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) {
                Shader *shader;
-               
+
                /* test if we need to sync */
                if(shader_map.sync(&shader, *b_lamp) || update_all) {
                        ShaderGraph *graph = new ShaderGraph();
@@ -1027,10 +1327,9 @@ void BlenderSync::sync_lamps(bool update_all)
 
                                BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
 
-                               add_nodes(scene, b_data, b_scene, graph, b_ntree);
+                               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 ||
@@ -1040,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);