Blame synfig-core/src/synfig/target_cairo_tile.cpp

Carlos Lopez 940dd2
/* === S Y N F I G ========================================================= */
Carlos Lopez 940dd2
/*!	\file target_cairo_tile.cpp
Carlos Lopez 940dd2
**	\brief Target Cairo class tile mode
Carlos Lopez 940dd2
**
Carlos Lopez 940dd2
**	$Id$
Carlos Lopez 940dd2
**
Carlos Lopez 940dd2
**	\legal
Carlos Lopez 940dd2
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez e83454
**	Copyright (c) 2013-2013 Carlos Lรณpez
Carlos Lopez 940dd2
**
Carlos Lopez 940dd2
**	This package is free software; you can redistribute it and/or
Carlos Lopez 940dd2
**	modify it under the terms of the GNU General Public License as
Carlos Lopez 940dd2
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez 940dd2
**	the License, or (at your option) any later version.
Carlos Lopez 940dd2
**
Carlos Lopez 940dd2
**	This package is distributed in the hope that it will be useful,
Carlos Lopez 940dd2
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez 940dd2
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez 940dd2
**	General Public License for more details.
Carlos Lopez 940dd2
**	\endlegal
Carlos Lopez 940dd2
*/
Carlos Lopez 940dd2
/* ========================================================================= */
Carlos Lopez 940dd2
Carlos Lopez 940dd2
/* === H E A D E R S ======================================================= */
Carlos Lopez 940dd2
Carlos Lopez 940dd2
#ifdef USING_PCH
Carlos Lopez 940dd2
#	include "pch.h"
Carlos Lopez 940dd2
#else
Carlos Lopez 940dd2
#ifdef HAVE_CONFIG_H
Carlos Lopez 940dd2
#	include <config.h></config.h>
Carlos Lopez 940dd2
#endif
Carlos Lopez 940dd2
Carlos Lopez 940dd2
#include "target_cairo_tile.h"
bw 94d8a6
bw 94d8a6
#include "general.h"
bw 94d8a6
#include <synfig localization.h=""></synfig>
bw 94d8a6
Carlos Lopez 940dd2
#include "canvas.h"
Carlos Lopez 940dd2
#include "context.h"
bw 94d8a6
#include "render.h"
bw 94d8a6
#include "string.h"
Carlos Lopez 940dd2
Carlos Lopez 940dd2
#endif
Carlos Lopez 940dd2
Carlos Lopez 940dd2
/* === U S I N G =========================================================== */
Carlos Lopez 940dd2
Carlos Lopez 940dd2
using namespace std;
Carlos Lopez 940dd2
using namespace etl;
Carlos Lopez 940dd2
using namespace synfig;
Carlos Lopez 940dd2
Carlos Lopez 940dd2
/* === M A C R O S ========================================================= */
Carlos Lopez 940dd2
const unsigned int	DEF_TILE_WIDTH = TILE_SIZE / 2;
Carlos Lopez 940dd2
const unsigned int	DEF_TILE_HEIGHT= TILE_SIZE / 2;
Carlos Lopez 940dd2
Carlos Lopez 940dd2
// note that if this isn't defined then the rendering is incorrect for
Carlos Lopez 940dd2
// the straight blend method since the optimize_layers() function in
Carlos Lopez 940dd2
// canvas.cpp which makes the straight blend method work correctly
Carlos Lopez 940dd2
// isn't called.  ie. leave this defined.  to see the problem, draw a
Carlos Lopez 940dd2
// small circle over a solid background.  set circle to amount 0.99
Carlos Lopez 940dd2
// and blend method 'straight'.  the background should vanish but doesn't
Carlos Lopez 940dd2
#define SYNFIG_OPTIMIZE_LAYER_TREE
Carlos Lopez 940dd2
Carlos Lopez 940dd2
/* === G L O B A L S ======================================================= */
Carlos Lopez 940dd2
Carlos Lopez 940dd2
/* === P R O C E D U R E S ================================================= */
Carlos Lopez 940dd2
Carlos Lopez 940dd2
/* === M E T H O D S ======================================================= */
Carlos Lopez 940dd2
Carlos Lopez 940dd2
Target_Cairo_Tile::Target_Cairo_Tile():
Carlos Lopez 940dd2
	threads_(2),
Carlos Lopez 940dd2
	tile_w_(DEF_TILE_WIDTH),
Carlos Lopez 940dd2
	tile_h_(DEF_TILE_HEIGHT),
Carlos Lopez 940dd2
	curr_tile_(0),
Carlos Lopez 940dd2
	clipping_(true)
Carlos Lopez 940dd2
{
Carlos Lopez 940dd2
	curr_frame_=0;
Carlos Lopez 940dd2
}
Carlos Lopez 940dd2
Carlos Lopez 940dd2
int
Carlos Lopez 940dd2
Target_Cairo_Tile::next_frame(Time& time)
Carlos Lopez 940dd2
{
Carlos Lopez 940dd2
	return Target::next_frame(time);
Carlos Lopez 940dd2
}
Carlos Lopez 940dd2
Carlos Lopez 940dd2
int
Carlos Lopez 940dd2
Target_Cairo_Tile::next_tile(int& x, int& y)
Carlos Lopez 940dd2
{
Carlos Lopez 940dd2
	// Width of the image(in tiles)
Carlos Lopez 940dd2
	int tw(rend_desc().get_w()/tile_w_);
Carlos Lopez 940dd2
	int th(rend_desc().get_h()/tile_h_);
Carlos Lopez 940dd2
	
Carlos Lopez 940dd2
	// Add the last tiles (which will be clipped)
Carlos Lopez 940dd2
	if(rend_desc().get_w()%tile_w_!=0)tw++;
Carlos Lopez 940dd2
	if(rend_desc().get_h()%tile_h_!=0)th++;
Carlos Lopez 940dd2
	
Carlos Lopez 940dd2
	x=(curr_tile_%tw)*tile_h_;
Carlos Lopez 940dd2
	y=(curr_tile_/tw)*tile_w_;
Carlos Lopez 940dd2
	
Carlos Lopez 940dd2
	curr_tile_++;
Carlos Lopez 940dd2
	return (tw*th)-curr_tile_+1;
Carlos Lopez 940dd2
}
Carlos Lopez 940dd2
Carlos Lopez 940dd2
bool
Carlos Lopez 3025c9
synfig::Target_Cairo_Tile::render_frame_(Context context,ProgressCallback *cb)
Carlos Lopez 940dd2
{
Carlos Lopez 940dd2
	if(tile_w_<=0||tile_h_<=0)
Carlos Lopez 940dd2
	{
Carlos Lopez 940dd2
		if(cb)cb->error(_("Bad Tile Size"));
Carlos Lopez 940dd2
		return false;
Carlos Lopez 940dd2
	}
Carlos Lopez 940dd2
	const RendDesc &rend_desc(desc);
Carlos Lopez 940dd2
#define total_tiles total_tiles()
Carlos Lopez 940dd2
Carlos Lopez 940dd2
	RendDesc tile_desc;
Carlos Lopez 940dd2
	int x,y,w,h;
Carlos Lopez 940dd2
	int i;
Carlos Lopez 940dd2
Carlos Lopez 940dd2
	while((i=next_tile(x,y)))
Carlos Lopez 940dd2
	{
Carlos Lopez 940dd2
		SuperCallback	super(cb,(total_tiles-i)*1000,(total_tiles-i+1)*1000,total_tiles*1000);
Carlos Lopez 940dd2
		if(!super.amount_complete(0,1000))
Carlos Lopez 940dd2
			return false;
Carlos Lopez 940dd2
		//			if(cb && !cb->amount_complete(total_tiles-i,total_tiles))
Carlos Lopez 940dd2
		//				return false;
Carlos Lopez 940dd2
		// Perform clipping on the tile
Carlos Lopez 940dd2
		if(clipping_)
Carlos Lopez 940dd2
		{
Carlos Lopez 940dd2
			w=x+tile_w_
Carlos Lopez 940dd2
			h=y+tile_h_
Carlos Lopez 940dd2
			if(w<=0||h<=0)continue;
Carlos Lopez 940dd2
		}
Carlos Lopez 940dd2
		else
Carlos Lopez 940dd2
		{
Carlos Lopez 940dd2
			w=tile_w_;
Carlos Lopez 940dd2
			h=tile_h_;
Carlos Lopez 940dd2
		}
Carlos Lopez 940dd2
		
Carlos Lopez 940dd2
		tile_desc=rend_desc;
Carlos Lopez 940dd2
		tile_desc.set_subwindow(x,y,w,h);
Carlos Lopez 940dd2
				
Carlos Lopez 940dd2
		cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
Carlos Lopez 413401
		cairo_t* cr=cairo_create(surface);
Carlos Lopez e0d481
		double tx=tile_desc.get_tl()[0];
Carlos Lopez e0d481
		double ty=tile_desc.get_tl()[1];
Carlos Lopez e0d481
		double sx=1.0/tile_desc.get_pw();
Carlos Lopez e0d481
		double sy=1.0/tile_desc.get_ph();
Carlos Lopez e0d481
		cairo_scale(cr, sx, sy);
Carlos Lopez e0d481
		cairo_translate(cr, -tx, -ty);
Carlos Lopez 413401
		if(!context.accelerated_cairorender(cr,get_quality(),tile_desc,&super))
Carlos Lopez 940dd2
		{
Carlos Lopez 940dd2
			// For some reason, the accelerated renderer failed.
Carlos Lopez 940dd2
			if(cb)cb->error(_("Accelerated Renderer Failure"));
Carlos Lopez e0d481
			cairo_destroy(cr);
Carlos Lopez 940dd2
			return false;
Carlos Lopez 940dd2
		}
Carlos Lopez 940dd2
		else
Carlos Lopez 940dd2
		{
Carlos Lopez 940dd2
			cairo_status_t status = cairo_surface_status(surface);
Carlos Lopez 940dd2
			if(status)
Carlos Lopez 940dd2
			{
Carlos Lopez 01e45b
				if(cb) cb->error(strprintf(_("Bad surface: %s"), cairo_status_to_string(status)));
Carlos Lopez 413401
				cairo_destroy(cr);
Carlos Lopez 940dd2
				return false;
Carlos Lopez 940dd2
			}
Carlos Lopez 940dd2
			// Add the tile to the target
Carlos Lopez 413401
			if(!add_tile(cairo_surface_reference(surface), x,y))
Carlos Lopez 940dd2
			{
Firas Hanife b4b6a7
				if(cb)cb->error(_("add_tile(): Unable to put surface on target"));
Carlos Lopez 940dd2
				return false;
Carlos Lopez 940dd2
			}
Carlos Lopez 413401
			cairo_destroy(cr);
Carlos Lopez 940dd2
		}
Carlos Lopez 940dd2
		signal_progress()();
Carlos Lopez 940dd2
	}
Carlos Lopez 940dd2
	if(cb && !cb->amount_complete(total_tiles,total_tiles))
Carlos Lopez 940dd2
		return false;
Carlos Lopez 940dd2
	
Carlos Lopez 940dd2
#undef total_tiles
Carlos Lopez 940dd2
	return true;
Carlos Lopez 940dd2
}
Carlos Lopez 940dd2
Carlos Lopez 940dd2
Carlos Lopez 940dd2
bool
Carlos Lopez 940dd2
synfig::Target_Cairo_Tile::render(ProgressCallback *cb)
Carlos Lopez 940dd2
{
Carlos Lopez 940dd2
	int
Carlos Lopez 940dd2
		frames=0,
Carlos Lopez 940dd2
		total_frames,
Carlos Lopez 940dd2
		frame_start,
Carlos Lopez 940dd2
		frame_end;
Carlos Lopez 940dd2
	Time
Carlos Lopez 940dd2
		t=0;
Carlos Lopez 940dd2
Carlos Lopez 940dd2
	assert(canvas);
Carlos Lopez 940dd2
	curr_frame_=0;
Carlos Lopez 940dd2
Carlos Lopez 940dd2
	if( !init() ){
Carlos Lopez 940dd2
		if(cb) cb->error(_("Target initialization failure"));
Carlos Lopez 940dd2
		return false;
Carlos Lopez 940dd2
	}
Carlos Lopez 940dd2
Carlos Lopez 940dd2
	frame_start=desc.get_frame_start();
Carlos Lopez 940dd2
	frame_end=desc.get_frame_end();
Carlos Lopez 940dd2
c74593
	ContextParams context_params(desc.get_render_excluded_contexts());
c74593
Carlos Lopez 940dd2
	// Calculate the number of frames
Carlos Lopez 940dd2
	total_frames=frame_end-frame_start+1;
Carlos Lopez 940dd2
	if(total_frames<=0)total_frames=1;
Carlos Lopez 940dd2
Carlos Lopez 940dd2
	try {
Carlos Lopez 940dd2
		do{
Carlos Lopez 940dd2
			// Grab the time
Carlos Lopez 940dd2
			if(total_frames>=1)
Carlos Lopez 940dd2
				frames=next_frame(t);
Carlos Lopez 940dd2
			else
Carlos Lopez 940dd2
				frames=0;
Carlos Lopez 940dd2
Carlos Lopez 940dd2
			// If we have a callback, and it returns
Carlos Lopez 940dd2
			// false, go ahead and bail. (it may be a user cancel)
Carlos Lopez 940dd2
			if(cb && !cb->amount_complete(total_frames-frames,total_frames))
Carlos Lopez 940dd2
				return false;
Carlos Lopez 940dd2
Carlos Lopez 3025c9
			if(!start_frame(cb))
Carlos Lopez 3025c9
			{
Carlos Lopez 3025c9
				if(cb)cb->error(_("Can't start frame"));
Carlos Lopez 3025c9
				return false;
Carlos Lopez 3025c9
			}
Carlos Lopez c1fe21
			Context context;
Carlos Lopez c1fe21
			// pass the Render Method to the context
c74593
			context=canvas->get_context(context_params);
Carlos Lopez 3025c9
Carlos Lopez 940dd2
			// Set the time that we wish to render
c3039f
			if(!get_avoid_time_sync() || canvas->get_time()!=t) {
2ffd0a
				canvas->set_time(t);
c3039f
				canvas->load_resources(t);
c3039f
			}
Carlos Lopez 940dd2
Carlos Lopez 940dd2
	#ifdef SYNFIG_OPTIMIZE_LAYER_TREE
Carlos Lopez 940dd2
			Canvas::Handle op_canvas;
Carlos Lopez 940dd2
			if (!getenv("SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE"))
Carlos Lopez 940dd2
			{
Carlos Lopez 940dd2
				op_canvas = Canvas::create();
Carlos Lopez 940dd2
				op_canvas->set_file_name(canvas->get_file_name());
c74593
				optimize_layers(canvas->get_time(), canvas->get_context(context_params), op_canvas);
c74593
				context=op_canvas->get_context(context_params);
Carlos Lopez 940dd2
			}
Carlos Lopez 940dd2
			else
c74593
				context=canvas->get_context(context_params);
Carlos Lopez 940dd2
	#else
c74593
			context=canvas->get_context(context_params);
Carlos Lopez 940dd2
	#endif
Carlos Lopez 3025c9
			if(!render_frame_(context,cb))
Carlos Lopez 940dd2
			{
Carlos Lopez 3025c9
				// For some reason, the accelerated renderer failed.
Carlos Lopez 3025c9
				if(cb)cb->error(_("Accelerated Renderer Failure"));
Carlos Lopez 3025c9
				return false;
Carlos Lopez 940dd2
			}
Carlos Lopez 3025c9
			end_frame();
Carlos Lopez 940dd2
		}while(frames);
Carlos Lopez 940dd2
	}
b1afd8
	catch (const String& str)
Carlos Lopez 940dd2
	{
Firas Hanife b4b6a7
		if (cb) cb->error(_("Caught string: ")+str);
Carlos Lopez 940dd2
		return false;
Carlos Lopez 940dd2
	}
b1afd8
	catch (std::bad_alloc&)
Carlos Lopez 940dd2
	{
Carlos Lopez 940dd2
		if(cb)cb->error(_("Ran out of memory (Probably a bug)"));
Carlos Lopez 940dd2
		return false;
Carlos Lopez 940dd2
	}
b1afd8
	catch (...)
Carlos Lopez 940dd2
	{
Carlos Lopez 940dd2
		if(cb)cb->error(_("Caught unknown error, rethrowing..."));
Carlos Lopez 940dd2
		throw;
Carlos Lopez 940dd2
	}
Carlos Lopez 940dd2
	return true;
Carlos Lopez 940dd2
}
Carlos Lopez 940dd2
Carlos Lopez 940dd2
void
e198f4
Target_Cairo_Tile::gamma_filter(cairo_surface_t *surface, const synfig::Gamma &gamma)
Carlos Lopez 940dd2
{
Carlos Lopez 56e542
	CairoSurface cairo_s;
Carlos Lopez 56e542
	cairo_s.set_cairo_surface(surface);
Carlos Lopez 56e542
	cairo_s.map_cairo_image();
Carlos Lopez 56e542
	int w=cairo_s.get_w();
Carlos Lopez 56e542
	int h=cairo_s.get_h();
Carlos Lopez 56e542
	for(int y=0; y
Carlos Lopez 56e542
		for(int x=0; x
Carlos Lopez 940dd2
		{
Carlos Lopez 56e542
			CairoColor c=cairo_s[y][x];
23b4d4
			if (c.get_alpha()) {
a4bbdd
				float a = c.get_alpha();
a4bbdd
				c.set_r( (unsigned char)(a*gamma.apply_r(c.get_r()/a)) );
a4bbdd
				c.set_r( (unsigned char)(a*gamma.apply_g(c.get_g()/a)) );
a4bbdd
				c.set_r( (unsigned char)(a*gamma.apply_b(c.get_b()/a)) );
23b4d4
			}
Carlos Lopez 56e542
			cairo_s[y][x]=c;
Carlos Lopez 940dd2
		}
Carlos Lopez 56e542
	cairo_s.unmap_cairo_image();
Carlos Lopez 940dd2
}