1 /* === S Y N F I G ========================================================= */
2 /*! \file stretch.cpp
3 ** \brief Implementation of the "Stretch" layer
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
10 ** Copyright (c) 2011-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 /* ========================================================================= */
24
25 /* === H E A D E R S ======================================================= */
26
27 #ifdef USING_PCH
28 # include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include <synfig/localization.h>
35 #include <synfig/general.h>
36
37 #include <synfig/string.h>
38 #include <synfig/time.h>
39 #include <synfig/context.h>
40 #include <synfig/paramdesc.h>
41 #include <synfig/renddesc.h>
42 #include <synfig/surface.h>
43 #include <synfig/value.h>
44 #include <synfig/valuenode.h>
45 #include <synfig/transform.h>
46
47 #include "stretch.h"
48
49 #include <synfig/rendering/common/task/tasktransformation.h>
50 #include <synfig/rendering/primitive/affinetransformation.h>
51
52 #endif
53
54 /* === U S I N G =========================================================== */
55
56 using namespace std;
57 using namespace etl;
58 using namespace synfig;
59 using namespace modules;
60 using namespace lyr_std;
61
62 /* === G L O B A L S ======================================================= */
63
64 SYNFIG_LAYER_INIT(Layer_Stretch);
65 SYNFIG_LAYER_SET_NAME(Layer_Stretch,"stretch");
66 SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Stretch,N_("Stretch"));
67 SYNFIG_LAYER_SET_CATEGORY(Layer_Stretch,N_("Distortions"));
68 SYNFIG_LAYER_SET_VERSION(Layer_Stretch,"0.1");
69 SYNFIG_LAYER_SET_CVS_ID(Layer_Stretch,"$Id$");
70
71 /* === P R O C E D U R E S ================================================= */
72
73 /* === M E T H O D S ======================================================= */
74
75 /* === E N T R Y P O I N T ================================================= */
76
Layer_Stretch()77 Layer_Stretch::Layer_Stretch():
78 param_amount(ValueBase(Point(1,1))),
79 param_center(ValueBase(Point(0,0)))
80 {
81 SET_INTERPOLATION_DEFAULTS();
82 SET_STATIC_DEFAULTS();
83 }
84
85
86 bool
set_param(const String & param,const ValueBase & value)87 Layer_Stretch::set_param(const String & param, const ValueBase &value)
88 {
89 IMPORT_VALUE(param_amount);
90 IMPORT_VALUE(param_center);
91
92 return false;
93 }
94
95 ValueBase
get_param(const String & param) const96 Layer_Stretch::get_param(const String ¶m)const
97 {
98 EXPORT_VALUE(param_amount);
99 EXPORT_VALUE(param_center);
100
101 EXPORT_NAME();
102 EXPORT_VERSION();
103
104 return ValueBase();
105 }
106
107 Layer::Vocab
get_param_vocab() const108 Layer_Stretch::get_param_vocab()const
109 {
110 Layer::Vocab ret;
111
112 ret.push_back(ParamDesc("amount")
113 .set_local_name(_("Amount"))
114 .set_origin("center")
115 .set_description(_("Size of the stretch relative to its Center"))
116 );
117
118 ret.push_back(ParamDesc("center")
119 .set_local_name(_("Center"))
120 .set_description(_("Where the stretch distortion is centered"))
121 );
122
123 return ret;
124 }
125
126 Layer::Handle
hit_check(Context context,const Point & pos) const127 Layer_Stretch::hit_check(Context context, const Point &pos)const
128 {
129 Vector amount=param_amount.get(Vector());
130 Point center=param_center.get(Point());
131
132 Point npos(pos);
133 npos[0]=(npos[0]-center[0])/amount[0]+center[0];
134 npos[1]=(npos[1]-center[1])/amount[1]+center[1];
135 return context.hit_check(npos);
136 }
137
138 Color
get_color(Context context,const Point & pos) const139 Layer_Stretch::get_color(Context context, const Point &pos)const
140 {
141 Vector amount=param_amount.get(Vector());
142 Point center=param_center.get(Point());
143
144 Point npos(pos);
145 npos[0]=(npos[0]-center[0])/amount[0]+center[0];
146 npos[1]=(npos[1]-center[1])/amount[1]+center[1];
147 return context.get_color(npos);
148 }
149
150 class lyr_std::Stretch_Trans : public Transform
151 {
152 etl::handle<const Layer_Stretch> layer;
153 public:
Stretch_Trans(const Layer_Stretch * x)154 Stretch_Trans(const Layer_Stretch* x):Transform(x->get_guid()),layer(x) { }
155
perform(const Vector & x) const156 Vector perform(const Vector& x)const
157 {
158 Vector amount=layer->param_amount.get(Vector());
159 Point center=layer->param_center.get(Point());
160
161 return Vector((x[0]-center[0])*amount[0]+center[0],
162 (x[1]-center[1])*amount[1]+center[1]);
163 }
164
unperform(const Vector & x) const165 Vector unperform(const Vector& x)const
166 {
167 Vector amount=layer->param_amount.get(Vector());
168 Point center=layer->param_center.get(Point());
169
170 return Vector((x[0]-center[0])/amount[0]+center[0],
171 (x[1]-center[1])/amount[1]+center[1]);
172 }
173
get_string() const174 String get_string()const
175 {
176 return "stretch";
177 }
178 };
179 etl::handle<Transform>
get_transform() const180 Layer_Stretch::get_transform()const
181 {
182 return new Stretch_Trans(this);
183 }
184
185 bool
accelerated_render(Context context,Surface * surface,int quality,const RendDesc & renddesc,ProgressCallback * cb) const186 Layer_Stretch::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
187 {
188 Vector amount=param_amount.get(Vector());
189 Point center=param_center.get(Point());
190
191 if (amount[0] == 0 || amount[1] == 0)
192 {
193 surface->set_wh(renddesc.get_w(), renddesc.get_h());
194 surface->clear();
195 return true;
196 }
197
198 RendDesc transformed_renddesc(renddesc);
199 transformed_renddesc.clear_flags();
200 transformed_renddesc.set_transformation_matrix(
201 Matrix().set_translate(-center)
202 * Matrix().set_scale(amount)
203 * Matrix().set_translate(center)
204 * renddesc.get_transformation_matrix() );
205
206 // Render the scene
207 return context.accelerated_render(surface,quality,transformed_renddesc,cb);
208 }
209
210
211
212 bool
accelerated_cairorender(Context context,cairo_t * cr,int quality,const RendDesc & renddesc,ProgressCallback * cb) const213 Layer_Stretch::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const
214 {
215 Vector amount=param_amount.get(Vector());
216 Point center=param_center.get(Point());
217
218 if (amount[0] == 0 || amount[1] == 0)
219 {
220 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
221 cairo_fill(cr);
222 return true;
223 }
224 const double stx(center[0]);
225 const double sty(center[1]);
226
227 cairo_save(cr);
228 cairo_translate(cr, stx, sty);
229 cairo_scale(cr, amount[0], amount[1]);
230 cairo_translate(cr, -stx, -sty);
231
232 if(!context.accelerated_cairorender(cr,quality,renddesc,cb))
233 {
234 cairo_restore(cr);
235 return false;
236 }
237 cairo_restore(cr);
238 return true;
239 }
240
241
242 Rect
get_full_bounding_rect(Context context) const243 Layer_Stretch::get_full_bounding_rect(Context context)const
244 {
245 Vector amount=param_amount.get(Vector());
246 Point center=param_center.get(Point());
247
248 Rect rect(context.get_full_bounding_rect());
249 Point min(rect.get_min()), max(rect.get_max());
250
251 return Rect(Point((min[0]-center[0])*amount[0]+center[0],
252 (min[1]-center[1])*amount[1]+center[1]),
253 Point((max[0]-center[0])*amount[0]+center[0],
254 (max[1]-center[1])*amount[1]+center[1]));
255 }
256
257 rendering::Task::Handle
build_rendering_task_vfunc(Context context) const258 Layer_Stretch::build_rendering_task_vfunc(Context context)const
259 {
260 Vector amount=param_amount.get(Vector());
261 Point center=param_center.get(Point());
262
263 rendering::TaskTransformation::Handle task_transformation(new rendering::TaskTransformation());
264 rendering::AffineTransformation::Handle affine_transformation(new rendering::AffineTransformation());
265 affine_transformation->matrix =
266 Matrix().set_translate(-center)
267 * Matrix().set_scale(amount)
268 * Matrix().set_translate(center);
269 task_transformation->transformation = affine_transformation;
270 task_transformation->sub_task() = context.build_rendering_task();
271 return task_transformation;
272 }
273