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 &param)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