Blame synfig-core/src/modules/mod_geometry/checkerboard.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file checkerboard.cpp
Carlos Lopez a09598
**	\brief Implementation of the "Checkerboard" layer
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007, 2008 Chris Moore
Carlos Lopez e83454
**	Copyright (c) 2011-2013 Carlos Lรณpez
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
*/
Carlos Lopez a09598
/* ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
e03d25
#include <algorithm></algorithm>
Carlos Lopez a09598
Carlos Lopez a09598
#include <synfig string.h=""></synfig>
Carlos Lopez a09598
#include <synfig time.h=""></synfig>
Carlos Lopez a09598
#include <synfig context.h=""></synfig>
Carlos Lopez a09598
#include <synfig paramdesc.h=""></synfig>
Carlos Lopez a09598
#include <synfig renddesc.h=""></synfig>
Carlos Lopez a09598
#include <synfig surface.h=""></synfig>
Carlos Lopez a09598
#include <synfig value.h=""></synfig>
Carlos Lopez a09598
#include <synfig valuenode.h=""></synfig>
Carlos Lopez a09598
#include <synfig segment.h=""></synfig>
Carlos Lopez a09598
e03d25
#include <synfig common="" rendering="" task="" tasktransformation.h=""></synfig>
e03d25
#include <synfig common="" rendering="" task="" taskblend.h=""></synfig>
e03d25
#include <synfig rendering="" software="" task="" tasksw.h=""></synfig>
e03d25
e03d25
#include "checkerboard.h"
e03d25
e03d25
#include <synfig localization.h=""></synfig>
e03d25
#include <synfig general.h=""></synfig>
e03d25
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
using namespace synfig;
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
SYNFIG_LAYER_INIT(CheckerBoard);
Carlos Lopez a09598
SYNFIG_LAYER_SET_NAME(CheckerBoard,"checker_board");
Carlos Lopez a09598
SYNFIG_LAYER_SET_LOCAL_NAME(CheckerBoard,N_("Checkerboard"));
Carlos Lopez a09598
SYNFIG_LAYER_SET_CATEGORY(CheckerBoard,N_("Geometry"));
Carlos Lopez a09598
SYNFIG_LAYER_SET_VERSION(CheckerBoard,"0.1");
Carlos Lopez a09598
SYNFIG_LAYER_SET_CVS_ID(CheckerBoard,"$Id$");
Carlos Lopez a09598
Carlos Lopez a09598
/* === P R O C E D U R E S ================================================= */
Carlos Lopez a09598
e03d25
namespace {
e03d25
e03d25
class TaskCheckerBoard: public rendering::Task, public rendering::TaskInterfaceTransformation
e03d25
{
e03d25
public:
e03d25
	typedef etl::handle<taskcheckerboard> Handle;</taskcheckerboard>
e03d25
	static Token token;
e03d25
	virtual Token::Handle get_token() const { return token.handle(); }
e03d25
e03d25
	Color color;
e03d25
	bool antialias;
e03d25
	rendering::Holder<rendering::transformationaffine> transformation;</rendering::transformationaffine>
e03d25
e03d25
	TaskCheckerBoard(): antialias(true) { }
3ae388
	virtual rendering::Transformation::Handle get_transformation() const
e03d25
		{ return transformation.handle(); }
e03d25
};
e03d25
e03d25
e03d25
class TaskCheckerBoardSW: public TaskCheckerBoard, public rendering::TaskSW,
e03d25
	public rendering::TaskInterfaceBlendToTarget,
e03d25
	public rendering::TaskInterfaceSplit
e03d25
{
e03d25
public:
e03d25
	typedef etl::handle<taskcheckerboardsw> Handle;</taskcheckerboardsw>
e03d25
	static Token token;
e03d25
	virtual Token::Handle get_token() const { return token.handle(); }
e03d25
111532
	virtual void on_target_set_as_source() {
111532
		Task::Handle &subtask = sub_task(0);
111532
		if ( subtask
111532
		  && subtask->target_surface == target_surface
111532
		  && !Color::is_straight(blend_method) )
111532
		{
111532
			trunc_by_bounds();
111532
			subtask->source_rect = source_rect;
111532
			subtask->target_rect = target_rect;
111532
		}
111532
	}
111532
e03d25
	virtual Color::BlendMethodFlags get_supported_blend_methods() const
e03d25
		{ return Color::BLEND_METHODS_ALL; }
e03d25
e03d25
	virtual bool run(RunParams&) const {
e03d25
		if (!is_valid())
e03d25
			return true;
e03d25
e03d25
		Vector ppu = get_pixels_per_unit();
e03d25
e03d25
		Matrix bounds_transfromation;
e03d25
		bounds_transfromation.m00 = ppu[0];
e03d25
		bounds_transfromation.m11 = ppu[1];
e03d25
		bounds_transfromation.m20 = target_rect.minx - ppu[0]*source_rect.minx;
e03d25
		bounds_transfromation.m21 = target_rect.miny - ppu[1]*source_rect.miny;
e03d25
e03d25
		Matrix matrix = bounds_transfromation * transformation->matrix;
e03d25
		Matrix inv_matrix = matrix.get_inverted();
e03d25
e03d25
		int tw = target_rect.get_width();
e03d25
		Vector dx = inv_matrix.axis_x();
e03d25
		Vector dy = inv_matrix.axis_y() - dx*(Real)tw;
e03d25
		Vector p = inv_matrix.get_transformed( Vector((Real)target_rect.minx, (Real)target_rect.miny) );
e03d25
e03d25
		LockWrite la(this);
e03d25
		if (!la)
e03d25
			return false;
e03d25
e03d25
		Surface::alpha_pen apen(la->get_surface().get_pen(target_rect.minx, target_rect.miny));
111532
		ColorReal amount = blend ? this->amount : ColorReal(1.0);
111532
		apen.set_blend_method(blend ? blend_method : Color::BLEND_COMPOSITE);
e03d25
		Color c = color;
e03d25
		if (antialias) {
e03d25
			ColorReal kx(matrix.axis_x().mag()*0.5);
e03d25
			ColorReal ky(matrix.axis_y().mag()*0.5);
e03d25
			for(int iy = target_rect.miny; iy < target_rect.maxy; ++iy, p += dy, apen.inc_y(), apen.dec_x(tw))
e03d25
				for(int ix = target_rect.minx; ix < target_rect.maxx; ++ix, p += dx, apen.inc_x()) {
e03d25
					p[0] -= floor(p[0]);
e03d25
					p[1] -= floor(p[1]);
e03d25
e03d25
					ColorReal px = p[0]*ColorReal(2);
e03d25
					px -= floor(px);
e03d25
					px = std::min(px, ColorReal(1) - px)*kx;
e03d25
e03d25
					ColorReal py = p[1]*ColorReal(2);
e03d25
					py -= floor(py);
e03d25
					py = std::min(py, ColorReal(1) - py)*ky;
e03d25
e03d25
					ColorReal a = std::min(px, py);
e03d25
					if ((p[0] < 0.5) != (p[1] < 0.5)) a = -a;
e03d25
					a = std::max(ColorReal(0), std::min(ColorReal(1), a + ColorReal(0.5)));
e03d25
e03d25
					c.set_a(color.get_a()*a);
e03d25
					apen.put_value(c, amount);
e03d25
				}
e03d25
		} else {
e03d25
			for(int iy = target_rect.miny; iy < target_rect.maxy; ++iy, p += dy, apen.inc_y(), apen.dec_x(tw))
e03d25
				for(int ix = target_rect.minx; ix < target_rect.maxx; ++ix, p += dx, apen.inc_x()) {
e03d25
					p[0] -= floor(p[0]);
e03d25
					p[1] -= floor(p[1]);
e03d25
					ColorReal a((p[0] < 0.5) == (p[1] < 0.5) ? 1.0 : 0.0);
e03d25
					c.set_a(color.get_a()*a);
e03d25
					apen.put_value(c, amount);
e03d25
				}
e03d25
		}
e03d25
e03d25
		return true;
e03d25
	}
e03d25
};
e03d25
e03d25
rendering::Task::Token TaskCheckerBoard::token(
111532
	DescAbstract<taskcheckerboard>("CheckerBoard") );</taskcheckerboard>
e03d25
rendering::Task::Token TaskCheckerBoardSW::token(
111532
	DescReal<taskcheckerboardsw, taskcheckerboard="">("CheckerBoardSW") );</taskcheckerboardsw,>
e03d25
e03d25
} // namespace
e03d25
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
CheckerBoard::CheckerBoard():
Carlos Lopez 346618
	Layer_Composite	(1.0,Color::BLEND_COMPOSITE),
Carlos Lopez 53cfd6
	param_color (ValueBase(Color::black())),
Carlos Lopez 53cfd6
	param_origin (ValueBase(Point(0.125,0.125))),
Carlos Lopez 53cfd6
	param_size (ValueBase(Point(0.25,0.25)))
Carlos Lopez 5b3df3
{
Carlos Lopez 53cfd6
	SET_INTERPOLATION_DEFAULTS();
Carlos Lopez 53cfd6
	SET_STATIC_DEFAULTS();
Carlos Lopez 5b3df3
}
Carlos Lopez a09598
Carlos Lopez a09598
inline bool
Carlos Lopez a09598
CheckerBoard::point_test(const synfig::Point& getpos)const
Carlos Lopez a09598
{
Carlos Lopez 53cfd6
	Point origin=param_origin.get(Point());
Carlos Lopez 53cfd6
	Point size=param_size.get(Point());
Carlos Lopez 53cfd6
	
Carlos Lopez a09598
	int val=((int)((getpos[0]-origin[0])/size[0])+(int)((getpos[1]-origin[1])/size[1]));
Carlos Lopez a09598
	if(getpos[0]-origin[0] < 0.0)
Carlos Lopez a09598
		val++;
Carlos Lopez a09598
	if(getpos[1]-origin[1] < 0.0)
Carlos Lopez a09598
		val++;
Carlos Lopez a09598
	return val&1;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
CheckerBoard::set_param(const String ¶m, const ValueBase &value)
Carlos Lopez a09598
{
Carlos Lopez 53cfd6
	IMPORT_VALUE_PLUS(param_color,
Carlos Lopez 53cfd6
	  {
Carlos Lopez 53cfd6
		  Color color(param_color.get(Color()));
Carlos Lopez 53cfd6
		  if (color.get_a() == 0)
Carlos Lopez 53cfd6
		  {
Carlos Lopez 53cfd6
			  if(converted_blend_)
Carlos Lopez 53cfd6
			  {
Carlos Lopez 53cfd6
				  set_blend_method(Color::BLEND_ALPHA_OVER);
Carlos Lopez 53cfd6
				  color.set_a(1);
Carlos Lopez 53cfd6
				  param_color.set(color);
Carlos Lopez 53cfd6
			  }
Carlos Lopez 53cfd6
			  else
Carlos Lopez 53cfd6
				  transparent_color_ = true;
Carlos Lopez 53cfd6
		  }
Carlos Lopez 53cfd6
	  }
Carlos Lopez 53cfd6
	  );
Carlos Lopez 53cfd6
	IMPORT_VALUE(param_origin);
Carlos Lopez 53cfd6
	IMPORT_VALUE(param_size);
Carlos Lopez 53cfd6
Carlos Lopez 53cfd6
	if(param=="pos")
Carlos Lopez 1c6c0b
		return set_param("origin", value);
Carlos Lopez 53cfd6
Carlos Lopez 53cfd6
	for(int i=0;i<2;i++)
e03d25
		if(param==etl::strprintf("pos[%d]",i) && value.get_type()==type_real)
Carlos Lopez 53cfd6
		{
Carlos Lopez 53cfd6
			Point p=param_origin.get(Point());
Carlos Lopez 53cfd6
			p[i]=value.get(Real());
Carlos Lopez 53cfd6
			param_origin.set(p);
Carlos Lopez 53cfd6
			return true;
Carlos Lopez 53cfd6
		}
Carlos Lopez a09598
Carlos Lopez a09598
	return Layer_Composite::set_param(param,value);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
ValueBase
Carlos Lopez a09598
CheckerBoard::get_param(const String ¶m)const
Carlos Lopez a09598
{
Carlos Lopez 53cfd6
	EXPORT_VALUE(param_color);
Carlos Lopez 53cfd6
	EXPORT_VALUE(param_origin);
Carlos Lopez 53cfd6
	EXPORT_VALUE(param_size);
Carlos Lopez a09598
	EXPORT_NAME();
Carlos Lopez a09598
	EXPORT_VERSION();
Carlos Lopez a09598
Carlos Lopez a09598
	return Layer_Composite::get_param(param);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Layer::Vocab
Carlos Lopez a09598
CheckerBoard::get_param_vocab()const
Carlos Lopez a09598
{
Carlos Lopez a09598
	Layer::Vocab ret(Layer_Composite::get_param_vocab());
Carlos Lopez a09598
Carlos Lopez a09598
	ret.push_back(ParamDesc("color")
Carlos Lopez a09598
		.set_local_name(_("Color"))
Carlos Lopez a09598
		.set_description(_("Color of checkers"))
Carlos Lopez a09598
	);
Carlos Lopez a09598
	ret.push_back(ParamDesc("origin")
Carlos Lopez a09598
		.set_local_name(_("Origin"))
Carlos Lopez 42e8f2
		.set_description(_("Center of the checkers"))
Carlos Lopez a09598
	);
Carlos Lopez a09598
	ret.push_back(ParamDesc("size")
Carlos Lopez a09598
		.set_local_name(_("Size"))
Carlos Lopez a09598
		.set_description(_("Size of checkers"))
Carlos Lopez a09598
		.set_origin("origin")
Carlos Lopez a09598
	);
Carlos Lopez a09598
Carlos Lopez a09598
	return ret;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
synfig::Layer::Handle
Carlos Lopez a09598
CheckerBoard::hit_check(synfig::Context context, const synfig::Point &getpos)const
Carlos Lopez a09598
{
Carlos Lopez a09598
	if(get_amount()!=0.0 && point_test(getpos))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		synfig::Layer::Handle tmp;
Carlos Lopez a09598
		if(get_blend_method()==Color::BLEND_BEHIND && (tmp=context.hit_check(getpos)))
Carlos Lopez a09598
			return tmp;
Carlos Lopez a09598
		if(Color::is_onto(get_blend_method()) && !(tmp=context.hit_check(getpos)))
Carlos Lopez a09598
			return 0;
Carlos Lopez a09598
		return const_cast<checkerboard*>(this);</checkerboard*>
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
		return context.hit_check(getpos);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Color
Carlos Lopez a09598
CheckerBoard::get_color(Context context, const Point &getpos)const
Carlos Lopez a09598
{
Carlos Lopez 53cfd6
	Color color=param_color.get(Color());
Carlos Lopez 53cfd6
Carlos Lopez a09598
	if(get_amount()!=0.0 && point_test(getpos))
Carlos Lopez a09598
	{
Carlos Lopez a09598
		if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT)
Carlos Lopez a09598
			return color;
Carlos Lopez a09598
		else
Carlos Lopez a09598
			return Color::blend(color,context.get_color(getpos),get_amount(),get_blend_method());
Carlos Lopez a09598
	}
Carlos Lopez a09598
	else
Carlos Lopez a09598
		return Color::blend(Color::alpha(),context.get_color(getpos),get_amount(),get_blend_method());
Carlos Lopez a09598
}
Carlos Lopez a09598
e03d25
rendering::Task::Handle
e03d25
CheckerBoard::build_composite_task_vfunc(ContextParams /*context_params*/)const
e03d25
{
e03d25
	Color color = param_color.get(Color());
e03d25
	Point origin = param_origin.get(Point());
e03d25
	Point size = param_size.get(Point());
e03d25
e03d25
	origin[0] += size[0]; // make first cell empty (by history)
e03d25
    size *= 2.0;          // task expects repeat period instead of cell size
e03d25
e03d25
	TaskCheckerBoard::Handle task(new TaskCheckerBoard());
e03d25
	task->color = color;
e03d25
	task->transformation->matrix = Matrix().set_translate(origin)
e03d25
			                     * Matrix().set_scale(size);
e03d25
e03d25
	return task;
e03d25
}
e03d25