Exemplo n.º 1
0
double GodRaysSampler::getCachedLight(const Vector3 &location) {
    double x = location.x - bounds->getStart().x;
    double y = location.y - bounds->getStart().y;
    double z = location.z - bounds->getStart().z;

    int ix = floor_to_int(x / sampling_step);
    int iy = floor_to_int(y / sampling_step);
    int iz = floor_to_int(z / sampling_step);

    // Check cache limits
    if (ix < 0 || ix >= samples_x - 1 || iy < 0 || iy >= samples_y - 1 || iz < 0 || iz >= samples_z - 1) {
        return 1.0;
    }

    // Hit cache
    double p[8] = {getCache(ix, iy, iz),
                   getCache(ix + 1, iy, iz),
                   getCache(ix + 1, iy + 1, iz),
                   getCache(ix, iy + 1, iz),
                   getCache(ix, iy, iz + 1),
                   getCache(ix + 1, iy, iz + 1),
                   getCache(ix + 1, iy + 1, iz + 1),
                   getCache(ix, iy + 1, iz + 1)};
    return Interpolation::trilinear(p, (x - sampling_step * double(ix)) / sampling_step,
                                    (y - sampling_step * double(iy)) / sampling_step,
                                    (z - sampling_step * double(iz)) / sampling_step);
}
Exemplo n.º 2
0
void PaintedGridBrush::getArea(double x, double y, int *xstart, int *ystart, int *xend, int *yend) const {
    double s = smoothed_size + hard_radius;

    *xstart = floor_to_int(x - s);
    *xend = ceil_to_int(x + s);
    *ystart = floor_to_int(y - s);
    *yend = ceil_to_int(y + s);
}
Exemplo n.º 3
0
	SphericalHarmonics3 IrradianceVolume::sample( const Vector3& pos ) const
	{
		Vector3 rel_pos = pos;

		rel_pos -= m_position;
		rel_pos += m_dimensions*0.5f;
		rel_pos -= m_cell_size*0.5f;
		rel_pos /= m_cell_size;

		int32 x0 = floor_to_int(rel_pos.x);
		int32 y0 = floor_to_int(rel_pos.y);
		int32 z0 = floor_to_int(rel_pos.z);
		int32 x1 = x0+1;
		int32 y1 = y0+1;
		int32 z1 = z0+1;
		
		float ax = rel_pos.x - float(x0);
		float ay = rel_pos.y - float(y0);
		float az = rel_pos.z - float(z0);

		if(x0<0) {x0=0; x1=x0; ax=0;}
		if(y0<0) {y0=0; y1=y0; ay=0;}
		if(z0<0) {z0=0; z1=z0; az=0;}
		if(x1>=int32(m_width))  {x1=int32(m_width)-1;  x0=x1; ax=1;}
		if(y1>=int32(m_height)) {y1=int32(m_height)-1; y0=y1; ay=1;}
		if(z1>=int32(m_depth))  {z1=int32(m_depth)-1;  z0=z1; az=1;}
				
		const SphericalHarmonics3& sh000 = cell(x0,y0,z0);
		const SphericalHarmonics3& sh100 = cell(x1,y0,z0);
		const SphericalHarmonics3& sh010 = cell(x0,y1,z0);
		const SphericalHarmonics3& sh110 = cell(x1,y1,z0);

		const SphericalHarmonics3& sh001 = cell(x0,y0,z1);
		const SphericalHarmonics3& sh101 = cell(x1,y0,z1);
		const SphericalHarmonics3& sh011 = cell(x0,y1,z1);
		const SphericalHarmonics3& sh111 = cell(x1,y1,z1);

		SphericalHarmonics3 top0 = sh000; top0.lerp(sh100, ax);
		SphericalHarmonics3 top1 = sh010; top1.lerp(sh110, ax);
		SphericalHarmonics3 top  = top0; top.lerp(top1, ay);

		SphericalHarmonics3 bot0 = sh001; bot0.lerp(sh101, ax);
		SphericalHarmonics3 bot1 = sh011; bot1.lerp(sh111, ax);
		SphericalHarmonics3 bot  = bot0; bot.lerp(bot1, ay);

		SphericalHarmonics3 res = top; res.lerp(bot, az);
		
		return res;
	}
Exemplo n.º 4
0
Color Texture3D::getLinear(double dx, double dy, double dz) const {
    if (dx < 0.0)
        dx = 0.0;
    if (dx > 1.0)
        dx = 1.0;
    if (dy < 0.0)
        dy = 0.0;
    if (dy > 1.0)
        dy = 1.0;
    if (dz < 0.0)
        dz = 0.0;
    if (dz > 1.0)
        dz = 1.0;

    dx *= to_double(this->xsize - 1);
    dy *= to_double(this->ysize - 1);
    dz *= to_double(this->zsize - 1);

    int ix = floor_to_int(dx);
    if (ix == this->xsize - 1) {
        ix--;
    }
    int iy = floor_to_int(dy);
    if (iy == this->ysize - 1) {
        iy--;
    }
    int iz = floor_to_int(dz);
    if (iz == this->zsize - 1) {
        iz--;
    }

    dx -= to_double(ix);
    dy -= to_double(iy);
    dz -= to_double(iz);

    Color *data = this->data + iz * this->xsize * this->ysize + iy * this->xsize + ix;

    Color cx1 = data->lerp(*(data + 1), dx);
    Color cx2 = (data + this->xsize)->lerp(*(data + this->xsize + 1), dx);
    Color cy1 = cx1.lerp(cx2, dy);

    data += this->xsize * this->ysize;
    cx1 = data->lerp(*(data + 1), dx);
    cx2 = (data + this->xsize)->lerp(*(data + this->xsize + 1), dx);
    Color cy2 = cx1.lerp(cx2, dy);

    return cy1.lerp(cy2, dz);
}
Exemplo n.º 5
0
void Rasterizer::pushScanPoint(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point) {
    point->x = floor_to_int(point->pixel.x);
    point->y = floor_to_int(point->pixel.y);

    if (point->x < 0 || point->x >= canvas->getWidth()) {
        // Point outside scanline range
        return;
    } else if (scanlines->right < 0) {
        // First point pushed
        scanlines->left = point->x;
        scanlines->right = point->x;
        scanlines->up[point->x] = *point;
        scanlines->down[point->x] = *point;
    } else if (point->x > scanlines->right) {
        // Grow scanlines to right
        for (int x = scanlines->right + 1; x < point->x; x++) {
            scanlines->up[x].y = -1;
            scanlines->down[x].y = canvas->getHeight();
        }
        scanlines->right = point->x;
        scanlines->up[point->x] = *point;
        scanlines->down[point->x] = *point;
    } else if (point->x < scanlines->left) {
        // Grow scanlines to left
        for (int x = point->x + 1; x < scanlines->left; x++) {
            scanlines->up[x].y = -1;
            scanlines->down[x].y = canvas->getHeight();
        }
        scanlines->left = point->x;
        scanlines->up[point->x] = *point;
        scanlines->down[point->x] = *point;
    } else {
        // Expand existing scanline
        if (point->y > scanlines->up[point->x].y) {
            scanlines->up[point->x] = *point;
        }
        if (point->y < scanlines->down[point->x].y) {
            scanlines->down[point->x] = *point;
        }
    }
}
Exemplo n.º 6
0
bool
Warp::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc_, ProgressCallback *cb)const
{
	Point src_tl=param_src_tl.get(Point());
	Point src_br=param_src_br.get(Point());
	Point dest_tl=param_dest_tl.get(Point());
	Point dest_tr=param_dest_tr.get(Point());
	Point dest_bl=param_dest_bl.get(Point());
	Point dest_br=param_dest_br.get(Point());
	Real horizon=param_horizon.get(Real());
	bool clip=param_clip.get(bool());

	SuperCallback stageone(cb,0,9000,10000);
	SuperCallback stagetwo(cb,9000,10000,10000);
	
	
	RendDesc renddesc(renddesc_);
	// Untransform the render desc
	if(!cairo_renddesc_untransform(cr, renddesc))
		return false;
	
	Real pw=(renddesc.get_w())/(renddesc.get_br()[0]-renddesc.get_tl()[0]);
	Real ph=(renddesc.get_h())/(renddesc.get_br()[1]-renddesc.get_tl()[1]);
	
	if(cb && !cb->amount_complete(0,10000))
		return false;
	
	Point tl(renddesc.get_tl());
	Point br(renddesc.get_br());
	
	Rect bounding_rect;
	
	Rect render_rect(tl,br);
	Rect clip_rect(Rect::full_plane());
	Rect dest_rect(dest_tl,dest_br); dest_rect.expand(dest_tr).expand(dest_bl);
	
	Real zoom_factor(1.0);
	
	// Quick exclusion clip, if necessary
	if(clip && !intersect(render_rect,dest_rect))
	{
		cairo_save(cr);
		cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
		cairo_paint(cr);
		cairo_restore(cr);
		return true;
	}
	
	{
		Rect other(render_rect);
		if(clip)
			other&=dest_rect;
		
		Point min(other.get_min());
		Point max(other.get_max());
		
		bool init_point_set=false;
		
		// Point trans_point[4];
		Point p;
		// Real trans_z[4];
		Real z,minz(10000000000000.0f),maxz(0);
		
		//! \todo checking the 4 corners for 0<=z<horizon*2 and using
		//! only 4 corners which satisfy this condition isn't the
		//! right thing to do.  It's possible that none of the 4
		//! corners fall within that range, and yet content of the
		//! tile does.
		p=transform_forward(min);
		z=transform_backward_z(p);
		if(z>0 && z<horizon*2)
		{
			if(init_point_set)
				bounding_rect.expand(p);
			else
				bounding_rect=Rect(p);
			init_point_set=true;
			maxz=std::max(maxz,z);
			minz=std::min(minz,z);
		}
		
		p=transform_forward(max);
		z=transform_backward_z(p);
		if(z>0 && z<horizon*2)
		{
			if(init_point_set)
				bounding_rect.expand(p);
			else
				bounding_rect=Rect(p);
			init_point_set=true;
			maxz=std::max(maxz,z);
			minz=std::min(minz,z);
		}
		
		swap(min[1],max[1]);
		
		p=transform_forward(min);
		z=transform_backward_z(p);
		if(z>0 && z<horizon*2)
		{
			if(init_point_set)
				bounding_rect.expand(p);
			else
				bounding_rect=Rect(p);
			init_point_set=true;
			maxz=std::max(maxz,z);
			minz=std::min(minz,z);
		}
		
		p=transform_forward(max);
		z=transform_backward_z(p);
		if(z>0 && z<horizon*2)
		{
			if(init_point_set)
				bounding_rect.expand(p);
			else
				bounding_rect=Rect(p);
			init_point_set=true;
			maxz=std::max(maxz,z);
			minz=std::min(minz,z);
		}
		
		if(!init_point_set)
		{
			cairo_save(cr);
			cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
			cairo_paint(cr);
			cairo_restore(cr);
			return true;
		}
		zoom_factor=(1+(maxz-minz));
		
	}
	
#ifdef ACCEL_WARP_IS_BROKEN
	return Layer::accelerated_cairorender(context,cr,quality,renddesc, cb);
#else
	
	/*swap(tl[1],br[1]);
	 bounding_rect
	 .expand(transform_forward(tl))
	 .expand(transform_forward(br))
	 ;
	 swap(tl[1],br[1]);*/
	
	//synfig::warning("given window: [%f,%f]-[%f,%f] %dx%d",tl[0],tl[1],br[0],br[1],renddesc.get_w(),renddesc.get_h());
	//synfig::warning("Projected: [%f,%f]-[%f,%f]",bounding_rect.get_min()[0],bounding_rect.get_min()[1],bounding_rect.get_max()[0],bounding_rect.get_max()[1]);
	
	// If we are clipping, then go ahead and clip to the
	// source rectangle
	if(clip)
		clip_rect&=Rect(src_tl,src_br);
	
	// Bound ourselves to the bounding rectangle of
	// what is under us
	clip_rect&=context.get_full_bounding_rect();//.expand_x(abs(zoom_factor/pw)).expand_y(abs(zoom_factor/ph));
	
	bounding_rect&=clip_rect;
	
	Point min_point(bounding_rect.get_min());
	Point max_point(bounding_rect.get_max());
	
	// we're going to divide by the difference of these pairs soon;
	// if they're the same, we'll be dividing by zero, and we don't
	// want to do that!
	// \todo what should we do in this case?
	if (min_point[0] == max_point[0]) max_point[0] += 0.001;
	if (min_point[1] == max_point[1]) max_point[1] += 0.001;
	
	if(tl[0]>br[0])
	{
		tl[0]=max_point[0];
		br[0]=min_point[0];
	}
	else
	{
		br[0]=max_point[0];
		tl[0]=min_point[0];
	}
	if(tl[1]>br[1])
	{
		tl[1]=max_point[1];
		br[1]=min_point[1];
	}
	else
	{
		br[1]=max_point[1];
		tl[1]=min_point[1];
	}
	
	const int tmp_d(max(renddesc.get_w(),renddesc.get_h()));
	Real src_pw=(tmp_d*zoom_factor)/(br[0]-tl[0]);
	Real src_ph=(tmp_d*zoom_factor)/(br[1]-tl[1]);
	
	
	RendDesc desc(renddesc);
	desc.clear_flags();
	//desc.set_flags(RendDesc::PX_ASPECT);
	desc.set_tl(tl);
	desc.set_br(br);
	desc.set_wh(ceil_to_int(src_pw*(br[0]-tl[0])),ceil_to_int(src_ph*(br[1]-tl[1])));
	
	//synfig::warning("surface to render: [%f,%f]-[%f,%f] %dx%d",desc.get_tl()[0],desc.get_tl()[1],desc.get_br()[0],desc.get_br()[1],desc.get_w(),desc.get_h());
	if(desc.get_w()==0 && desc.get_h()==0)
	{
		cairo_save(cr);
		cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
		cairo_paint(cr);
		cairo_restore(cr);
		return true;
	}
	
	// Recalculate the pixel widths for the src renddesc
	src_pw=(desc.get_w())/(desc.get_br()[0]-desc.get_tl()[0]);
	src_ph=(desc.get_h())/(desc.get_br()[1]-desc.get_tl()[1]);
	
	cairo_surface_t* source=cairo_surface_create_similar(cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, desc.get_w(),desc.get_h());
	cairo_surface_t* surface=cairo_surface_create_similar(cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA,renddesc.get_w(), renddesc.get_h());
	cairo_t* subcr=cairo_create(source);
	cairo_scale(subcr, 1/desc.get_pw(), 1/desc.get_ph());
	cairo_translate(subcr, -desc.get_tl()[0], -desc.get_tl()[1]);

	if(!context.accelerated_cairorender(subcr,quality,desc,&stageone))
		return false;
	
	cairo_destroy(subcr);
		
	int surfacew, surfaceh, sourcew, sourceh;
	
	CairoSurface csurface(surface);
	CairoSurface csource(source);
	
	csurface.map_cairo_image();
	csource.map_cairo_image();
	
	surfacew=csurface.get_w();
	surfaceh=csurface.get_h();
	sourcew=csource.get_w();
	sourceh=csource.get_h();
	
	CairoSurface::pen pen(csurface.begin());
	
	// Do the warp
	{
		int x,y;
		float u,v;
		Point point,tmp;
		for(y=0,point[1]=renddesc.get_tl()[1];y<surfaceh;y++,pen.inc_y(),pen.dec_x(x),point[1]+=1.0/ph)
		{
			for(x=0,point[0]=renddesc.get_tl()[0];x<surfacew;x++,pen.inc_x(),point[0]+=1.0/pw)
			{
				tmp=transform_forward(point);
				const float z(transform_backward_z(tmp));
				if(!clip_rect.is_inside(tmp) || !(z>0 && z<horizon))
				{
					csurface[y][x]=Color::alpha();
					continue;
				}
				
				u=(tmp[0]-tl[0])*src_pw;
				v=(tmp[1]-tl[1])*src_ph;
				
				if(u<0 || v<0 || u>=sourcew || v>=sourceh || isnan(u) || isnan(v))
					csurface[y][x]=context.get_cairocolor(tmp);
				else
				{
					// CUBIC
					if(quality<=4)
						csurface[y][x]=csource.cubic_sample_cooked(u,v);
					// INTEPOLATION_LINEAR
					else if(quality<=6)
						csurface[y][x]=csource.linear_sample_cooked(u,v);
					else
						// NEAREST_NEIGHBOR
						csurface[y][x]=csource[floor_to_int(v)][floor_to_int(u)];
				}
			}
			if((y&31)==0 && cb)
			{
				if(!stagetwo.amount_complete(y,surfaceh))
					return false;
			}
		}
	}
	
#endif
	
	if(cb && !cb->amount_complete(10000,10000)) return false;
	
	csurface.unmap_cairo_image();
	csource.unmap_cairo_image();
	cairo_surface_destroy(source);
	
	cairo_save(cr);
	
	cairo_translate(cr, renddesc.get_tl()[0], renddesc.get_tl()[1]);
	cairo_scale(cr, renddesc.get_pw(), renddesc.get_ph());
	cairo_set_source_surface(cr, surface, 0, 0);
	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
	cairo_paint(cr);
	
	cairo_restore(cr);
	
	cairo_surface_destroy(surface);
	return true;
}
Exemplo n.º 7
0
bool
CurveWarp::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc_, ProgressCallback *cb)const
{
	Point start_point=param_start_point.get(Point());
	Point end_point=param_end_point.get(Point());

	SuperCallback stageone(cb,0,9000,10000);
	SuperCallback stagetwo(cb,9000,10000,10000);
	
	RendDesc renddesc(renddesc_);
	// Untransform the render desc
	if(!cairo_renddesc_untransform(cr, renddesc))
		return false;
	
	int x,y;
	
	const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
	Point tl(renddesc.get_tl());
	Point br(renddesc.get_br());
	const int w(renddesc.get_w());
	const int h(renddesc.get_h());
	
	// find a bounding rectangle for the context we need to render
	// todo: find a better way of doing this - this way doesn't work
	Rect src_rect(transform(tl));
	Point pos1, pos2;
	Real dist, along;
	Real min_dist(999999), max_dist(-999999), min_along(999999), max_along(-999999);
	
#define UPDATE_DIST \
if (dist < min_dist) min_dist = dist; \
if (dist > max_dist) max_dist = dist; \
if (along < min_along) min_along = along; \
if (along > max_along) max_along = along
	
	// look along the top and bottom edges
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < w; x++, pos1[0] += pw, pos2[0] += pw)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}
	
	// look along the left and right edges
	pos1[0] = tl[0]; pos2[0] = br[0]; pos1[1] = pos2[1] = tl[1];
	for (y = 0; y < h; y++, pos1[1] += ph, pos2[1] += ph)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}
	
	// look along the diagonals
	const int max_wh(std::max(w,h));
	const Real inc_x((br[0]-tl[0])/max_wh),inc_y((br[1]-tl[1])/max_wh);
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < max_wh; x++, pos1[0] += inc_x, pos2[0] = pos1[0], pos1[1]+=inc_y, pos2[1]-=inc_y)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}
	
#if 0
	// look at each blinepoint
	std::vector<synfig::BLinePoint>::const_iterator iter;
	for (iter=bline.begin(); iter!=bline.end(); iter++)
		src_rect.expand(transform(iter->get_vertex()+origin, &dist, &along)); UPDATE_DIST;
#endif
	
	Point src_tl(src_rect.get_min());
	Point src_br(src_rect.get_max());
	
	Vector ab((end_point - start_point).norm());
	Angle::tan ab_angle(ab[1], ab[0]);
	
	Real used_length = max_along - min_along;
	Real render_width = max_dist - min_dist;
	
	int src_w = (abs(used_length*Angle::cos(ab_angle).get()) +
				 abs(render_width*Angle::sin(ab_angle).get())) / abs(pw);
	int src_h = (abs(used_length*Angle::sin(ab_angle).get()) +
				 abs(render_width*Angle::cos(ab_angle).get())) / abs(ph);
	
	Real src_pw((src_br[0] - src_tl[0]) / src_w);
	Real src_ph((src_br[1] - src_tl[1]) / src_h);
	
	if (src_pw > abs(pw))
	{
		src_w = int((src_br[0] - src_tl[0]) / abs(pw));
		src_pw = (src_br[0] - src_tl[0]) / src_w;
	}
	
	if (src_ph > abs(ph))
	{
		src_h = int((src_br[1] - src_tl[1]) / abs(ph));
		src_ph = (src_br[1] - src_tl[1]) / src_h;
	}
	
#define MAXPIX 10000
	if (src_w > MAXPIX) src_w = MAXPIX;
	if (src_h > MAXPIX) src_h = MAXPIX;
	
	// this is an attempt to remove artifacts around tile edges - the
	// cubic interpolation uses at most 2 pixels either side of the
	// target pixel, so add an extra 2 pixels around the tile on all
	// sides
	src_tl -= (Point(src_pw,src_ph)*2);
	src_br += (Point(src_pw,src_ph)*2);
	src_w += 4;
	src_h += 4;
	src_pw = (src_br[0] - src_tl[0]) / src_w;
	src_ph = (src_br[1] - src_tl[1]) / src_h;
	
	// set up a renddesc for the context to render
	RendDesc src_desc(renddesc);
	//src_desc.clear_flags();
	src_desc.set_tl(src_tl);
	src_desc.set_br(src_br);
	src_desc.set_wh(src_w, src_h);
	
	
	// New expanded renddesc values
	const double wpw=src_desc.get_pw();
	const double wph=src_desc.get_ph();
	const double wtlx=src_desc.get_tl()[0];
	const double wtly=src_desc.get_tl()[1];

	// render the context onto a new surface
	
	cairo_surface_t* csource, *cresult;
	csource=cairo_surface_create_similar(cairo_get_target(cr),CAIRO_CONTENT_COLOR_ALPHA, src_w, src_h);
	cresult=cairo_surface_create_similar(cairo_get_target(cr),CAIRO_CONTENT_COLOR_ALPHA, w, h);
	cairo_t *subcr=cairo_create(csource);
	cairo_scale(subcr, 1/wpw, 1/wph);
	cairo_translate(subcr, -wtlx, -wtly);

	if(!context.accelerated_cairorender(subcr,quality,src_desc,&stageone))
		return false;
	// don't needed anymore
	cairo_destroy(subcr);
	//access to pixels
	CairoSurface source(csource);
	source.map_cairo_image();
	
	CairoSurface result(cresult);
	result.map_cairo_image();
	float u,v;
	Point pos, tmp;
		
	if(quality<=4)				// CUBIC
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
				else
					result[y][x]=source.cubic_sample_cooked(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else if (quality<=6)		// INTERPOLATION_LINEAR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
				else
					result[y][x]=source.linear_sample_cooked(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else						// NEAREST_NEIGHBOR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					result[y][x]=CairoColor(context.get_color(tmp)).premult_alpha();
				else
					result[y][x]=source[floor_to_int(v)][floor_to_int(u)];
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	
	result.unmap_cairo_image();
	source.unmap_cairo_image();
	
	cairo_surface_destroy(csource);
	// Now paint it on the context
	cairo_save(cr);
	
	cairo_translate(cr, tl[0], tl[1]);
	cairo_scale(cr, pw, ph);
	cairo_set_source_surface(cr, cresult, 0, 0);
	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
	cairo_paint(cr);
	
	cairo_restore(cr);
	
	cairo_surface_destroy(cresult);
	
	// Mark our progress as finished
	if(cb && !cb->amount_complete(10000,10000))
		return false;
	
	return true;
}
Exemplo n.º 8
0
bool
CurveWarp::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
	Point start_point=param_start_point.get(Point());
	Point end_point=param_end_point.get(Point());

	SuperCallback stageone(cb,0,9000,10000);
	SuperCallback stagetwo(cb,9000,10000,10000);

	int x,y;

	const Real pw(renddesc.get_pw()),ph(renddesc.get_ph());
	Point tl(renddesc.get_tl());
	Point br(renddesc.get_br());
	const int w(renddesc.get_w());
	const int h(renddesc.get_h());

	// find a bounding rectangle for the context we need to render
	// todo: find a better way of doing this - this way doesn't work
	Rect src_rect(transform(tl));
	Point pos1, pos2;
	Real dist, along;
	Real min_dist(999999), max_dist(-999999), min_along(999999), max_along(-999999);

#define UPDATE_DIST \
	if (dist < min_dist) min_dist = dist; \
	if (dist > max_dist) max_dist = dist; \
	if (along < min_along) min_along = along; \
	if (along > max_along) max_along = along

	// look along the top and bottom edges
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < w; x++, pos1[0] += pw, pos2[0] += pw)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}

	// look along the left and right edges
	pos1[0] = tl[0]; pos2[0] = br[0]; pos1[1] = pos2[1] = tl[1];
	for (y = 0; y < h; y++, pos1[1] += ph, pos2[1] += ph)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}

	// look along the diagonals
	const int max_wh(std::max(w,h));
	const Real inc_x((br[0]-tl[0])/max_wh),inc_y((br[1]-tl[1])/max_wh);
	pos1[0] = pos2[0] = tl[0]; pos1[1] = tl[1]; pos2[1] = br[1];
	for (x = 0; x < max_wh; x++, pos1[0] += inc_x, pos2[0] = pos1[0], pos1[1]+=inc_y, pos2[1]-=inc_y)
	{
		src_rect.expand(transform(pos1, &dist, &along)); UPDATE_DIST;
		src_rect.expand(transform(pos2, &dist, &along)); UPDATE_DIST;
	}

#if 0
	// look at each blinepoint
	std::vector<synfig::BLinePoint>::const_iterator iter;
	for (iter=bline.begin(); iter!=bline.end(); iter++)
		src_rect.expand(transform(iter->get_vertex()+origin, &dist, &along)); UPDATE_DIST;
#endif

	Point src_tl(src_rect.get_min());
	Point src_br(src_rect.get_max());

	Vector ab((end_point - start_point).norm());
	Angle::tan ab_angle(ab[1], ab[0]);

	Real used_length = max_along - min_along;
	Real render_width = max_dist - min_dist;

	int src_w = (abs(used_length*Angle::cos(ab_angle).get()) +
				 abs(render_width*Angle::sin(ab_angle).get())) / abs(pw);
	int src_h = (abs(used_length*Angle::sin(ab_angle).get()) +
				 abs(render_width*Angle::cos(ab_angle).get())) / abs(ph);

	Real src_pw((src_br[0] - src_tl[0]) / src_w);
	Real src_ph((src_br[1] - src_tl[1]) / src_h);

	if (src_pw > abs(pw))
	{
		src_w = int((src_br[0] - src_tl[0]) / abs(pw));
		src_pw = (src_br[0] - src_tl[0]) / src_w;
	}

	if (src_ph > abs(ph))
	{
		src_h = int((src_br[1] - src_tl[1]) / abs(ph));
		src_ph = (src_br[1] - src_tl[1]) / src_h;
	}

#define MAXPIX 10000
	if (src_w > MAXPIX) src_w = MAXPIX;
	if (src_h > MAXPIX) src_h = MAXPIX;

	// this is an attempt to remove artifacts around tile edges - the
	// cubic interpolation uses at most 2 pixels either side of the
	// target pixel, so add an extra 2 pixels around the tile on all
	// sides
	src_tl -= (Point(src_pw,src_ph)*2);
	src_br += (Point(src_pw,src_ph)*2);
	src_w += 4;
	src_h += 4;
	src_pw = (src_br[0] - src_tl[0]) / src_w;
	src_ph = (src_br[1] - src_tl[1]) / src_h;

	// set up a renddesc for the context to render
	RendDesc src_desc(renddesc);
	src_desc.clear_flags();
	src_desc.set_tl(src_tl);
	src_desc.set_br(src_br);
	src_desc.set_wh(src_w, src_h);

	// render the context onto a new surface
	Surface source;
	source.set_wh(src_w,src_h);
	if(!context.accelerated_render(&source,quality,src_desc,&stageone))
		return false;

	float u,v;
	Point pos, tmp;

	surface->set_wh(w,h);
	surface->clear();

	if(quality<=4)				// CUBIC
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					(*surface)[y][x]=context.get_color(tmp);
				else
					(*surface)[y][x]=source.cubic_sample(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else if (quality<=6)		// INTERPOLATION_LINEAR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					(*surface)[y][x]=context.get_color(tmp);
				else
					(*surface)[y][x]=source.linear_sample(u,v);
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}
	else						// NEAREST_NEIGHBOR
		for(y=0,pos[1]=tl[1];y<h;y++,pos[1]+=ph)
		{
			for(x=0,pos[0]=tl[0];x<w;x++,pos[0]+=pw)
			{
				tmp=transform(pos);
				u=(tmp[0]-src_tl[0])/src_pw;
				v=(tmp[1]-src_tl[1])/src_ph;
				if(u<0 || v<0 || u>=src_w || v>=src_h || isnan(u) || isnan(v))
					(*surface)[y][x]=context.get_color(tmp);
				else
					(*surface)[y][x]=source[floor_to_int(v)][floor_to_int(u)];
			}
			if((y&31)==0 && cb && !stagetwo.amount_complete(y,h)) return false;
		}

	// Mark our progress as finished
	if(cb && !cb->amount_complete(10000,10000))
		return false;

	return true;
}