예제 #1
0
bool
synfig::Target_Scanline::render(ProgressCallback *cb)
{
	SuperCallback super_cb;
	int
//		i=0,
		total_frames,
		quality=get_quality(),
		frame_start,
		frame_end;
	Time
		t=0,
		time_start,
		time_end;

	assert(canvas);
	curr_frame_=0;

	if( !init() ){
		if(cb) cb->error(_("Target initialization failure"));
		return false;
	}

	// If the description's end frame is equal to
	// the start frame, then it is assumed that we
	// are rendering only one frame. Correct it.
	if(desc.get_frame_end()==desc.get_frame_start())
		desc.set_frame_end(desc.get_frame_start()+1);

	frame_start=desc.get_frame_start();
	frame_end=desc.get_frame_end();
	time_start=desc.get_time_start();
	time_end=desc.get_time_end();

	// Calculate the number of frames
	total_frames=frame_end-frame_start;


	//RendDesc rend_desc=desc;

	try {
	// Grab the time
	int i=next_frame(t);

	//synfig::info("1time_set_to %s",t.get_string().c_str());

	if(i>1)
	do{

	//if(total_frames>1)
	//for(i=0,t=time_start;i<total_frames;i++)
	//{
		//t=((time_end-time_start)*((Real)i/(Real)total_frames)).round(desc.get_frame_rate())+time_start;

		// If we have a callback, and it returns
		// false, go ahead and bail. (it may be a user cancel)
		if(cb && !cb->amount_complete(total_frames-(i-1),total_frames))
			return false;

		// Set the time that we wish to render
		if(!get_avoid_time_sync() || canvas->get_time()!=t)
			canvas->set_time(t);

		Context context;

#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
		Canvas::Handle op_canvas;
		if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
		{
			op_canvas = Canvas::create();
			op_canvas->set_file_name(canvas->get_file_name());
			optimize_layers(canvas->get_time(), canvas->get_context(), op_canvas);
			context=op_canvas->get_context();
		}
		else
			context=canvas->get_context();
#else
		context=canvas->get_context();
#endif

		// If the quality is set to zero, then we
		// use the parametric scanline-renderer.
		if(quality==0)
		{
			if(threads_<=0)
			{
				if(!synfig::render(context,this,desc,0))
					return false;
			}
			else
			{
				if(!synfig::render_threaded(context,this,desc,0,threads_))
					return false;
			}
		}
		else // If quality is set otherwise, then we use the accelerated renderer
		{
			#if USE_PIXELRENDERING_LIMIT
			if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
			{
				Surface surface;
				int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
				if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
				int rows = desc.get_h()/rowheight;
				int lastrowheight = desc.get_h() - rows*rowheight;

				rows++;

				synfig::info("Render broken up into %d block%s %d pixels tall, and a final block %d pixels tall",
							 rows-1, rows==2?"":"s", rowheight, lastrowheight);

				// loop through all the full rows
				if(!start_frame())
				{
					throw(string("add_frame(): target panic on start_frame()"));
					return false;
				}

				for(int i=0; i < rows; ++i)
				{
					RendDesc	blockrd = desc;

					//render the strip at the normal size unless it's the last one...
					if(i == rows-1)
					{
						if(!lastrowheight) break;
						blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
					}
					else
					{
						blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
					}

					if(!context.accelerated_render(&surface,quality,blockrd,0))
					{
						if(cb)cb->error(_("Accelerated Renderer Failure"));
						return false;
					}else
					{
						int y;
						int rowspan=sizeof(Color)*surface.get_w();
						Surface::pen pen = surface.begin();

						int yoff = i*rowheight;

						for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
						{
							Color *colordata= start_scanline(y + yoff);
							if(!colordata)
							{
								throw(string("add_frame(): call to start_scanline(y) returned NULL"));
								return false;
							}

							if(get_remove_alpha())
							{
								for(int i = 0; i < surface.get_w(); i++)
									colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
							}
							else
								memcpy(colordata,surface[y],rowspan);

							if(!end_scanline())
							{
								throw(string("add_frame(): target panic on end_scanline()"));
								return false;
							}
						}
					}
				}

				end_frame();

			}else //use normal rendering...
			{
			#endif
				Surface surface;

				if(!context.accelerated_render(&surface,quality,desc,0))
				{
					// For some reason, the accelerated renderer failed.
					if(cb)cb->error(_("Accelerated Renderer Failure"));
					return false;
				}
				else
				{
					// Put the surface we renderer
					// onto the target.
					if(!add_frame(&surface))
					{
						if(cb)cb->error(_("Unable to put surface on target"));
						return false;
					}
				}
			#if USE_PIXELRENDERING_LIMIT
			}
			#endif
		}
	}while((i=next_frame(t)));
    else
    {
		// Set the time that we wish to render
		if(!get_avoid_time_sync() || canvas->get_time()!=t)
			canvas->set_time(t);
		Context context;

#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
		Canvas::Handle op_canvas;
		if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
		{
			op_canvas = Canvas::create();
			op_canvas->set_file_name(canvas->get_file_name());
			optimize_layers(canvas->get_time(), canvas->get_context(), op_canvas);
			context=op_canvas->get_context();
		}
		else
			context=canvas->get_context();
#else
		context=canvas->get_context();
#endif

		// If the quality is set to zero, then we
		// use the parametric scanline-renderer.
		if(quality==0)
		{
			if(threads_<=0)
			{
				if(!synfig::render(context,this,desc,cb))
					return false;
			}
			else
			{
				if(!synfig::render_threaded(context,this,desc,cb,threads_))
					return false;
			}
		}
		else // If quality is set otherwise, then we use the accelerated renderer
		{
			#if USE_PIXELRENDERING_LIMIT
			if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
			{
				Surface surface;
				int totalheight = desc.get_h();
				int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
				if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
				int rows = desc.get_h()/rowheight;
				int lastrowheight = desc.get_h() - rows*rowheight;

				rows++;

				synfig::info("Render broken up into %d block%s %d pixels tall, and a final block %d pixels tall",
							 rows-1, rows==2?"":"s", rowheight, lastrowheight);

				// loop through all the full rows
				if(!start_frame())
				{
					throw(string("add_frame(): target panic on start_frame()"));
					return false;
				}

				for(int i=0; i < rows; ++i)
				{
					RendDesc	blockrd = desc;

					//render the strip at the normal size unless it's the last one...
					if(i == rows-1)
					{
						if(!lastrowheight) break;
						blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
					}
					else
					{
						blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
					}

					SuperCallback	sc(cb, i*rowheight, (i+1)*rowheight, totalheight);

					if(!context.accelerated_render(&surface,quality,blockrd,&sc))
					{
						if(cb)cb->error(_("Accelerated Renderer Failure"));
						return false;
					}else
					{
						int y;
						int rowspan=sizeof(Color)*surface.get_w();
						Surface::pen pen = surface.begin();

						int yoff = i*rowheight;

						for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
						{
							Color *colordata= start_scanline(y + yoff);
							if(!colordata)
							{
								throw(string("add_frame(): call to start_scanline(y) returned NULL"));
								return false;
							}

							if(get_remove_alpha())
							{
								for(int i = 0; i < surface.get_w(); i++)
									colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
							}
							else
								memcpy(colordata,surface[y],rowspan);

							if(!end_scanline())
							{
								throw(string("add_frame(): target panic on end_scanline()"));
								return false;
							}
						}
					}

					//I'm done with this part
					sc.amount_complete(100,100);
				}

				end_frame();

			}else
			{
			#endif
				Surface surface;

				if(!context.accelerated_render(&surface,quality,desc,cb))
				{
					if(cb)cb->error(_("Accelerated Renderer Failure"));
					return false;
				}
				else
				{
					// Put the surface we renderer
					// onto the target.
					if(!add_frame(&surface))
					{
						if(cb)cb->error(_("Unable to put surface on target"));
						return false;
					}
				}
			#if USE_PIXELRENDERING_LIMIT
			}
			#endif
		}
	}

	}
	catch(String str)
	{
		if(cb)cb->error(_("Caught string :")+str);
		return false;
	}
	catch(std::bad_alloc)
	{
		if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
		return false;
	}
	catch(...)
	{
		if(cb)cb->error(_("Caught unknown error, rethrowing..."));
		throw;
	}
	return true;
}
예제 #2
0
bool
Layer_SphereDistort::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
{
	RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__)

	/*	Things to consider:
		1) Block expansion for distortion (ouch... quality level??)
		2) Bounding box clipping
		3) Super sampling for better visual quality (based on the quality level?)
		4) Interpolation type for sampling (based on quality level?)

		//things to defer until after
		super sampling, non-linear interpolation
	*/

	//bounding box reject
	Vector center=param_center.get(Vector());
	double radius=param_radius.get(double());
	double percent=param_amount.get(double());
	int type=param_type.get(int());
	bool clip=param_clip.get(bool());
	{
		Rect	sphr;

		sphr.set_point(center[0]-radius,center[1]-radius);
		sphr.expand(center[0]+radius,center[1]+radius);

		//get the bounding box of the transform
		Rect	windr;

		//and the bounding box of the rendering
		windr.set_point(renddesc.get_tl()[0],renddesc.get_tl()[1]);
		windr.expand(renddesc.get_br()[0],renddesc.get_br()[1]);

		//test bounding boxes for collision
		if( (type == TYPE_NORMAL && !intersect(sphr,windr)) ||
			(type == TYPE_DISTH && (sphr.minx >= windr.maxx || windr.minx >= sphr.maxx)) ||
			(type == TYPE_DISTV && (sphr.miny >= windr.maxy || windr.miny >= sphr.maxy)) )
		{
			//warning("Spherize: Bounding box reject");
			if (clip)
			{
				surface->set_wh(renddesc.get_w(), renddesc.get_h());
				surface->clear();
				return true;
			}
			else
				return context.accelerated_render(surface,quality,renddesc,cb);
		}

		//warning("Spherize: Bounding box accept");
	}

	//Ok, so we overlap some... now expand the window for rendering
	RendDesc r = renddesc;
	Surface background;
	Real pw = renddesc.get_pw(),ph = renddesc.get_ph();

	int nl=0,nt=0,nr=0,nb=0, nw=0,nh=0;
	Point tl = renddesc.get_tl(), br = renddesc.get_br();

	{
		//must enlarge window by pixel coordinates so go!

		//need to figure out closest and farthest point and distort THOSE

		Point origin[4] = {tl,tl,br,br};
		Vector v[4] = {Vector(0,br[1]-tl[1]),
					   Vector(br[0]-tl[0],0),
					   Vector(0,tl[1]-br[1]),
					   Vector(tl[0]-br[0],0)};

		Point close(0,0);
		Real t = 0;
		Rect	expandr(tl,br);

		//expandr.set_point(tl[0],tl[1]);
		//expandr.expand(br[0],br[1]);

		//warning("Spherize: Loop through lines and stuff");
		for(int i=0; i<4; ++i)
		{
			//warning("Spherize: 	%d", i);
			Vector p_o = center-origin[i];

			//project onto left line
			t = (p_o*v[i])/v[i].mag_squared();

			//clamp
			if(t < 0) t = 0; if(t > 1) t = 1;

			close = origin[i] + v[i]*t;

			//now get transforms and expand the rectangle to accommodate
			Point p = sphtrans(close,center,radius,percent,type);
			expandr.expand(p[0],p[1]);
			p = sphtrans(origin[i],center,radius,percent,type);
			expandr.expand(p[0],p[1]);
			p = sphtrans(origin[i]+v[i],center,radius,percent,type);
			expandr.expand(p[0],p[1]);
		}

		/*warning("Spherize: Bounding box (%f,%f)-(%f,%f)",
							expandr.minx,expandr.miny,expandr.maxx,expandr.maxy);*/

		//now that we have the bounding rectangle of ALL the pixels (should be...)
		//order it so that it's in the same orientation as the tl,br pair

		//warning("Spherize: Organize like tl,br");
		Point ntl(0,0),nbr(0,0);

		//sort x
		if(tl[0] < br[0])
		{
			ntl[0] = expandr.minx;
			nbr[0] = expandr.maxx;
		}
		else
		{
			ntl[0] = expandr.maxx;
			nbr[0] = expandr.minx;
		}

		//sort y
		if(tl[1] < br[1])
		{
			ntl[1] = expandr.miny;
			nbr[1] = expandr.maxy;
		}
		else
		{
			ntl[1] = expandr.maxy;
			nbr[1] = expandr.miny;
		}

		//now expand the window as needed
		Vector temp = ntl-tl;

		//pixel offset
		nl = (int)(temp[0]/pw)-1;
		nt = (int)(temp[1]/ph)-1;

		temp = nbr - br;
		nr = (int)(temp[0]/pw)+1;
		nb = (int)(temp[1]/ph)+1;

		nw = renddesc.get_w() + nr - nl;
		nh = renddesc.get_h() + nb - nt;

		//warning("Spherize: Setting subwindow (%d,%d) (%d,%d) (%d,%d)",nl,nt,nr,nb,nw,nh);
		r.set_subwindow(nl,nt,nw,nh);

		/*r = renddesc;
		nw = r.get_w(), nh = r.get_h();
		nl = 0, nt = 0;*/
	}

	//warning("Spherize: render background");
	if(!context.accelerated_render(&background,quality,r,cb))
	{
		warning("SphereDistort: Layer below failed");
		return false;
	}

	//now distort and check to make sure we aren't overshooting our bounds here
	int w = renddesc.get_w(), h = renddesc.get_h();
	surface->set_wh(w,h);

	Point sample = tl, sub = tl, trans(0,0);
	float xs = 0,ys = 0;
	int y=0,x=0;
	Real invpw = 1/pw, invph = 1/ph;
	Surface::pen	p = surface->begin();

	Point rtl = r.get_tl();

	//warning("Spherize: About to transform");

	for(y = 0; y < h; ++y, sample[1] += ph, p.inc_y())
	{
		sub = sample;
		for(x = 0; x < w; ++x, sub[0] += pw, p.inc_x())
		{
			bool clipped;
			trans=sphtrans(sub,center,radius,percent,type,clipped);
			if(clip && clipped)
			{
				p.put_value(Color::alpha());
				continue;
			}

			xs = (trans[0]-rtl[0])*invpw;
			ys = (trans[1]-rtl[1])*invph;

			if(!(xs >= 0 && xs < nw && ys >= 0 && ys < nh))
			{
				//warning("Spherize: we failed to account for %f,%f",xs,ys);
				p.put_value(context.get_color(trans));//Color::alpha());
				continue;
			}

			//sample at that pixel location based on the quality
			if(quality <= 4)	// cubic
				p.put_value(background.cubic_sample(xs,ys));
			else if(quality <= 5) // cosine
				p.put_value(background.cosine_sample(xs,ys));
			else if(quality <= 6) // linear
				p.put_value(background.linear_sample(xs,ys));
			else				// nearest
				p.put_value(background[round_to_int(ys)][round_to_int(xs)]);
		}
		p.dec_x(w);
	}

	return true;
}
bool
synfig::Target_Scanline::render(ProgressCallback *cb)
{
	SuperCallback super_cb;
	int
		frames=0,
		total_frames,
		quality=get_quality(),
		frame_start,
		frame_end;
	Time
		t=0;

	assert(canvas);
	curr_frame_=0;

	if( !init() ){
		if(cb) cb->error(_("Target initialization failure"));
		return false;
	}

	frame_start=desc.get_frame_start();
	frame_end=desc.get_frame_end();

	ContextParams context_params(desc.get_render_excluded_contexts());

	// Calculate the number of frames
	total_frames=frame_end-frame_start+1;
	if(total_frames<=0)total_frames=1;

	try {

	//synfig::info("1time_set_to %s",t.get_string().c_str());

	if(total_frames>=1)
	{
		do{
			// Grab the time
			frames=next_frame(t);

			// If we have a callback, and it returns
			// false, go ahead and bail. (it may be a user cancel)
			if(cb && !cb->amount_complete(total_frames-frames,total_frames))
				return false;

			Context context;
			// pass the Render Method to the context
			context=canvas->get_context(context_params);
			context.set_render_method(SOFTWARE);

			// Set the time that we wish to render
			if(!get_avoid_time_sync() || canvas->get_time()!=t)
				canvas->set_time(t);

	#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
			Canvas::Handle op_canvas;
			if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
			{
				op_canvas = Canvas::create();
				op_canvas->set_file_name(canvas->get_file_name());
				optimize_layers(canvas->get_time(), canvas->get_context(context_params), op_canvas);
				context=op_canvas->get_context(context_params);
			}
			else
				context=canvas->get_context(context_params);
	#else
			context=canvas->get_context(context_params);
	#endif

			// If the quality is set to zero, then we
			// use the parametric scanline-renderer.
			if(quality==0 && get_engine().empty())
			{
				if(threads_<=0)
				{
					if(!synfig::render(context,this,desc,0))
						return false;
				}
				else
				{
					if(!synfig::render_threaded(context,this,desc,0,threads_))
						return false;
				}
			}
			else // If quality is set otherwise, then we use the accelerated renderer
			{
				#if USE_PIXELRENDERING_LIMIT
				if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
				{
					SurfaceSW::Handle surfacesw(new SurfaceSW());
					Surface &surface = surfacesw->get_surface();

					int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
					if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
					int rows = desc.get_h()/rowheight;
					int lastrowheight = desc.get_h() - rows*rowheight;

					rows++;

					synfig::info("Render broken up into %d block%s %d pixels tall, and a final block %d pixels tall",
								 rows-1, rows==2?"":"s", rowheight, lastrowheight);

					// loop through all the full rows
					if(!start_frame())
					{
						throw(string("add_frame(): target panic on start_frame()"));
						return false;
					}

					for(int i=0; i < rows; ++i)
					{
						RendDesc	blockrd = desc;

						//render the strip at the normal size unless it's the last one...
						if(i == rows-1)
						{
							if(!lastrowheight) break;
							blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
						}
						else
						{
							blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
						}

						if(!call_renderer(context,surfacesw,quality,blockrd,0))
						{
							if(cb)cb->error(_("Accelerated Renderer Failure"));
							return false;
						}else
						{
							int y;
							int rowspan=sizeof(Color)*surface.get_w();
							Surface::pen pen = surface.begin();

							int yoff = i*rowheight;

							for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
							{
								Color *colordata= start_scanline(y + yoff);
								if(!colordata)
								{
									throw(string("add_frame(): call to start_scanline(y) returned NULL"));
									return false;
								}

								switch(get_alpha_mode())
								{
									case TARGET_ALPHA_MODE_FILL:
										for(int i = 0; i < surface.get_w(); i++)
											colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
										break;
									case TARGET_ALPHA_MODE_EXTRACT:
										for(int i = 0; i < surface.get_w(); i++)
										{
											float a=surface[y][i].get_a();
											colordata[i] = Color(a,a,a,a);
										}
										break;
									case TARGET_ALPHA_MODE_REDUCE:
										for(int i = 0; i < surface.get_w(); i++)
											colordata[i] = Color(surface[y][i].get_r(),surface[y][i].get_g(),surface[y][i].get_b(),1.0f);
										break;
									case TARGET_ALPHA_MODE_KEEP:
										memcpy(colordata,surface[y],rowspan);
										break;
								}	

								if(!end_scanline())
								{
									throw(string("add_frame(): target panic on end_scanline()"));
									return false;
								}
							}
						}
					}

					end_frame();

				}else //use normal rendering...
				{
				#endif
					SurfaceSW::Handle surfacesw(new SurfaceSW());
					Surface &surface = surfacesw->get_surface();

					if(!call_renderer(context,surfacesw,quality,desc,0))
					{
						// For some reason, the accelerated renderer failed.
						if(cb)cb->error(_("Accelerated Renderer Failure"));
						return false;
					}

					// Put the surface we renderer
					// onto the target.
					if(!add_frame(&surface))
					{
						if(cb)cb->error(_("Unable to put surface on target"));
						return false;
					}
				#if USE_PIXELRENDERING_LIMIT
				}
				#endif
			}
		}while(frames);
	}
    else
    {
		// Set the time that we wish to render
		if(!get_avoid_time_sync() || canvas->get_time()!=t)
			canvas->set_time(t);
		Context context;

#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
		Canvas::Handle op_canvas;
		if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
		{
			op_canvas = Canvas::create();
			op_canvas->set_file_name(canvas->get_file_name());
			optimize_layers(canvas->get_time(), canvas->get_context(context_params), op_canvas);
			context=op_canvas->get_context(context_params);
		}
		else
			context=canvas->get_context(context_params);
#else
		context=canvas->get_context(context_params);
#endif

		// If the quality is set to zero, then we
		// use the parametric scanline-renderer.
		if(quality==0 && get_engine().empty())
		{
			if(threads_<=0)
			{
				if(!synfig::render(context,this,desc,cb))
					return false;
			}
			else
			{
				if(!synfig::render_threaded(context,this,desc,cb,threads_))
					return false;
			}
		}
		else // If quality is set otherwise, then we use the accelerated renderer
		{
			#if USE_PIXELRENDERING_LIMIT
			if(desc.get_w()*desc.get_h() > PIXEL_RENDERING_LIMIT)
			{
				SurfaceSW::Handle surfacesw(new SurfaceSW());
				Surface &surface = surfacesw->get_surface();

				int totalheight = desc.get_h();
				int rowheight = PIXEL_RENDERING_LIMIT/desc.get_w();
				if (!rowheight) rowheight = 1; // TODO: render partial lines to stay within the limit?
				int rows = desc.get_h()/rowheight;
				int lastrowheight = desc.get_h() - rows*rowheight;

				rows++;

				synfig::info("Render broken up into %d block%s %d pixels tall, and a final block %d pixels tall",
							 rows-1, rows==2?"":"s", rowheight, lastrowheight);

				// loop through all the full rows
				if(!start_frame())
				{
					throw(string("add_frame(): target panic on start_frame()"));
					return false;
				}

				for(int i=0; i < rows; ++i)
				{
					RendDesc	blockrd = desc;

					//render the strip at the normal size unless it's the last one...
					if(i == rows-1)
					{
						if(!lastrowheight) break;
						blockrd.set_subwindow(0,i*rowheight,desc.get_w(),lastrowheight);
					}
					else
					{
						blockrd.set_subwindow(0,i*rowheight,desc.get_w(),rowheight);
					}

					SuperCallback	sc(cb, i*rowheight, (i+1)*rowheight, totalheight);

					if(!call_renderer(context,surfacesw,quality,blockrd,&sc))
					{
						if(cb)cb->error(_("Accelerated Renderer Failure"));
						return false;
					}

					int y;
					int rowspan=sizeof(Color)*surface.get_w();
					Surface::pen pen = surface.begin();

					int yoff = i*rowheight;

					for(y = 0; y < blockrd.get_h(); y++, pen.inc_y())
					{
						Color *colordata= start_scanline(y + yoff);
						if(!colordata)
						{
							throw(string("add_frame(): call to start_scanline(y) returned NULL"));
							return false;
						}

						switch(get_alpha_mode())
						{
							case TARGET_ALPHA_MODE_FILL:
								for(int i = 0; i < surface.get_w(); i++)
									colordata[i] = Color::blend(surface[y][i],desc.get_bg_color(),1.0f);
								break;
							case TARGET_ALPHA_MODE_EXTRACT:
								for(int i = 0; i < surface.get_w(); i++)
								{
									float a=surface[y][i].get_a();
									colordata[i] = Color(a,a,a,a);
								}
								break;
							case TARGET_ALPHA_MODE_REDUCE:
								for(int i = 0; i < surface.get_w(); i++)
									colordata[i] = Color(surface[y][i].get_r(),surface[y][i].get_g(),surface[y][i].get_b(),1.0f);
								break;
							case TARGET_ALPHA_MODE_KEEP:
								memcpy(colordata,surface[y],rowspan);
								break;
						}

						if(!end_scanline())
						{
							throw(string("add_frame(): target panic on end_scanline()"));
							return false;
						}
					}

					//I'm done with this part
					sc.amount_complete(100,100);
				}

				end_frame();

			}else
			{
			#endif
				SurfaceSW::Handle surfacesw(new SurfaceSW());
				Surface &surface = surfacesw->get_surface();

				if(!call_renderer(context,surfacesw,quality,desc,cb))
				{
					if(cb)cb->error(_("Accelerated Renderer Failure"));
					return false;
				}

				// Put the surface we renderer
				// onto the target.
				if(!add_frame(&surface))
				{
					if(cb)cb->error(_("Unable to put surface on target"));
					return false;
				}
			#if USE_PIXELRENDERING_LIMIT
			}
			#endif
		}
	}

	}
	catch(String str)
	{
		if(cb)cb->error(_("Caught string :")+str);
		return false;
	}
	catch(std::bad_alloc)
	{
		if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
		return false;
	}
	catch(...)
	{
		if(cb)cb->error(_("Caught unknown error, rethrowing..."));
		throw;
	}
	return true;
}