Example #1
0
static int get_glyph_surface(bitmap_backend_data_t *data, glyph_id_t glyph_id,
    surface_t **result)
{
	if (glyph_id >= data->glyph_count)
		return ENOENT;
	
	if (data->glyph_cache[glyph_id].surface != NULL) {
		*result = data->glyph_cache[glyph_id].surface;
		return EOK;
	}
	
	surface_t *raw_surface;
	int rc = data->decoder->load_glyph_surface(data->decoder_data, glyph_id,
	    &raw_surface);
	if (rc != EOK)
		return rc;
	
	sysarg_t w;
	sysarg_t h;
	surface_get_resolution(raw_surface, &w, &h);
	
	if (!data->scale) {
		*result = raw_surface;
		return EOK;
	}
	
	source_t source;
	source_init(&source);
	source_set_texture(&source, raw_surface, PIXELMAP_EXTEND_TRANSPARENT_BLACK);

	transform_t transform;
	transform_identity(&transform);
	transform_translate(&transform, 0.5, 0.5);
	transform_scale(&transform, data->scale_ratio, data->scale_ratio);
	source_set_transform(&source, transform);

	surface_coord_t scaled_width = (data->scale_ratio * ((double) w) + 0.5);
	surface_coord_t scaled_height = (data->scale_ratio * ((double) h) + 0.5);

	surface_t *scaled_surface = surface_create(scaled_width, scaled_height,
	    NULL, 0);
	if (!scaled_surface) {
		surface_destroy(raw_surface);
		return ENOMEM;
	}

	drawctx_t context;
	drawctx_init(&context, scaled_surface);
	drawctx_set_source(&context, &source);
	drawctx_transfer(&context, 0, 0, scaled_width, scaled_height);

	surface_destroy(raw_surface);
	
	data->glyph_cache[glyph_id].surface = scaled_surface;
	*result = scaled_surface;
	return EOK;
}
Example #2
0
void glScale3f(float x, float y, float z)
{
	matrix_t matrix_scale;
	matrix_t matrix_res;

	transform_scale(&matrix_scale, x, y, z);
	matrix_mul(&matrix_main, &matrix_scale, &matrix_res);
	matrix_clone(&matrix_main, &matrix_res);
}
Example #3
0
void
transform_project(enum projection pro, struct coord *c, int distance, int angle, struct coord *res)
{
	double scale;
	switch (pro) {
	case projection_mg:
		scale=transform_scale(c->y);
		res->x=c->x+distance*sin(angle*M_PI/180)*scale;
		res->y=c->y+distance*cos(angle*M_PI/180)*scale;
		break;
	default:
		dbg(0,"Unsupported projection: %d\n", pro);
		return;
	}
	
}
Example #4
0
double
transform_distance(enum projection pro, struct coord *c1, struct coord *c2)
{
	if (pro == projection_mg) {
#ifndef AVOID_FLOAT 
	double dx,dy,scale=transform_scale((c1->y+c2->y)/2);
	dx=c1->x-c2->x;
	dy=c1->y-c2->y;
	return sqrt(dx*dx+dy*dy)/scale;
#else
	int dx,dy,f,scale=transform_int_scale((c1->y+c2->y)/2);
	dx=c1->x-c2->x;
	dy=c1->y-c2->y;
	if (dx < 0)
		dx=-dx;
	if (dy < 0)
		dy=-dy;
	while (dx > 20000 || dy > 20000) {
		dx/=10;
		dy/=10;
		scale/=10;
	}
	if (! dy)
		return dx*10000/scale;
	if (! dx)
		return dy*10000/scale;
	if (dx > dy) {
		f=dx*8/dy-8;
		if (f >= 32)
			return dx*10000/scale;
		return dx*tab_sqrt[f]/scale;
	} else {
		f=dy*8/dx-8;
		if (f >= 32)
			return dy*10000/scale;
		return dy*tab_sqrt[f]/scale;
	}
#endif
	} else if (pro == projection_garmin) {
		return transform_distance_garmin(c1, c2);
	} else {
		dbg(0,"Unknown projection: %d\n", pro);
		return 0;
	}
}
static Transform blender_camera_matrix(const Transform& tfm, CameraType type)
{
	Transform result;

	if(type == CAMERA_PANORAMA) {
		/* make it so environment camera needs to be pointed in the direction
		 * of the positive x-axis to match an environment texture, this way
		 * it is looking at the center of the texture */
		result = tfm *
			make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
			                0.0f,  0.0f, 1.0f, 0.0f,
			               -1.0f,  0.0f, 0.0f, 0.0f,
			                0.0f,  0.0f, 0.0f, 1.0f);
	}
	else {
		/* note the blender camera points along the negative z-axis */
		result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
	}

	return transform_clear_scale(result);
}
Example #6
0
static Transform blender_camera_matrix(const Transform& tfm,
                                       const CameraType type,
                                       const PanoramaType panorama_type)
{
	Transform result;

	if(type == CAMERA_PANORAMA) {
		if(panorama_type == PANORAMA_MIRRORBALL) {
			/* Mirror ball camera is looking into the negative Y direction
			 * which matches texture mirror ball mapping.
			 */
			result = tfm *
				make_transform(1.0f, 0.0f, 0.0f, 0.0f,
				               0.0f, 0.0f, 1.0f, 0.0f,
				               0.0f, 1.0f, 0.0f, 0.0f,
				               0.0f, 0.0f, 0.0f, 1.0f);
		}
		else {
			/* Make it so environment camera needs to be pointed in the direction
			 * of the positive x-axis to match an environment texture, this way
			 * it is looking at the center of the texture
			 */
			result = tfm *
				make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
				                0.0f,  0.0f, 1.0f, 0.0f,
				               -1.0f,  0.0f, 0.0f, 0.0f,
				                0.0f,  0.0f, 0.0f, 1.0f);
		}
	}
	else {
		/* note the blender camera points along the negative z-axis */
		result = tfm * transform_scale(1.0f, 1.0f, -1.0f);
	}

	return transform_clear_scale(result);
}
Example #7
0
void
graphics_redraw(struct container *co)
{
	int scale=transform_get_scale(co->trans);
	int i,slimit=255,tlimit=255,plimit=255;
	int bw[4],w[4],t[4];
	struct display_list **disp=co->disp;
	struct graphics *gra=co->gra;

#if 0
	printf("scale=%d center=0x%lx,0x%lx mercator scale=%f\n", scale, co->trans->center.x, co->trans->center.y, transform_scale(co->trans->center.y));
#endif
	
	display_free(co->disp, display_end);

	transform_setup_source_rect(co->trans);

	gra->draw_mode(gra, draw_mode_begin);
	for (i = 0 ; i < data_window_type_end; i++) {
		data_window_begin(co->data_window[i]);	
	}
	gra->gc_set_linewidth(gra->gc[GC_RAIL], 3);

	bw[0]=0;
	bw[1]=0;
	bw[2]=0;
	bw[3]=0;
	w[0]=1;
	w[1]=1;
	w[2]=1;
	w[3]=1;
	t[0]=0xf;
	t[1]=0xf;
	t[2]=0xf;
	t[3]=0xf;
	if (scale < 2) {
		tlimit=0xff;
		slimit=0xff;
		bw[0]=17;
		w[0]=15;
		bw[1]=19;
		w[1]=17;
		bw[2]=19;
		w[2]=17;
		bw[3]=21;
		w[3]=17;
	} else if (scale < 4) {
		tlimit=0xff;
		slimit=0xff;
		bw[0]=11;
		w[0]=9;
		bw[1]=13;
		w[1]=11;
		bw[2]=13;
		w[2]=11;
		bw[3]=15;
		w[3]=11;
	} else if (scale < 8) {
		tlimit=0xff;
		slimit=0xff;
		bw[0]=5;
		w[0]=3;
		bw[1]=11;
		w[1]=9;
		bw[2]=11;
		w[2]=9;
		bw[3]=13;
		w[3]=9;
		t[0]=0xa;
		t[1]=0xf;
	} else if (scale < 16) {
		tlimit=0xff;
		slimit=0xff;
		bw[1]=9;
		w[1]=7;
		bw[2]=9;
		w[2]=7;
		bw[3]=11;
		w[3]=7;
		t[0]=0x9;
		t[1]=0xe;
	} else if (scale < 32) {
		tlimit=0xff;
		slimit=0xff;
		bw[1]=5;
		w[1]=3;
		bw[2]=5;
		w[2]=3;
		bw[3]=5;
		w[3]=3;
		t[0]=0x8;
		t[1]=0xb;
	} else if (scale < 64) {
		tlimit=0xf;
		slimit=0x6;
		bw[1]=5;
		w[1]=3;
		bw[2]=5;
		w[2]=3;
		bw[3]=5;
		w[3]=3;
		t[0]=0x8;
		t[1]=0xa;
	} else if (scale < 128) {
		tlimit=0xc;
		slimit=0x6;
		plimit=0x1e;
		w[1]=3;
		w[2]=3;
		bw[3]=5;
		w[3]=3;
		t[0]=0x7;
		t[1]=0xa;
	} else if (scale < 256) {
		tlimit=0xb;
		slimit=0x5;
		plimit=0x1a;
		w[2]=3;
		bw[3]=5;
		w[3]=3;
		t[0]=0x7;
		t[1]=0x8;
	} else if (scale < 512) {
		tlimit=0x9;
		slimit=0x5;
		plimit=0x14;
		w[1]=0;
		w[2]=1;
		bw[3]=3;
		w[3]=1;
		t[0]=0x4;
		t[1]=0x7;
	} else if (scale < 1024) {
		tlimit=0x8;
		slimit=0x4;
		slimit=0x4;
		plimit=0x11;
		w[1]=0;
		w[2]=1;
		bw[3]=3;
		w[3]=1;
		t[0]=0x3;
		t[1]=0x5;
	} else if (scale < 2048) {
		tlimit=0x5;
		slimit=0x3;
		plimit=0x10;
		bw[3]=3;
		w[3]=1;
		t[0]=0x2;
		t[1]=0x4;
	} else if (scale < 4096) {
		bw[3]=3;
		w[3]=1;
		tlimit=0x4;
		slimit=0x2;
		plimit=0xf;
		t[0]=0x2;
		t[1]=0x3;
	} else if (scale < 8192) {
		bw[3]=3;
		w[3]=1;
		tlimit=0x3;
		slimit=0x2;
		plimit=0xf;
		t[0]=0x1;
		t[1]=0x2;
	} else {
		bw[3]=3;
		w[3]=1;
		tlimit=0x2;
		slimit=0x2;
		plimit=0xf;
		t[0]=0x1;
		t[1]=0x4;
	}
	gra->gc_set_linewidth(gra->gc[GC_STREET_SMALL], w[0]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_NO_PASS], w[0]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_SMALL_B], bw[0]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_MID], w[1]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_MID_B], bw[1]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_BIG], w[2]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_BIG_B], bw[2]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_BIG2], w[3]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_BIG2_B], bw[3]);
	gra->gc_set_linewidth(gra->gc[GC_STREET_ROUTE], w[3]+7+w[3]/2);

	profile_timer(NULL);
	graphics_draw(co->map_data, file_border_ply, co, display_rail, plimit, 48, poly_draw_block);
	graphics_draw(co->map_data, file_woodland_ply, co, display_wood, plimit, 48, poly_draw_block);
	graphics_draw(co->map_data, file_other_ply, co, display_other, plimit, 48, poly_draw_block);
	graphics_draw(co->map_data, file_town_twn, co, display_town, tlimit, 48, town_draw_block);
	graphics_draw(co->map_data, file_water_ply, co, display_water, plimit, 48, poly_draw_block);
	graphics_draw(co->map_data, file_sea_ply, co, display_sea, plimit, 48, poly_draw_block);
	/* todo height, tunnel, bridge, street_bti ??? */
#if 0
	graphics_draw(co->map_data, file_height_ply, co, display_other1, plimit, 48, poly_draw_block);
#endif
	if (scale < 256) {
		graphics_draw(co->map_data, file_rail_ply, co, display_rail, plimit, 48, poly_draw_block);
	}
	profile_timer("map_draw");
	plugin_call_draw(co);
	profile_timer("plugin");
#if 0
	draw_poly(map, &co->d_tunnel_ply, "Tunnel", 0, 11, plimit);
#endif
	graphics_draw(co->map_data, file_street_str, co, display_street, slimit, 7, street_draw_block);
  
	display_draw(disp[display_sea], gra, gra->gc[GC_WATER_FILL], NULL); 
	display_draw(disp[display_wood], gra, gra->gc[GC_WOOD], NULL); 
	display_draw(disp[display_other], gra, gra->gc[GC_TOWN_FILL], gra->gc[GC_TOWN_LINE]); 
	display_draw(disp[display_other1], gra, gra->gc[GC_BUILDING], NULL); 
	display_draw(disp[display_other2], gra, gra->gc[GC_BUILDING_2], NULL); 
	display_draw(disp[display_other3], gra, gra->gc[GC_PARK], NULL); 
	display_draw(disp[display_water], gra, gra->gc[GC_WATER_FILL], gra->gc[GC_WATER_LINE]); 
	display_draw(disp[display_rail], gra, gra->gc[GC_RAIL], NULL); 
	street_route_draw(co);
	display_draw(disp[display_street_route], gra, gra->gc[GC_STREET_ROUTE], NULL); 
	if (bw[0]) {
		display_draw(disp[display_street_no_pass], gra, gra->gc[GC_STREET_SMALL_B], NULL); 
		display_draw(disp[display_street], gra, gra->gc[GC_STREET_SMALL_B], NULL); 
	}
	if (bw[1]) 
		display_draw(disp[display_street1], gra, gra->gc[GC_STREET_MID_B], NULL); 
	if (bw[2])
		display_draw(disp[display_street2], gra, gra->gc[GC_STREET_BIG_B], NULL); 
	if (bw[3])
		display_draw(disp[display_street3], gra, gra->gc[GC_STREET_BIG2_B], NULL); 
	if (w[0]) {
		display_draw(disp[display_street_no_pass], gra, gra->gc[GC_STREET_NO_PASS], NULL); 
		display_draw(disp[display_street], gra, gra->gc[GC_STREET_SMALL], NULL); 
	}
	if (w[1]) 
		display_draw(disp[display_street1], gra, gra->gc[GC_STREET_MID], gra->gc[GC_BLACK]); 
	display_draw(disp[display_street2], gra, gra->gc[GC_STREET_BIG], gra->gc[GC_BLACK]); 
	display_draw(disp[display_street3], gra, gra->gc[GC_STREET_BIG2], gra->gc[GC_BLACK]); 
	if (w[3] > 1) 
		display_draw(disp[display_street3], gra, gra->gc[GC_STREET_BIG2_L], NULL); 

	display_draw(disp[display_poi], gra, gra->gc[GC_BLACK], NULL); 


	profile_timer("display_draw");

	if (scale < 2) {
		display_labels(disp[display_street], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[1]);
		display_labels(disp[display_street1], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[1]);
	}
	else {
		display_labels(disp[display_street], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]);
		display_labels(disp[display_street1], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]);
	}
	display_labels(disp[display_street2], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]);
	display_labels(disp[display_street3], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]);

	for (i = display_town+t[1] ; i < display_town+0x10 ; i++) 
		display_labels(disp[i], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[0]);
	for (i = display_town+t[0] ; i < display_town+t[1] ; i++) 
		display_labels(disp[i], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[1]);
	for (i = display_town ; i < display_town+t[0] ; i++) 
		display_labels(disp[i], gra, gra->gc[GC_TEXT_FG], gra->gc[GC_TEXT_BG], gra->font[2]);

	for (i = display_town ; i < display_town+0x10 ; i++) 
		display_draw(disp[i], gra, gra->gc[GC_BLACK], NULL); 
	display_draw(disp[display_bti], gra, gra->gc[GC_BLACK], NULL); 
	profile_timer("labels");
	gra->draw_mode(gra, draw_mode_end);
	for (i = 0 ; i < data_window_type_end; i++) {
		data_window_end(co->data_window[i]);	
	}
#if 0
	map_scrollbars_update(map);
#endif
}
Example #8
0
void Camera::update()
{
	if(!need_update)
		return;

	/* Full viewport to camera border in the viewport. */
	Transform fulltoborder = transform_from_viewplane(viewport_camera_border);
	Transform bordertofull = transform_inverse(fulltoborder);

	/* ndc to raster */
	Transform screentocamera;
	Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull;

	/* raster to screen */
	Transform screentondc = fulltoborder * transform_from_viewplane(viewplane);

	Transform screentoraster = ndctoraster * screentondc;
	Transform rastertoscreen = transform_inverse(screentoraster);

	/* screen to camera */
	if(type == CAMERA_PERSPECTIVE)
		screentocamera = transform_inverse(transform_perspective(fov, nearclip, farclip));
	else if(type == CAMERA_ORTHOGRAPHIC)
		screentocamera = transform_inverse(transform_orthographic(nearclip, farclip));
	else
		screentocamera = transform_identity();
	
	Transform cameratoscreen = transform_inverse(screentocamera);

	rastertocamera = screentocamera * rastertoscreen;
	cameratoraster = screentoraster * cameratoscreen;

	cameratoworld = matrix;
	screentoworld = cameratoworld * screentocamera;
	rastertoworld = cameratoworld * rastertocamera;
	ndctoworld = rastertoworld * ndctoraster;

	/* note we recompose matrices instead of taking inverses of the above, this
	 * is needed to avoid inverting near degenerate matrices that happen due to
	 * precision issues with large scenes */
	worldtocamera = transform_inverse(matrix);
	worldtoscreen = cameratoscreen * worldtocamera;
	worldtondc = screentondc * worldtoscreen;
	worldtoraster = ndctoraster * worldtondc;

	/* differentials */
	if(type == CAMERA_ORTHOGRAPHIC) {
		dx = transform_direction(&rastertocamera, make_float3(1, 0, 0));
		dy = transform_direction(&rastertocamera, make_float3(0, 1, 0));
	}
	else if(type == CAMERA_PERSPECTIVE) {
		dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) -
		     transform_perspective(&rastertocamera, make_float3(0, 0, 0));
		dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) -
		     transform_perspective(&rastertocamera, make_float3(0, 0, 0));
	}
	else {
		dx = make_float3(0.0f, 0.0f, 0.0f);
		dy = make_float3(0.0f, 0.0f, 0.0f);
	}

	dx = transform_direction(&cameratoworld, dx);
	dy = transform_direction(&cameratoworld, dy);

	need_update = false;
	need_device_update = true;
	need_flags_update = true;
}
Example #9
0
static void create_mesh(Scene *scene,
                        Mesh *mesh,
                        BL::Mesh &b_mesh,
                        const vector<Shader *> &used_shaders,
                        bool subdivision = false,
                        bool subdivide_uvs = true)
{
  /* count vertices and faces */
  int numverts = b_mesh.vertices.length();
  int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length();
  int numtris = 0;
  int numcorners = 0;
  int numngons = 0;
  bool use_loop_normals = b_mesh.use_auto_smooth() &&
                          (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK);

  /* If no faces, create empty mesh. */
  if (numfaces == 0) {
    return;
  }

  if (!subdivision) {
    numtris = numfaces;
  }
  else {
    BL::Mesh::polygons_iterator p;
    for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
      numngons += (p->loop_total() == 4) ? 0 : 1;
      numcorners += p->loop_total();
    }
  }

  /* allocate memory */
  mesh->reserve_mesh(numverts, numtris);
  mesh->reserve_subd_faces(numfaces, numngons, numcorners);

  /* create vertex coordinates and normals */
  BL::Mesh::vertices_iterator v;
  for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
    mesh->add_vertex(get_float3(v->co()));

  AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
  Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
  float3 *N = attr_N->data_float3();

  for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
    *N = get_float3(v->normal());
  N = attr_N->data_float3();

  /* create generated coordinates from undeformed coordinates */
  const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.length() == 0) &&
                                    (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
  if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) {
    Attribute *attr = attributes.add(ATTR_STD_GENERATED);
    attr->flags |= ATTR_SUBDIVIDED;

    float3 loc, size;
    mesh_texture_space(b_mesh, loc, size);

    float3 *generated = attr->data_float3();
    size_t i = 0;

    for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) {
      generated[i++] = get_float3(v->undeformed_co()) * size - loc;
    }
  }

  /* create faces */
  if (!subdivision) {
    BL::Mesh::loop_triangles_iterator t;

    for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
      BL::MeshPolygon p = b_mesh.polygons[t->polygon_index()];
      int3 vi = get_int3(t->vertices());

      int shader = clamp(p.material_index(), 0, used_shaders.size() - 1);
      bool smooth = p.use_smooth() || use_loop_normals;

      if (use_loop_normals) {
        BL::Array<float, 9> loop_normals = t->split_normals();
        for (int i = 0; i < 3; i++) {
          N[vi[i]] = make_float3(
              loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);
        }
      }

      /* Create triangles.
       *
       * NOTE: Autosmooth is already taken care about.
       */
      mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
    }
  }
  else {
    BL::Mesh::polygons_iterator p;
    vector<int> vi;

    for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
      int n = p->loop_total();
      int shader = clamp(p->material_index(), 0, used_shaders.size() - 1);
      bool smooth = p->use_smooth() || use_loop_normals;

      vi.resize(n);
      for (int i = 0; i < n; i++) {
        /* NOTE: Autosmooth is already taken care about. */
        vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();
      }

      /* create subd faces */
      mesh->add_subd_face(&vi[0], n, shader, smooth);
    }
  }

  /* Create all needed attributes.
   * The calculate functions will check whether they're needed or not.
   */
  attr_create_pointiness(scene, mesh, b_mesh, subdivision);
  attr_create_vertex_color(scene, mesh, b_mesh, subdivision);

  if (subdivision) {
    attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs);
  }
  else {
    attr_create_uv_map(scene, mesh, b_mesh);
  }

  /* for volume objects, create a matrix to transform from object space to
   * mesh texture space. this does not work with deformations but that can
   * probably only be done well with a volume grid mapping of coordinates */
  if (mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
    Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
    Transform *tfm = attr->data_transform();

    float3 loc, size;
    mesh_texture_space(b_mesh, loc, size);

    *tfm = transform_translate(-loc) * transform_scale(size);
  }
}
Example #10
0
static void create_mesh(Scene *scene,
                        Mesh *mesh,
                        BL::Mesh& b_mesh,
                        const vector<uint>& used_shaders)
{
	/* count vertices and faces */
	int numverts = b_mesh.vertices.length();
	int numfaces = b_mesh.tessfaces.length();
	int numtris = 0;
	bool use_loop_normals = b_mesh.use_auto_smooth();

	BL::Mesh::vertices_iterator v;
	BL::Mesh::tessfaces_iterator f;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
		int4 vi = get_int4(f->vertices_raw());
		numtris += (vi[3] == 0)? 1: 2;
	}

	/* reserve memory */
	mesh->reserve(numverts, numtris, 0, 0);

	/* create vertex coordinates and normals */
	int i = 0;
	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i)
		mesh->verts[i] = get_float3(v->co());

	Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
	float3 *N = attr_N->data_float3();

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
		*N = get_float3(v->normal());
	N = attr_N->data_float3();

	/* create generated coordinates from undeformed coordinates */
	if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
		Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);

		float3 loc, size;
		mesh_texture_space(b_mesh, loc, size);

		float3 *generated = attr->data_float3();
		size_t i = 0;

		for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
			generated[i++] = get_float3(v->undeformed_co())*size - loc;
	}

	/* Create needed vertex attributes. */
	attr_create_pointiness(scene, mesh, b_mesh);

	/* create faces */
	vector<int> nverts(numfaces);
	vector<int> face_flags(numfaces, FACE_FLAG_NONE);
	int fi = 0, ti = 0;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
		int4 vi = get_int4(f->vertices_raw());
		int n = (vi[3] == 0)? 3: 4;
		int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
		int shader = used_shaders[mi];
		bool smooth = f->use_smooth() || use_loop_normals;

		/* split vertices if normal is different
		 *
		 * note all vertex attributes must have been set here so we can split
		 * and copy attributes in split_vertex without remapping later */
		if(use_loop_normals) {
			BL::Array<float, 12> loop_normals = f->split_normals();

			for(int i = 0; i < n; i++) {
				float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);

				if(N[vi[i]] != loop_N) {
					int new_vi = mesh->split_vertex(vi[i]);

					/* set new normal and vertex index */
					N = attr_N->data_float3();
					N[new_vi] = loop_N;
					vi[i] = new_vi;
				}
			}
		}

		/* create triangles */
		if(n == 4) {
			if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
			   is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
			{
				mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth);
				mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth);
				face_flags[fi] |= FACE_FLAG_DIVIDE_24;
			}
			else {
				mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
				mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth);
				face_flags[fi] |= FACE_FLAG_DIVIDE_13;
			}
		}
		else
			mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);

		nverts[fi] = n;
	}

	/* Create all needed attributes.
	 * The calculate functions will check whether they're needed or not.
	 */
	attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags);
	attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags);

	/* for volume objects, create a matrix to transform from object space to
	 * mesh texture space. this does not work with deformations but that can
	 * probably only be done well with a volume grid mapping of coordinates */
	if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
		Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
		Transform *tfm = attr->data_transform();

		float3 loc, size;
		mesh_texture_space(b_mesh, loc, size);

		*tfm = transform_translate(-loc)*transform_scale(size);
	}
}
Example #11
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);
		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()];
		/* 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;
		}

		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 OSL_LIBRARY_VERSION_CODE >= 10701
			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. */
#endif

			/* 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());
		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_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->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();
		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 ||
			                  b_engine.is_preview();

			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->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()];
		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();
		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();
		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;
	}
	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;

		/* Transformation form world space to texture space. */
		BL::Object b_ob(b_point_density_node.object());
		if(b_ob) {
			float3 loc, size;
			point_density_texture_space(b_point_density_node, loc, size);
			point_density->tfm =
			        transform_translate(-loc) * transform_scale(size) *
			        transform_inverse(get_transform(b_ob.matrix_world()));
		}

		/* TODO(sergey): Use more proper update flag. */
		if(true) {
			int settings = background ? 1 : 0;  /* 1 - render settings, 0 - vewport settings. */
			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;
	}

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

	return node;
}
Example #12
0
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
{
	/* count vertices and faces */
	int numverts = b_mesh.vertices.length();
	int numfaces = b_mesh.tessfaces.length();
	int numtris = 0;
	bool use_loop_normals = b_mesh.use_auto_smooth();

	BL::Mesh::vertices_iterator v;
	BL::Mesh::tessfaces_iterator f;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
		int4 vi = get_int4(f->vertices_raw());
		numtris += (vi[3] == 0)? 1: 2;
	}

	/* reserve memory */
	mesh->reserve(numverts, numtris, 0, 0);

	/* create vertex coordinates and normals */
	int i = 0;
	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++i)
		mesh->verts[i] = get_float3(v->co());

	Attribute *attr_N = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL);
	float3 *N = attr_N->data_float3();

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
		*N = get_float3(v->normal());
	N = attr_N->data_float3();

	/* create generated coordinates from undeformed coordinates */
	if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
		Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);

		float3 loc, size;
		mesh_texture_space(b_mesh, loc, size);

		float3 *generated = attr->data_float3();
		size_t i = 0;

		for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
			generated[i++] = get_float3(v->undeformed_co())*size - loc;
	}

	/* create faces */
	vector<int> nverts(numfaces);
	int fi = 0, ti = 0;

	for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
		int4 vi = get_int4(f->vertices_raw());
		int n = (vi[3] == 0)? 3: 4;
		int mi = clamp(f->material_index(), 0, used_shaders.size()-1);
		int shader = used_shaders[mi];
		bool smooth = f->use_smooth();

		/* split vertices if normal is different
		 *
		 * note all vertex attributes must have been set here so we can split
		 * and copy attributes in split_vertex without remapping later */
		if(use_loop_normals) {
			BL::Array<float, 12> loop_normals = f->split_normals();

			for(int i = 0; i < n; i++) {
				float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);

				if(N[vi[i]] != loop_N) {
					int new_vi = mesh->split_vertex(vi[i]);

					/* set new normal and vertex index */
					N = attr_N->data_float3();
					N[new_vi] = loop_N;
					vi[i] = new_vi;
				}
			}
		}

		/* create triangles */
		if(n == 4) {
			if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
				is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) {
				mesh->set_triangle(ti++, vi[0], vi[1], vi[3], shader, smooth);
				mesh->set_triangle(ti++, vi[2], vi[3], vi[1], shader, smooth);
			}
			else {
				mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);
				mesh->set_triangle(ti++, vi[0], vi[2], vi[3], shader, smooth);
			}
		}
		else
			mesh->set_triangle(ti++, vi[0], vi[1], vi[2], shader, smooth);

		nverts[fi] = n;
	}

	/* create vertex color attributes */
	{
		BL::Mesh::tessface_vertex_colors_iterator l;

		for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l) {
			if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
				continue;

			Attribute *attr = mesh->attributes.add(
				ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER);

			BL::MeshColorLayer::data_iterator c;
			float3 *fdata = attr->data_float3();
			size_t i = 0;

			for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
				fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
				fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
				fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));

				if(nverts[i] == 4) {
					fdata[3] = fdata[0];
					fdata[4] = fdata[2];
					fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
					fdata += 6;
				}
				else
					fdata += 3;
			}
		}
	}

	/* create uv map attributes */
	{
		BL::Mesh::tessface_uv_textures_iterator l;

		for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l) {
			bool active_render = l->active_render();
			AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
			ustring name = ustring(l->name().c_str());

			/* UV map */
			if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
				Attribute *attr;

				if(active_render)
					attr = mesh->attributes.add(std, name);
				else
					attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);

				BL::MeshTextureFaceLayer::data_iterator t;
				float3 *fdata = attr->data_float3();
				size_t i = 0;

				for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
					fdata[0] =  get_float3(t->uv1());
					fdata[1] =  get_float3(t->uv2());
					fdata[2] =  get_float3(t->uv3());
					fdata += 3;

					if(nverts[i] == 4) {
						fdata[0] =  get_float3(t->uv1());
						fdata[1] =  get_float3(t->uv3());
						fdata[2] =  get_float3(t->uv4());
						fdata += 3;
					}
				}
			}

			/* UV tangent */
			std = (active_render)? ATTR_STD_UV_TANGENT: ATTR_STD_NONE;
			name = ustring((string(l->name().c_str()) + ".tangent").c_str());

			if(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, std))) {
				std = (active_render)? ATTR_STD_UV_TANGENT_SIGN: ATTR_STD_NONE;
				name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str());
				bool need_sign = (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std));

				mikk_compute_tangents(b_mesh, *l, mesh, nverts, need_sign, active_render);
			}
		}
	}

	/* for volume objects, create a matrix to transform from object space to
	 * mesh texture space. this does not work with deformations but that can
	 * probably only be done well with a volume grid mapping of coordinates */
	if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
		Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
		Transform *tfm = attr->data_transform();

		float3 loc, size;
		mesh_texture_space(b_mesh, loc, size);

		*tfm = transform_translate(-loc)*transform_scale(size);
	}
}
Example #13
0
static void create_mesh(Scene *scene,
                        Mesh *mesh,
                        BL::Mesh& b_mesh,
                        const vector<Shader*>& used_shaders,
                        bool subdivision=false,
                        bool subdivide_uvs=true)
{
	/* count vertices and faces */
	int numverts = b_mesh.vertices.length();
	int numfaces = (!subdivision) ? b_mesh.tessfaces.length() : b_mesh.polygons.length();
	int numtris = 0;
	int numcorners = 0;
	int numngons = 0;
	bool use_loop_normals = b_mesh.use_auto_smooth() && (mesh->subdivision_type != Mesh::SUBDIVISION_CATMULL_CLARK);

	BL::Mesh::vertices_iterator v;
	BL::Mesh::tessfaces_iterator f;
	BL::Mesh::polygons_iterator p;

	if(!subdivision) {
		for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f) {
			int4 vi = get_int4(f->vertices_raw());
			numtris += (vi[3] == 0)? 1: 2;
		}
	}
	else {
		for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
			numngons += (p->loop_total() == 4)? 0: 1;
			numcorners += p->loop_total();
		}
	}

	/* allocate memory */
	mesh->reserve_mesh(numverts, numtris);
	mesh->reserve_subd_faces(numfaces, numngons, numcorners);

	/* create vertex coordinates and normals */
	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
		mesh->add_vertex(get_float3(v->co()));

	AttributeSet& attributes = (subdivision)? mesh->subd_attributes: mesh->attributes;
	Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
	float3 *N = attr_N->data_float3();

	for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
		*N = get_float3(v->normal());
	N = attr_N->data_float3();

	/* create generated coordinates from undeformed coordinates */
	if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
		Attribute *attr = attributes.add(ATTR_STD_GENERATED);
		attr->flags |= ATTR_SUBDIVIDED;

		float3 loc, size;
		mesh_texture_space(b_mesh, loc, size);

		float3 *generated = attr->data_float3();
		size_t i = 0;

		for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
			generated[i++] = get_float3(v->undeformed_co())*size - loc;
	}

	/* Create needed vertex attributes. */
	attr_create_pointiness(scene, mesh, b_mesh, subdivision);

	/* create faces */
	vector<int> nverts(numfaces);
	vector<int> face_flags(numfaces, FACE_FLAG_NONE);
	int fi = 0;

	if(!subdivision) {
		for(b_mesh.tessfaces.begin(f); f != b_mesh.tessfaces.end(); ++f, ++fi) {
			int4 vi = get_int4(f->vertices_raw());
			int n = (vi[3] == 0)? 3: 4;
			int shader = clamp(f->material_index(), 0, used_shaders.size()-1);
			bool smooth = f->use_smooth() || use_loop_normals;

			/* split vertices if normal is different
			 *
			 * note all vertex attributes must have been set here so we can split
			 * and copy attributes in split_vertex without remapping later */
			if(use_loop_normals) {
				BL::Array<float, 12> loop_normals = f->split_normals();

				for(int i = 0; i < n; i++) {
					float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]);

					if(N[vi[i]] != loop_N) {
						int new_vi = mesh->split_vertex(vi[i]);

						/* set new normal and vertex index */
						N = attr_N->data_float3();
						N[new_vi] = loop_N;
						vi[i] = new_vi;
					}
				}
			}

			/* create triangles */
			if(n == 4) {
				if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) ||
				   is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])))
				{
					mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth);
					mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth);
					face_flags[fi] |= FACE_FLAG_DIVIDE_24;
				}
				else {
					mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
					mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
					face_flags[fi] |= FACE_FLAG_DIVIDE_13;
				}
			}
			else {
				mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
			}

			nverts[fi] = n;
		}
	}
	else {
		vector<int> vi;

		for(b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
			int n = p->loop_total();
			int shader = clamp(p->material_index(), 0, used_shaders.size()-1);
			bool smooth = p->use_smooth() || use_loop_normals;

			vi.reserve(n);
			for(int i = 0; i < n; i++) {
				vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index();

				/* split vertices if normal is different
				 *
				 * note all vertex attributes must have been set here so we can split
				 * and copy attributes in split_vertex without remapping later */
				if(use_loop_normals) {
					float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal());

					if(N[vi[i]] != loop_N) {
						int new_vi = mesh->split_vertex(vi[i]);

						/* set new normal and vertex index */
						N = attr_N->data_float3();
						N[new_vi] = loop_N;
						vi[i] = new_vi;
					}
				}
			}

			/* create subd faces */
			mesh->add_subd_face(&vi[0], n, shader, smooth);
		}
	}

	/* Create all needed attributes.
	 * The calculate functions will check whether they're needed or not.
	 */
	attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision);
	attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs);

	/* for volume objects, create a matrix to transform from object space to
	 * mesh texture space. this does not work with deformations but that can
	 * probably only be done well with a volume grid mapping of coordinates */
	if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
		Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
		Transform *tfm = attr->data_transform();

		float3 loc, size;
		mesh_texture_space(b_mesh, loc, size);

		*tfm = transform_translate(-loc)*transform_scale(size);
	}
}
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->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)) {
		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 = (NodeMix)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_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 RGBToBWNode();
	}
	else if(b_node.is_a(&RNA_ShaderNodeMath)) {
		BL::ShaderNodeMath b_math_node(b_node);
		MathNode *math = new MathNode();
		math->type = (NodeMath)b_math_node.operation();
		math->use_clamp = b_math_node.use_clamp();
		node = math;
	}
	else if(b_node.is_a(&RNA_ShaderNodeVectorMath)) {
		BL::ShaderNodeVectorMath b_vector_math_node(b_node);
		VectorMathNode *vmath = new VectorMathNode();
		vmath->type = (NodeVectorMath)b_vector_math_node.operation();
		node = vmath;
	}
	else if(b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
		BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
		VectorTransformNode *vtransform = new VectorTransformNode();
		vtransform->type = (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)) {
		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 = 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_ASHIKHMIN_SHIRLEY:
				aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID;
				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->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)) {
		BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
		GlossyBsdfNode *glossy = new GlossyBsdfNode();
		
		switch(b_glossy_node.distribution()) {
			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_ANISO_ID;
				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 = 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;
		}
		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 = CLOSURE_BSDF_REFRACTION_ID;
				break;
			case BL::ShaderNodeBsdfRefraction::distribution_BECKMANN:
				refraction->distribution = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
				break;
			case BL::ShaderNodeBsdfRefraction::distribution_GGX:
				refraction->distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
				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 = CLOSURE_BSDF_DIFFUSE_TOON_ID;
				break;
			case BL::ShaderNodeBsdfToon::component_GLOSSY:
				toon->component = CLOSURE_BSDF_GLOSSY_TOON_ID;
				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 = CLOSURE_BSDF_HAIR_REFLECTION_ID;
				break;
			case BL::ShaderNodeBsdfHair::component_Transmission:
				hair->component = CLOSURE_BSDF_HAIR_TRANSMISSION_ID;
				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);

			OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager;
			string bytecode_hash = b_script_node.bytecode_hash();

			if(!bytecode_hash.empty()) {
				node = manager->osl_node("", bytecode_hash, b_script_node.bytecode());
			}
			else {
				string absolute_filepath = blender_absolute_path(b_data, b_ntree, b_script_node.filepath());
				node = manager->osl_node(absolute_filepath, "");
			}
		}
#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.string(),
				        image->builtin_data,
				        get_image_interpolation(b_image_node),
				        get_image_extension(b_image_node));
			}
		}
		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();
		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->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->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)) {
		BL::ShaderNodeTexGradient b_gradient_node(b_node);
		GradientTextureNode *gradient = new GradientTextureNode();
		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)) {
		BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
		VoronoiTextureNode *voronoi = new VoronoiTextureNode();
		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)) {
		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 = (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)) {
		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 = (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)) {
		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 = (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();
		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 = (NodeNormalMapSpace)b_normal_map_node.space();
		nmap->attribute = b_normal_map_node.uv_map();
		node = nmap;
	}
	else if(b_node.is_a(&RNA_ShaderNodeTangent)) {
		BL::ShaderNodeTangent b_tangent_node(b_node);
		TangentNode *tangent = new TangentNode();
		tangent->direction_type = (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);
		}
		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;
}