static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::ShaderNode b_node)
{
	ShaderNode *node = NULL;

	switch(b_node.type()) {
		/* not supported */
		case BL::ShaderNode::type_GEOMETRY: break;
		case BL::ShaderNode::type_MATERIAL: break;
		case BL::ShaderNode::type_MATERIAL_EXT: break;
		case BL::ShaderNode::type_OUTPUT: break;
		case BL::ShaderNode::type_SQUEEZE: break;
		case BL::ShaderNode::type_TEXTURE: break;
		case BL::ShaderNode::type_FRAME: break;
		/* handled outside this function */
		case BL::ShaderNode::type_GROUP: break;
		/* existing blender nodes */
		case BL::ShaderNode::type_REROUTE: {
			BL::Node::inputs_iterator b_input;
			b_node.inputs.begin(b_input);
			BL::Node::outputs_iterator b_output;
			b_node.outputs.begin(b_output);
			ProxyNode *proxy = new ProxyNode(convert_socket_type(b_input->type()), convert_socket_type(b_output->type()));
			node = proxy;
			break;
		}
		case BL::ShaderNode::type_CURVE_VEC: {
			BL::ShaderNodeVectorCurve b_curve_node(b_node);
			VectorCurvesNode *curves = new VectorCurvesNode();
			curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false);
			node = curves;
			break;
		}
		case BL::ShaderNode::type_CURVE_RGB: {
			BL::ShaderNodeRGBCurve b_curve_node(b_node);
			RGBCurvesNode *curves = new RGBCurvesNode();
			curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true);
			node = curves;
			break;
		}
		case BL::ShaderNode::type_VALTORGB: {
			RGBRampNode *ramp = new RGBRampNode();
			BL::ShaderNodeValToRGB b_ramp_node(b_node);
			colorramp_to_array(b_ramp_node.color_ramp(), ramp->ramp, RAMP_TABLE_SIZE);
			node = ramp;
			break;
		}
		case BL::ShaderNode::type_RGB: {
			ColorNode *color = new ColorNode();
			color->value = get_node_output_rgba(b_node, "Color");
			node = color;
			break;
		}
		case BL::ShaderNode::type_VALUE: {
			ValueNode *value = new ValueNode();
			value->value = get_node_output_value(b_node, "Value");
			node = value;
			break;
		}
		case BL::ShaderNode::type_CAMERA: {
			node = new CameraNode();
			break;
		}
		case BL::ShaderNode::type_INVERT: {
			node = new InvertNode();
			break;
		}
		case BL::ShaderNode::type_GAMMA: {
			node = new GammaNode();
			break;
		}
		case BL::ShaderNode::type_BRIGHTCONTRAST: {
			node = new BrightContrastNode();
			break;
		}
		case BL::ShaderNode::type_MIX_RGB: {
			BL::ShaderNodeMixRGB b_mix_node(b_node);
			MixNode *mix = new MixNode();
			mix->type = MixNode::type_enum[b_mix_node.blend_type()];
			mix->use_clamp = b_mix_node.use_clamp();
			node = mix;
			break;
		}
		case BL::ShaderNode::type_SEPRGB: {
			node = new SeparateRGBNode();
			break;
		}
		case BL::ShaderNode::type_COMBRGB: {
			node = new CombineRGBNode();
			break;
		}
		case BL::ShaderNode::type_HUE_SAT: {
			node = new HSVNode();
			break;
		}
		case BL::ShaderNode::type_RGBTOBW: {
			node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
			break;
		}
		case BL::ShaderNode::type_MATH: {
			BL::ShaderNodeMath b_math_node(b_node);
			MathNode *math = new MathNode();
			math->type = MathNode::type_enum[b_math_node.operation()];
			math->use_clamp = b_math_node.use_clamp();
			node = math;
			break;
		}
		case BL::ShaderNode::type_VECT_MATH: {
			BL::ShaderNodeVectorMath b_vector_math_node(b_node);
			VectorMathNode *vmath = new VectorMathNode();
			vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
			node = vmath;
			break;
		}
		case BL::ShaderNode::type_NORMAL: {
			BL::Node::outputs_iterator out_it;
			b_node.outputs.begin(out_it);
			BL::NodeSocketVectorNone vec_sock(*out_it);

			NormalNode *norm = new NormalNode();
			norm->direction = get_float3(vec_sock.default_value());

			node = norm;
			break;
		}
		case BL::ShaderNode::type_MAPPING: {
			BL::ShaderNodeMapping b_mapping_node(b_node);
			MappingNode *mapping = new MappingNode();

			get_tex_mapping(&mapping->tex_mapping, b_mapping_node);

			node = mapping;
			break;
		}

		/* new nodes */
		case BL::ShaderNode::type_OUTPUT_MATERIAL:
		case BL::ShaderNode::type_OUTPUT_WORLD:
		case BL::ShaderNode::type_OUTPUT_LAMP: {
			node = graph->output();
			break;
		}
		case BL::ShaderNode::type_FRESNEL: {
			node = new FresnelNode();
			break;
		}
		case BL::ShaderNode::type_LAYER_WEIGHT: {
			node = new LayerWeightNode();
			break;
		}
		case BL::ShaderNode::type_ADD_SHADER: {
			node = new AddClosureNode();
			break;
		}
		case BL::ShaderNode::type_MIX_SHADER: {
			node = new MixClosureNode();
			break;
		}
		case BL::ShaderNode::type_ATTRIBUTE: {
			BL::ShaderNodeAttribute b_attr_node(b_node);
			AttributeNode *attr = new AttributeNode();
			attr->attribute = b_attr_node.attribute_name();
			node = attr;
			break;
		}
		case BL::ShaderNode::type_BACKGROUND: {
			node = new BackgroundNode();
			break;
		}
		case BL::ShaderNode::type_HOLDOUT: {
			node = new HoldoutNode();
			break;
		}
		case BL::ShaderNode::type_BSDF_ANISOTROPIC: {
			node = new WardBsdfNode();
			break;
		}
		case BL::ShaderNode::type_BSDF_DIFFUSE: {
			node = new DiffuseBsdfNode();
			break;
		}
		case BL::ShaderNode::type_BSDF_GLOSSY: {
			BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
			GlossyBsdfNode *glossy = new GlossyBsdfNode();

			switch(b_glossy_node.distribution()) {
				case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
					glossy->distribution = ustring("Sharp");
					break;
				case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
					glossy->distribution = ustring("Beckmann");
					break;
				case BL::ShaderNodeBsdfGlossy::distribution_GGX:
					glossy->distribution = ustring("GGX");
					break;
			}
			node = glossy;
			break;
		}
		case BL::ShaderNode::type_BSDF_GLASS: {
			BL::ShaderNodeBsdfGlass b_glass_node(b_node);
			GlassBsdfNode *glass = new GlassBsdfNode();
			switch(b_glass_node.distribution()) {
				case BL::ShaderNodeBsdfGlass::distribution_SHARP:
					glass->distribution = ustring("Sharp");
					break;
				case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
					glass->distribution = ustring("Beckmann");
					break;
				case BL::ShaderNodeBsdfGlass::distribution_GGX:
					glass->distribution = ustring("GGX");
					break;
			}
			node = glass;
			break;
		}
		case BL::ShaderNode::type_BSDF_REFRACTION: {
			BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
			RefractionBsdfNode *refraction = new RefractionBsdfNode();
			switch(b_refraction_node.distribution()) {
				case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
					refraction->distribution = ustring("Sharp");
					break;
				case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
					refraction->distribution = ustring("Beckmann");
					break;
				case BL::ShaderNodeBsdfRefraction::distribution_GGX:
					refraction->distribution = ustring("GGX");
					break;
			}
			node = refraction;
			break;
		}
		case BL::ShaderNode::type_BSDF_TRANSLUCENT: {
			node = new TranslucentBsdfNode();
			break;
		}
		case BL::ShaderNode::type_BSDF_TRANSPARENT: {
			node = new TransparentBsdfNode();
			break;
		}
		case BL::ShaderNode::type_BSDF_VELVET: {
			node = new VelvetBsdfNode();
			break;
		}
		case BL::ShaderNode::type_EMISSION: {
			node = new EmissionNode();
			break;
		}
		case BL::ShaderNode::type_AMBIENT_OCCLUSION: {
			node = new AmbientOcclusionNode();
			break;
		}
		case BL::ShaderNode::type_VOLUME_ISOTROPIC: {
			node = new IsotropicVolumeNode();
			break;
		}
		case BL::ShaderNode::type_VOLUME_TRANSPARENT: {
			node = new TransparentVolumeNode();
			break;
		}
		case BL::ShaderNode::type_NEW_GEOMETRY: {
			node = new GeometryNode();
			break;
		}
		case BL::ShaderNode::type_LIGHT_PATH: {
			node = new LightPathNode();
			break;
		}
		case BL::ShaderNode::type_LIGHT_FALLOFF: {
			node = new LightFalloffNode();
			break;
		}
		case BL::ShaderNode::type_OBJECT_INFO: {
			node = new ObjectInfoNode();
			break;
		}
		case BL::ShaderNode::type_PARTICLE_INFO: {
			node = new ParticleInfoNode();
			break;
		}
		case BL::ShaderNode::type_HAIR_INFO: {
			node = new HairInfoNode();
			break;
		}
		case BL::ShaderNode::type_BUMP: {
			node = new BumpNode();
			break;
		}
		case BL::ShaderNode::type_SCRIPT: {
#ifdef WITH_OSL
			if(!scene->shader_manager->use_osl())
				break;

			/* 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->type()));
				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_socket_type(b_output->type()));
			}

			/* load bytecode or filepath */
			OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
			string bytecode_hash = b_script_node.bytecode_hash();

			if(!bytecode_hash.empty()) {
				/* loaded bytecode if not already done */
				if(!manager->shader_test_loaded(bytecode_hash))
					manager->shader_load_bytecode(bytecode_hash, b_script_node.bytecode());

				script_node->bytecode_hash = bytecode_hash;
			}
			else {
				/* set filepath */
				script_node->filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
			}
			
			node = script_node;
#endif

			break;
		}
		case BL::ShaderNode::type_TEX_IMAGE: {
			BL::ShaderNodeTexImage b_image_node(b_node);
			BL::Image b_image(b_image_node.image());
			ImageTextureNode *image = new ImageTextureNode();
			if(b_image) {
				/* builtin images will use callback-based reading because
				 * they could only be loaded correct from blender side
				 */
				bool is_builtin = b_image.packed_file() ||
				                  b_image.source() == BL::Image::source_GENERATED ||
				                  b_image.source() == BL::Image::source_MOVIE;

				if(is_builtin) {
					/* for builtin images we're using image datablock name to find an image to
					 * read pixels from later
					 *
					 * also store frame number as well, so there's no differences in handling
					 * builtin names for packed images and movies
					 */
					int scene_frame = b_scene.frame_current();
					int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
					image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
					image->is_builtin = true;
				}
				else {
					image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
					image->is_builtin = false;
				}

				image->animated = b_image_node.image_user().use_auto_refresh();
			}
			image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
			image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
			image->projection_blend = b_image_node.projection_blend();
			get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
			node = image;
			break;
		}
		case BL::ShaderNode::type_TEX_ENVIRONMENT: {
			BL::ShaderNodeTexEnvironment b_env_node(b_node);
			BL::Image b_image(b_env_node.image());
			EnvironmentTextureNode *env = new EnvironmentTextureNode();
			if(b_image) {
				bool is_builtin = b_image.packed_file() ||
				                  b_image.source() == BL::Image::source_GENERATED ||
				                  b_image.source() == BL::Image::source_MOVIE;

				if(is_builtin) {
					int scene_frame = b_scene.frame_current();
					int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
					env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
					env->is_builtin = true;
				}
				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->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
			env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
			get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
			node = env;
			break;
		}
		case BL::ShaderNode::type_TEX_GRADIENT: {
			BL::ShaderNodeTexGradient b_gradient_node(b_node);
			GradientTextureNode *gradient = new GradientTextureNode();
			gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
			get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
			node = gradient;
			break;
		}
		case BL::ShaderNode::type_TEX_VORONOI: {
			BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
			VoronoiTextureNode *voronoi = new VoronoiTextureNode();
			voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
			get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
			node = voronoi;
			break;
		}
		case BL::ShaderNode::type_TEX_MAGIC: {
			BL::ShaderNodeTexMagic b_magic_node(b_node);
			MagicTextureNode *magic = new MagicTextureNode();
			magic->depth = b_magic_node.turbulence_depth();
			get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
			node = magic;
			break;
		}
		case BL::ShaderNode::type_TEX_WAVE: {
			BL::ShaderNodeTexWave b_wave_node(b_node);
			WaveTextureNode *wave = new WaveTextureNode();
			wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
			get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
			node = wave;
			break;
		}
		case BL::ShaderNode::type_TEX_CHECKER: {
			BL::ShaderNodeTexChecker b_checker_node(b_node);
			CheckerTextureNode *checker = new CheckerTextureNode();
			get_tex_mapping(&checker->tex_mapping, b_checker_node.texture_mapping());
			node = checker;
			break;
		}
		case BL::ShaderNode::type_TEX_BRICK: {
			BL::ShaderNodeTexBrick b_brick_node(b_node);
			BrickTextureNode *brick = new BrickTextureNode();
			brick->offset = b_brick_node.offset();
			brick->offset_frequency = b_brick_node.offset_frequency();
			brick->squash = b_brick_node.squash();
			brick->squash_frequency = b_brick_node.squash_frequency();
			get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
			node = brick;
			break;
		}
		case BL::ShaderNode::type_TEX_NOISE: {
			BL::ShaderNodeTexNoise b_noise_node(b_node);
			NoiseTextureNode *noise = new NoiseTextureNode();
			get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
			node = noise;
			break;
		}
		case BL::ShaderNode::type_TEX_MUSGRAVE: {
			BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
			MusgraveTextureNode *musgrave = new MusgraveTextureNode();
			musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
			get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
			node = musgrave;
			break;
		}
		case BL::ShaderNode::type_TEX_COORD: {
			BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
			TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
			tex_coord->from_dupli = b_tex_coord_node.from_dupli();
			node = tex_coord;
			break;
		}
		case BL::ShaderNode::type_TEX_SKY: {
			BL::ShaderNodeTexSky b_sky_node(b_node);
			SkyTextureNode *sky = new SkyTextureNode();
			sky->sun_direction = get_float3(b_sky_node.sun_direction());
			sky->turbidity = b_sky_node.turbidity();
			get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
			node = sky;
			break;
		}
		case BL::ShaderNode::type_NORMAL_MAP: {
			BL::ShaderNodeNormalMap b_normal_map_node(b_node);
			NormalMapNode *nmap = new NormalMapNode();
			nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
			nmap->attribute = b_normal_map_node.uv_map();
			node = nmap;
			break;
		}
		case BL::ShaderNode::type_TANGENT: {
			BL::ShaderNodeTangent b_tangent_node(b_node);
			TangentNode *tangent = new TangentNode();
			tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
			tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
			tangent->attribute = b_tangent_node.uv_map();
			node = tangent;
			break;
		}
	}

	if(node && node != graph->output())
		graph->add(node);

	return node;
}
static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scene, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::ShaderNode b_node)
{
	ShaderNode *node = NULL;

	/* existing blender nodes */
	if (b_node.is_a(&RNA_ShaderNodeRGBCurve)) {
		BL::ShaderNodeRGBCurve b_curve_node(b_node);
		RGBCurvesNode *curves = new RGBCurvesNode();
		curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true);
		node = curves;
	}
	if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
		BL::ShaderNodeVectorCurve b_curve_node(b_node);
		VectorCurvesNode *curves = new VectorCurvesNode();
		curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false);
		node = curves;
	}
	else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
		RGBRampNode *ramp = new RGBRampNode();
		BL::ShaderNodeValToRGB b_ramp_node(b_node);
		colorramp_to_array(b_ramp_node.color_ramp(), ramp->ramp, RAMP_TABLE_SIZE);
		ramp->interpolate = b_ramp_node.color_ramp().interpolation() != BL::ColorRamp::interpolation_CONSTANT;
		node = ramp;
	}
	else if (b_node.is_a(&RNA_ShaderNodeRGB)) {
		ColorNode *color = new ColorNode();
		color->value = get_node_output_rgba(b_node, "Color");
		node = color;
	}
	else if (b_node.is_a(&RNA_ShaderNodeValue)) {
		ValueNode *value = new ValueNode();
		value->value = get_node_output_value(b_node, "Value");
		node = value;
	}
	else if (b_node.is_a(&RNA_ShaderNodeCameraData)) {
		node = new CameraNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeInvert)) {
		node = new InvertNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeGamma)) {
		node = new GammaNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
		node = new BrightContrastNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeMixRGB)) {
		BL::ShaderNodeMixRGB b_mix_node(b_node);
		MixNode *mix = new MixNode();
		mix->type = MixNode::type_enum[b_mix_node.blend_type()];
			mix->use_clamp = b_mix_node.use_clamp();
		node = mix;
	}
	else if (b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
		node = new SeparateRGBNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
		node = new CombineRGBNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
		node = new SeparateHSVNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
		node = new CombineHSVNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeHueSaturation)) {
		node = new HSVNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
		node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
	}
	else if (b_node.is_a(&RNA_ShaderNodeMath)) {
		BL::ShaderNodeMath b_math_node(b_node);
		MathNode *math = new MathNode();
		math->type = MathNode::type_enum[b_math_node.operation()];
			math->use_clamp = b_math_node.use_clamp();
		node = math;
	}
	else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
		BL::ShaderNodeVectorMath b_vector_math_node(b_node);
		VectorMathNode *vmath = new VectorMathNode();
		vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
		node = vmath;
	}
	else if (b_node.is_a(&RNA_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()];
		node = vtransform;
	}
	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)) {
		BL::ShaderNodeMapping b_mapping_node(b_node);
		MappingNode *mapping = new MappingNode();
		
		get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
		
		node = mapping;
	}
	else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
		node = new FresnelNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
		node = new LayerWeightNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeAddShader)) {
		node = new AddClosureNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeMixShader)) {
		node = new MixClosureNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeAttribute)) {
		BL::ShaderNodeAttribute b_attr_node(b_node);
		AttributeNode *attr = new AttributeNode();
		attr->attribute = b_attr_node.attribute_name();
		node = attr;
	}
	else if (b_node.is_a(&RNA_ShaderNodeBackground)) {
		node = new BackgroundNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeHoldout)) {
		node = new HoldoutNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
		node = new WardBsdfNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
		node = new DiffuseBsdfNode();
	}
	else if (b_node.is_a(&RNA_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;
		}

		node = subsurface;
	}
	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;
		}
		node = glossy;
	}
	else if (b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
		BL::ShaderNodeBsdfGlass b_glass_node(b_node);
		GlassBsdfNode *glass = new GlassBsdfNode();
		switch(b_glass_node.distribution()) {
		case BL::ShaderNodeBsdfGlass::distribution_SHARP:
			glass->distribution = ustring("Sharp");
			break;
		case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
			glass->distribution = ustring("Beckmann");
			break;
		case BL::ShaderNodeBsdfGlass::distribution_GGX:
			glass->distribution = ustring("GGX");
			break;
		}
		node = glass;
	}
	else if (b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
		BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
		RefractionBsdfNode *refraction = new RefractionBsdfNode();
		switch(b_refraction_node.distribution()) {
			case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
				refraction->distribution = ustring("Sharp");
				break;
			case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
				refraction->distribution = ustring("Beckmann");
				break;
			case BL::ShaderNodeBsdfRefraction::distribution_GGX:
				refraction->distribution = ustring("GGX");
				break;
		}
		node = refraction;
	}
	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");
				break;
			case BL::ShaderNodeBsdfToon::component_GLOSSY:
				toon->component = ustring("Glossy");
				break;
		}
		node = toon;
	}
	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");
				break;
			case BL::ShaderNodeBsdfHair::component_Transmission:
				hair->component = ustring("Transmission");
				break;
		}
		node = hair;
	}
	else if (b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
		node = new TranslucentBsdfNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
		node = new TransparentBsdfNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
		node = new VelvetBsdfNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeEmission)) {
		node = new EmissionNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
		node = new AmbientOcclusionNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
		node = new ScatterVolumeNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
		node = new AbsorptionVolumeNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
		node = new GeometryNode();
	}
	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)) {
		node = new WavelengthNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeBlackbody)) {
		node = new BlackbodyNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeLightPath)) {
		node = new LightPathNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
		node = new LightFalloffNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
		node = new ObjectInfoNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
		node = new ParticleInfoNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
		node = new HairInfoNode();
	}
	else if (b_node.is_a(&RNA_ShaderNodeBump)) {
		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)) {
#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;
			}
			else {
				/* set filepath */
				script_node->filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
			}
			
			node = script_node;
		}
#endif
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexImage)) {
		BL::ShaderNodeTexImage b_image_node(b_node);
		BL::Image b_image(b_image_node.image());
		ImageTextureNode *image = new ImageTextureNode();
		if(b_image) {
			/* builtin images will use callback-based reading because
			 * they could only be loaded correct from blender side
			 */
			bool is_builtin = b_image.packed_file() ||
			                  b_image.source() == BL::Image::source_GENERATED ||
			                  b_image.source() == BL::Image::source_MOVIE;

			if(is_builtin) {
				/* for builtin images we're using image datablock name to find an image to
				 * read pixels from later
				 *
				 * also store frame number as well, so there's no differences in handling
				 * builtin names for packed images and movies
				 */
				int scene_frame = b_scene.frame_current();
				int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
				image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
				image->builtin_data = b_image.ptr.data;
			}
			else {
				image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
				image->builtin_data = NULL;
			}

			image->animated = b_image_node.image_user().use_auto_refresh();
		}
		image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
		image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
		image->projection_blend = b_image_node.projection_blend();
		get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
		node = image;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexEnvironment)) {
		BL::ShaderNodeTexEnvironment b_env_node(b_node);
		BL::Image b_image(b_env_node.image());
		EnvironmentTextureNode *env = new EnvironmentTextureNode();
		if(b_image) {
			bool is_builtin = b_image.packed_file() ||
			                  b_image.source() == BL::Image::source_GENERATED ||
			                  b_image.source() == BL::Image::source_MOVIE;

			if(is_builtin) {
				int scene_frame = b_scene.frame_current();
				int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
				env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
				env->builtin_data = b_image.ptr.data;
			}
			else {
				env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
				env->animated = b_env_node.image_user().use_auto_refresh();
				env->builtin_data = NULL;
			}
		}
		env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
		env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
		get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
		node = env;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexGradient)) {
		BL::ShaderNodeTexGradient b_gradient_node(b_node);
		GradientTextureNode *gradient = new GradientTextureNode();
		gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
		get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
		node = gradient;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
		BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
		VoronoiTextureNode *voronoi = new VoronoiTextureNode();
		voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
		get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
		node = voronoi;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexMagic)) {
		BL::ShaderNodeTexMagic b_magic_node(b_node);
		MagicTextureNode *magic = new MagicTextureNode();
		magic->depth = b_magic_node.turbulence_depth();
		get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
		node = magic;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexWave)) {
		BL::ShaderNodeTexWave b_wave_node(b_node);
		WaveTextureNode *wave = new WaveTextureNode();
		wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
		get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
		node = wave;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexChecker)) {
		BL::ShaderNodeTexChecker b_checker_node(b_node);
		CheckerTextureNode *checker = new CheckerTextureNode();
		get_tex_mapping(&checker->tex_mapping, b_checker_node.texture_mapping());
		node = checker;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexBrick)) {
		BL::ShaderNodeTexBrick b_brick_node(b_node);
		BrickTextureNode *brick = new BrickTextureNode();
		brick->offset = b_brick_node.offset();
		brick->offset_frequency = b_brick_node.offset_frequency();
		brick->squash = b_brick_node.squash();
		brick->squash_frequency = b_brick_node.squash_frequency();
		get_tex_mapping(&brick->tex_mapping, b_brick_node.texture_mapping());
		node = brick;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) {
		BL::ShaderNodeTexNoise b_noise_node(b_node);
		NoiseTextureNode *noise = new NoiseTextureNode();
		get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
		node = noise;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexMusgrave)) {
		BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
		MusgraveTextureNode *musgrave = new MusgraveTextureNode();
		musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
		get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
		node = musgrave;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexCoord)) {
		BL::ShaderNodeTexCoord b_tex_coord_node(b_node);
		TextureCoordinateNode *tex_coord = new TextureCoordinateNode();
		tex_coord->from_dupli = b_tex_coord_node.from_dupli();
		node = tex_coord;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTexSky)) {
		BL::ShaderNodeTexSky b_sky_node(b_node);
		SkyTextureNode *sky = new SkyTextureNode();
		sky->type = SkyTextureNode::type_enum[(int)b_sky_node.sky_type()];
		sky->sun_direction = 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());
		node = sky;
	}
	else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
		BL::ShaderNodeNormalMap b_normal_map_node(b_node);
		NormalMapNode *nmap = new NormalMapNode();
		nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
		nmap->attribute = b_normal_map_node.uv_map();
		node = nmap;
	}
	else if (b_node.is_a(&RNA_ShaderNodeTangent)) {
		BL::ShaderNodeTangent b_tangent_node(b_node);
		TangentNode *tangent = new TangentNode();
		tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
		tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
		tangent->attribute = b_tangent_node.uv_map();
		node = tangent;
	}

	if(node)
		graph->add(node);

	return node;
}
Exemple #3
0
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)) {
		BL::ShaderNodeRGBCurve b_curve_node(b_node);
		BL::CurveMapping mapping(b_curve_node.mapping());
		RGBCurvesNode *curves = new RGBCurvesNode();
		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)) {
		BL::ShaderNodeVectorCurve b_curve_node(b_node);
		BL::CurveMapping mapping(b_curve_node.mapping());
		VectorCurvesNode *curves = new VectorCurvesNode();
		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)) {
		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);
		ramp->interpolate = b_color_ramp.interpolation() != BL::ColorRamp::interpolation_CONSTANT;
		node = ramp;
	}
	else if(b_node.is_a(&RNA_ShaderNodeRGB)) {
		ColorNode *color = new ColorNode();
		color->value = get_node_output_rgba(b_node, "Color");
		node = color;
	}
	else if(b_node.is_a(&RNA_ShaderNodeValue)) {
		ValueNode *value = new ValueNode();
		value->value = get_node_output_value(b_node, "Value");
		node = value;
	}
	else if(b_node.is_a(&RNA_ShaderNodeCameraData)) {
		node = new CameraNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeInvert)) {
		node = new InvertNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeGamma)) {
		node = new GammaNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeBrightContrast)) {
		node = new BrightContrastNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeMixRGB)) {
		BL::ShaderNodeMixRGB b_mix_node(b_node);
		MixNode *mix = new MixNode();
		mix->type = MixNode::type_enum[b_mix_node.blend_type()];
		/* Tag if it's Mix */
		if(b_mix_node.blend_type() == 0) 
			mix->special_type = SHADER_SPECIAL_TYPE_MIX_RGB;

		mix->use_clamp = b_mix_node.use_clamp();
		node = mix;
	}
	else if(b_node.is_a(&RNA_ShaderNodeSeparateRGB)) {
		node = new SeparateRGBNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeCombineRGB)) {
		node = new CombineRGBNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeSeparateHSV)) {
		node = new SeparateHSVNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
		node = new CombineHSVNode();
	}
	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_ShaderNodeMath)) {
		BL::ShaderNodeMath b_math_node(b_node);
		MathNode *math = new MathNode();
		math->type = MathNode::type_enum[b_math_node.operation()];
		math->use_clamp = b_math_node.use_clamp();
		node = math;
	}
	else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) {
		BL::ShaderNodeVectorMath b_vector_math_node(b_node);
		VectorMathNode *vmath = new VectorMathNode();
		vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
		node = vmath;
	}
	else if(b_node.is_a(&RNA_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()];
		node = vtransform;
	}
	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)) {
		BL::ShaderNodeMapping b_mapping_node(b_node);
		MappingNode *mapping = new MappingNode();

		get_tex_mapping(&mapping->tex_mapping, b_mapping_node);

		node = mapping;
	}
	else if(b_node.is_a(&RNA_ShaderNodeFresnel)) {
		node = new FresnelNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeLayerWeight)) {
		node = new LayerWeightNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeAddShader)) {
		node = new AddClosureNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeMixShader)) {
		node = new MixClosureNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeAttribute)) {
		BL::ShaderNodeAttribute b_attr_node(b_node);
		AttributeNode *attr = new AttributeNode();
		attr->attribute = b_attr_node.attribute_name();
		node = attr;
	}
	else if(b_node.is_a(&RNA_ShaderNodeBackground)) {
		node = new BackgroundNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeHoldout)) {
		node = new HoldoutNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeBsdfAnisotropic)) {
		BL::ShaderNodeBsdfAnisotropic b_aniso_node(b_node);
		AnisotropicBsdfNode *aniso = new AnisotropicBsdfNode();

		switch(b_aniso_node.distribution()) {
			case BL::ShaderNodeBsdfAnisotropic::distribution_BECKMANN:
				aniso->distribution = ustring("Beckmann");
				break;
			case BL::ShaderNodeBsdfAnisotropic::distribution_GGX:
				aniso->distribution = ustring("GGX");
				break;
			case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY:
				aniso->distribution = ustring("Ashikhmin-Shirley");
				break;
		}

		node = aniso;
	}
	else if(b_node.is_a(&RNA_ShaderNodeBsdfDiffuse)) {
		node = new DiffuseBsdfNode();
	}
	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_BURLEY:
				subsurface->closure = CLOSURE_BSSRDF_BURLEY_ID;
				break;
		}

		node = subsurface;
	}
	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_ASHIKHMIN_SHIRLEY:
				glossy->distribution = ustring("Ashikhmin-Shirley");
				break;
		}
		node = glossy;
	}
	else if(b_node.is_a(&RNA_ShaderNodeBsdfGlass)) {
		BL::ShaderNodeBsdfGlass b_glass_node(b_node);
		GlassBsdfNode *glass = new GlassBsdfNode();
		switch(b_glass_node.distribution()) {
			case BL::ShaderNodeBsdfGlass::distribution_SHARP:
				glass->distribution = ustring("Sharp");
				break;
			case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
				glass->distribution = ustring("Beckmann");
				break;
			case BL::ShaderNodeBsdfGlass::distribution_GGX:
				glass->distribution = ustring("GGX");
				break;
		}
		node = glass;
	}
	else if(b_node.is_a(&RNA_ShaderNodeBsdfRefraction)) {
		BL::ShaderNodeBsdfRefraction b_refraction_node(b_node);
		RefractionBsdfNode *refraction = new RefractionBsdfNode();
		switch(b_refraction_node.distribution()) {
			case BL::ShaderNodeBsdfRefraction::distribution_SHARP:
				refraction->distribution = ustring("Sharp");
				break;
			case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
				refraction->distribution = ustring("Beckmann");
				break;
			case BL::ShaderNodeBsdfRefraction::distribution_GGX:
				refraction->distribution = ustring("GGX");
				break;
		}
		node = refraction;
	}
	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");
				break;
			case BL::ShaderNodeBsdfToon::component_GLOSSY:
				toon->component = ustring("Glossy");
				break;
		}
		node = toon;
	}
	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");
				break;
			case BL::ShaderNodeBsdfHair::component_Transmission:
				hair->component = ustring("Transmission");
				break;
		}
		node = hair;
	}
	else if(b_node.is_a(&RNA_ShaderNodeBsdfTranslucent)) {
		node = new TranslucentBsdfNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeBsdfTransparent)) {
		node = new TransparentBsdfNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeBsdfVelvet)) {
		node = new VelvetBsdfNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeEmission)) {
		node = new EmissionNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
		node = new AmbientOcclusionNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
		node = new ScatterVolumeNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
		node = new AbsorptionVolumeNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
		node = new GeometryNode();
	}
	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)) {
		node = new WavelengthNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeBlackbody)) {
		node = new BlackbodyNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeLightPath)) {
		node = new LightPathNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeLightFalloff)) {
		node = new LightFalloffNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeObjectInfo)) {
		node = new ObjectInfoNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeParticleInfo)) {
		node = new ParticleInfoNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeHairInfo)) {
		node = new HairInfoNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeBump)) {
		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)) {
#ifdef WITH_OSL
		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;
			}
			else {
				/* set filepath */
				script_node->filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
			}

			node = script_node;
		}
#else
		(void)b_data;
		(void)b_ntree;
#endif
	}
	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
			 * they could only be loaded correct from blender side
			 */
			bool is_builtin = b_image.packed_file() ||
			                  b_image.source() == BL::Image::source_GENERATED ||
			                  b_image.source() == BL::Image::source_MOVIE ||
			                  b_engine.is_preview();

			if(is_builtin) {
				/* for builtin images we're using image datablock name to find an image to
				 * read pixels from later
				 *
				 * also store frame number as well, so there's no differences in handling
				 * builtin names for packed images and movies
				 */
				int scene_frame = b_scene.frame_current();
				int image_frame = image_user_frame_number(b_image_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_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,
				        image->builtin_data,
				        (InterpolationType)b_image_node.interpolation(),
				        (ExtensionType)b_image_node.extension());
			}
		}
		image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
		image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
		image->interpolation = (InterpolationType)b_image_node.interpolation();
		image->extension = (ExtensionType)b_image_node.extension();
		image->projection_blend = b_image_node.projection_blend();
		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)) {
		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_engine.is_preview();

			if(is_builtin) {
				int scene_frame = b_scene.frame_current();
				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_image_user,
				                                     b_image,
				                                     b_scene.frame_current());
				env->animated = b_env_node.image_user().use_auto_refresh();
				env->builtin_data = NULL;
			}

			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->builtin_data,
				                                       (InterpolationType)b_env_node.interpolation(),
				                                       EXTENSION_REPEAT);
			}
		}
		env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
		env->interpolation = (InterpolationType)b_env_node.interpolation();
		env->projection = EnvironmentTextureNode::projection_enum[(int)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)) {
		BL::ShaderNodeTexGradient b_gradient_node(b_node);
		GradientTextureNode *gradient = new GradientTextureNode();
		gradient->type = GradientTextureNode::type_enum[(int)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)) {
		BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
		VoronoiTextureNode *voronoi = new VoronoiTextureNode();
		voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)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)) {
		BL::ShaderNodeTexMagic b_magic_node(b_node);
		MagicTextureNode *magic = new MagicTextureNode();
		magic->depth = b_magic_node.turbulence_depth();
		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)) {
		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()];
		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)) {
		BL::ShaderNodeTexChecker b_checker_node(b_node);
		CheckerTextureNode *checker = new CheckerTextureNode();
		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)) {
		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();
		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)) {
		BL::ShaderNodeTexNoise b_noise_node(b_node);
		NoiseTextureNode *noise = new NoiseTextureNode();
		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)) {
		BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
		MusgraveTextureNode *musgrave = new MusgraveTextureNode();
		musgrave->type = MusgraveTextureNode::type_enum[(int)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)) {
		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)) {
		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 = normalize(get_float3(b_sky_node.sun_direction()));
		sky->turbidity = b_sky_node.turbidity();
		sky->ground_albedo = b_sky_node.ground_albedo();
		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)) {
		BL::ShaderNodeNormalMap b_normal_map_node(b_node);
		NormalMapNode *nmap = new NormalMapNode();
		nmap->space = NormalMapNode::space_enum[(int)b_normal_map_node.space()];
		nmap->attribute = b_normal_map_node.uv_map();
		node = nmap;
	}
	else if(b_node.is_a(&RNA_ShaderNodeTangent)) {
		BL::ShaderNodeTangent b_tangent_node(b_node);
		TangentNode *tangent = new TangentNode();
		tangent->direction_type = TangentNode::direction_type_enum[(int)b_tangent_node.direction_type()];
		tangent->axis = TangentNode::axis_enum[(int)b_tangent_node.axis()];
		tangent->attribute = b_tangent_node.uv_map();
		node = tangent;
	}
	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 =
		        PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
		point_density->interpolation =
		        (InterpolationType)b_point_density_node.interpolation();
		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,
			        point_density->builtin_data,
			        point_density->interpolation,
			        EXTENSION_CLIP);
		}
		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)
		graph->add(node);

	return node;
}