1 /* === S Y N F I G ========================================================= */
2 /*!	\file rotate.cpp
3 **	\brief Implementation of the "Rotate" layer
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **	Copyright (c) 2008 Chris Moore
10 **	Copyright (c) 2012-2013 Carlos López
11 **
12 **	This package is free software; you can redistribute it and/or
13 **	modify it under the terms of the GNU General Public License as
14 **	published by the Free Software Foundation; either version 2 of
15 **	the License, or (at your option) any later version.
16 **
17 **	This package is distributed in the hope that it will be useful,
18 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
19 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 **	General Public License for more details.
21 **	\endlegal
22 **
23 ** === N O T E S ===========================================================
24 **
25 ** ========================================================================= */
26 
27 /* === H E A D E R S ======================================================= */
28 
29 #ifdef USING_PCH
30 #	include "pch.h"
31 #else
32 #ifdef HAVE_CONFIG_H
33 #	include <config.h>
34 #endif
35 
36 #include <ETL/misc>
37 
38 #include <synfig/localization.h>
39 #include <synfig/general.h>
40 
41 #include <synfig/string.h>
42 #include <synfig/time.h>
43 #include <synfig/context.h>
44 #include <synfig/paramdesc.h>
45 #include <synfig/renddesc.h>
46 #include <synfig/surface.h>
47 #include <synfig/value.h>
48 #include <synfig/valuenode.h>
49 #include <synfig/transform.h>
50 
51 #include "rotate.h"
52 
53 #include <synfig/rendering/common/task/tasktransformation.h>
54 #include <synfig/rendering/primitive/affinetransformation.h>
55 
56 #endif
57 
58 using namespace std;
59 using namespace etl;
60 using namespace synfig;
61 using namespace modules;
62 using namespace lyr_std;
63 
64 /* === M A C R O S ========================================================= */
65 
66 /* === G L O B A L S ======================================================= */
67 
68 SYNFIG_LAYER_INIT(Rotate);
69 SYNFIG_LAYER_SET_NAME(Rotate,"rotate");
70 SYNFIG_LAYER_SET_LOCAL_NAME(Rotate,N_("Rotate"));
71 SYNFIG_LAYER_SET_CATEGORY(Rotate,N_("Transform"));
72 SYNFIG_LAYER_SET_VERSION(Rotate,"0.1");
73 SYNFIG_LAYER_SET_CVS_ID(Rotate,"$Id$");
74 
75 /* === P R O C E D U R E S ================================================= */
76 
77 /* === M E T H O D S ======================================================= */
78 
79 /* === E N T R Y P O I N T ================================================= */
80 
Rotate()81 Rotate::Rotate():
82 	param_origin (ValueBase(Vector(0,0))),
83 	param_amount (ValueBase(Angle::deg(0))),
84 	sin_val	(0),
85 	cos_val	(1)
86 {
87 	SET_INTERPOLATION_DEFAULTS();
88 	SET_STATIC_DEFAULTS();
89 }
90 
~Rotate()91 Rotate::~Rotate()
92 {
93 }
94 
95 bool
set_param(const String & param,const ValueBase & value)96 Rotate::set_param(const String & param, const ValueBase &value)
97 {
98 	IMPORT_VALUE(param_origin);
99 
100 	IMPORT_VALUE_PLUS(param_amount,
101 	{
102 		Angle amount=value.get(Angle());
103 		sin_val=Angle::sin(amount).get();
104 		cos_val=Angle::cos(amount).get();
105 		param_amount.set(amount);
106 		return true;
107 	}
108 	);
109 
110 	return false;
111 }
112 
113 ValueBase
get_param(const String & param) const114 Rotate::get_param(const String &param)const
115 {
116 	EXPORT_VALUE(param_origin);
117 	EXPORT_VALUE(param_amount);
118 
119 	EXPORT_NAME();
120 	EXPORT_VERSION();
121 
122 	return ValueBase();
123 }
124 
125 Layer::Vocab
get_param_vocab() const126 Rotate::get_param_vocab()const
127 {
128 	Layer::Vocab ret;
129 
130 	ret.push_back(ParamDesc("origin")
131 		.set_local_name(_("Origin"))
132 		.set_description(_("Point where you want the origin to be"))
133 	);
134 
135 	ret.push_back(ParamDesc("amount")
136 		.set_local_name(_("Amount"))
137 		.set_description(_("Amount of rotation"))
138 		.set_origin("origin")
139 	);
140 
141 	return ret;
142 }
143 
144 class lyr_std::Rotate_Trans : public Transform
145 {
146 	etl::handle<const Rotate> layer;
147 public:
Rotate_Trans(const Rotate * x)148 	Rotate_Trans(const Rotate* x):Transform(x->get_guid()),layer(x) { }
149 
perform(const Vector & x) const150 	Vector perform(const Vector& x)const
151 	{
152 		Vector origin=layer->param_origin.get(Vector());
153 		Point pos(x-origin);
154 		return Point(layer->cos_val*pos[0]-layer->sin_val*pos[1],layer->sin_val*pos[0]+layer->cos_val*pos[1])+origin;
155 	}
156 
unperform(const Vector & x) const157 	Vector unperform(const Vector& x)const
158 	{
159 		Vector origin=layer->param_origin.get(Vector());
160 		Point pos(x-origin);
161 		return Point(layer->cos_val*pos[0]+layer->sin_val*pos[1],-layer->sin_val*pos[0]+layer->cos_val*pos[1])+origin;
162 	}
163 
get_string() const164 	String get_string()const
165 	{
166 		return "rotate";
167 	}
168 };
169 etl::handle<Transform>
get_transform() const170 Rotate::get_transform()const
171 {
172 	return new Rotate_Trans(this);
173 }
174 
175 Layer::Handle
hit_check(Context context,const Point & p) const176 Rotate::hit_check(Context context, const Point &p)const
177 {
178 	Vector origin=param_origin.get(Vector());
179 	Point pos(p-origin);
180 	Point newpos(cos_val*pos[0]+sin_val*pos[1],-sin_val*pos[0]+cos_val*pos[1]);
181 	newpos+=origin;
182 	return context.hit_check(newpos);
183 }
184 
185 Color
get_color(Context context,const Point & p) const186 Rotate::get_color(Context context, const Point &p)const
187 {
188 	Vector origin=param_origin.get(Vector());
189 	Point pos(p-origin);
190 	Point newpos(cos_val*pos[0]+sin_val*pos[1],-sin_val*pos[0]+cos_val*pos[1]);
191 	newpos+=origin;
192 	return context.get_color(newpos);
193 }
194 
195 bool
accelerated_render(Context context,Surface * surface,int quality,const RendDesc & renddesc,ProgressCallback * cb) const196 Rotate::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
197 {
198 	Vector origin=param_origin.get(Vector());
199 	Angle amount=param_amount.get(Angle());
200 
201 	RendDesc transformed_renddesc(renddesc);
202 	transformed_renddesc.clear_flags();
203 	transformed_renddesc.set_transformation_matrix(
204 		Matrix().set_translate(-origin)
205 	  * Matrix().set_rotate(amount)
206 	  * Matrix().set_translate(origin)
207 	  * renddesc.get_transformation_matrix() );
208 	return context.accelerated_render(surface,quality,transformed_renddesc,cb);
209 }
210 
211 ///////////
212 
213 bool
accelerated_cairorender(Context context,cairo_t * cr,int quality,const RendDesc & renddesc,ProgressCallback * cb) const214 Rotate::accelerated_cairorender(Context context, cairo_t *cr,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
215 {
216 	Vector origin=param_origin.get(Vector());
217 	Angle amount=param_amount.get(Angle());
218 
219 	const double rtx(origin[0]);
220 	const double rty(origin[1]);
221 
222 	float angle=Angle::rad(amount).get();
223 
224 	cairo_save(cr);
225 	cairo_translate(cr, rtx, rty);
226 	cairo_rotate(cr, angle);
227 	cairo_translate(cr, -rtx, -rty);
228 
229 	// is this really useful?
230 	if(quality>8) cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
231 	else if(quality>=4) cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD);
232 	else cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BEST);
233 
234 	if(!context.accelerated_cairorender(cr,quality,renddesc,cb))
235 	{
236 		cairo_restore(cr);
237 		return false;
238 	}
239 	cairo_restore(cr);
240 	return true;
241 }
242 
243 Rect
get_full_bounding_rect(Context context) const244 Rotate::get_full_bounding_rect(Context context)const
245 {
246 	Rect under(context.get_full_bounding_rect());
247 	return get_transform()->perform(under);
248 }
249 
250 rendering::Task::Handle
build_rendering_task_vfunc(Context context) const251 Rotate::build_rendering_task_vfunc(Context context)const
252 {
253 	Vector origin=param_origin.get(Vector());
254 	Angle amount=param_amount.get(Angle());
255 
256 	rendering::TaskTransformation::Handle task_transformation(new rendering::TaskTransformation());
257 	rendering::AffineTransformation::Handle affine_transformation(new rendering::AffineTransformation());
258 	affine_transformation->matrix =
259 			Matrix().set_translate(-origin)
260 		  * Matrix().set_rotate(amount)
261 		  * Matrix().set_translate(origin);
262 	task_transformation->transformation = affine_transformation;
263 	task_transformation->sub_task() = context.build_rendering_task();
264 	return task_transformation;
265 }
266 
267