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 ¶m)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