1 /* === S Y N F I G ========================================================= */
2 /*! \file layer_meshtransform.cpp
3 ** \brief Implementation of the "MeshTransform" layer
4 **
5 ** $Id$
6 **
7 ** \legal
8 ** ......... ... 2014 Ivan Mahonin
9 **
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
14 **
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
19 ** \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 # include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <cmath>
33 #include <climits>
34
35 #include <algorithm>
36
37 #include "layer_meshtransform.h"
38
39 #include <synfig/general.h>
40 #include <synfig/localization.h>
41
42 #include <synfig/context.h>
43 #include <synfig/transform.h>
44
45 #include <synfig/rendering/software/task/taskmeshsw.h>
46
47 #endif
48
49 /* === U S I N G =========================================================== */
50
51 using namespace etl;
52 using namespace std;
53 using namespace synfig;
54
55 /* === M A C R O S ========================================================= */
56
57 /* === C L A S S E S ======================================================= */
58
59 class synfig::Mesh_Trans : public Transform
60 {
61 etl::handle<const Layer_MeshTransform> layer;
62 public:
Mesh_Trans(const Layer_MeshTransform * x)63 Mesh_Trans(const Layer_MeshTransform* x):Transform(x->get_guid()),layer(x) { }
64
perform(const synfig::Vector & x) const65 synfig::Vector perform(const synfig::Vector& x)const
66 {
67 Vector v(INFINITY, INFINITY);
68 layer->mesh.transform_coord_texture_to_world(x, v);
69 return v;
70 }
71
unperform(const synfig::Vector & x) const72 synfig::Vector unperform(const synfig::Vector& x)const
73 {
74 Vector v(INFINITY, INFINITY);
75 layer->mesh.transform_coord_world_to_texture(x, v);
76 return v;
77 }
78
get_string() const79 synfig::String get_string()const
80 {
81 return "mesh";
82 }
83 };
84
85 /* === G L O B A L S ======================================================= */
86
87 /* === M E T H O D S ======================================================= */
88
Layer_MeshTransform()89 Layer_MeshTransform::Layer_MeshTransform():
90 max_texture_size(4096),
91 max_texture_scale(INFINITY),
92 world_bounds(Rect::zero()),
93 texture_bounds(Rect::zero())
94 {
95 SET_INTERPOLATION_DEFAULTS();
96 SET_STATIC_DEFAULTS();
97 }
98
~Layer_MeshTransform()99 Layer_MeshTransform::~Layer_MeshTransform()
100 {
101 }
102
103 void
update_mesh_and_mask()104 Layer_MeshTransform::update_mesh_and_mask()
105 {
106 // TODO: check mask to calculate bounds
107
108 texture_scale_dependency_from_x = Vector::zero();
109 texture_scale_dependency_from_y = Vector::zero();
110
111 if (mesh.vertices.empty())
112 {
113 world_bounds = Rect::zero();
114 texture_bounds = Rect::zero();
115 }
116 else
117 {
118 Mesh::VertexList::const_iterator i = mesh.vertices.begin();
119 world_bounds.set_point(i->position);
120 texture_bounds.set_point(i->tex_coords);
121 for(++i; i != mesh.vertices.end(); ++i)
122 {
123 world_bounds.expand(i->position);
124 texture_bounds.expand(i->position);
125 }
126
127 const Real epsilon = 1e-10;
128 for(Mesh::TriangleList::const_iterator i = mesh.triangles.begin(); i != mesh.triangles.end(); ++i)
129 {
130 for(int j = 0; j < 3; ++j)
131 {
132 const Mesh::Vertex &v0 = mesh.vertices[i->vertices[j]];
133 const Mesh::Vertex &v1 = mesh.vertices[i->vertices[(j+1)%3]];
134 Vector wd( fabs(v1.position[0] - v0.position[0]),
135 fabs(v1.position[1] - v0.position[1]) );
136 Vector td( fabs(v1.tex_coords[0] - v0.tex_coords[0]),
137 fabs(v1.tex_coords[1] - v0.tex_coords[1]) );
138 if (td[0] > epsilon)
139 {
140 Vector dep(wd[0]/td[0], wd[1]/td[0]);
141 if (dep[0] > texture_scale_dependency_from_x[0])
142 texture_scale_dependency_from_x[0] = dep[0];
143 if (dep[1] > texture_scale_dependency_from_y[0])
144 texture_scale_dependency_from_y[0] = dep[1];
145 }
146 if (td[1] > epsilon)
147 {
148 Vector dep(wd[0]/td[1], wd[1]/td[1]);
149 if (dep[0] > texture_scale_dependency_from_x[1])
150 texture_scale_dependency_from_x[1] = dep[0];
151 if (dep[1] > texture_scale_dependency_from_y[1])
152 texture_scale_dependency_from_y[1] = dep[1];
153 }
154 }
155 }
156
157 if (max_texture_scale > 0.0)
158 {
159 if (texture_scale_dependency_from_x[0] > max_texture_scale)
160 texture_scale_dependency_from_x[0] = max_texture_scale;
161 if (texture_scale_dependency_from_x[1] > max_texture_scale)
162 texture_scale_dependency_from_x[1] = max_texture_scale;
163 if (texture_scale_dependency_from_y[0] > max_texture_scale)
164 texture_scale_dependency_from_y[0] = max_texture_scale;
165 if (texture_scale_dependency_from_y[1] > max_texture_scale)
166 texture_scale_dependency_from_y[1] = max_texture_scale;
167 }
168 }
169 }
170
171 Layer::Handle
hit_check(synfig::Context context,const synfig::Point & point) const172 Layer_MeshTransform::hit_check(synfig::Context context, const synfig::Point &point)const
173 {
174 // TODO: check mask
175 Vector v;
176 return mesh.transform_coord_world_to_texture(point, v)
177 ? context.hit_check(v)
178 : Layer::Handle();
179 }
180
181 Color
get_color(Context context,const Point & pos) const182 Layer_MeshTransform::get_color(Context context, const Point &pos)const
183 {
184 // TODO: check mask
185 Vector v;
186 return mesh.transform_coord_world_to_texture(pos, v)
187 ? context.get_color(v)
188 : Color();
189 }
190
191 Rect
get_full_bounding_rect(Context) const192 Layer_MeshTransform::get_full_bounding_rect(Context /* context */)const
193 {
194 return world_bounds;
195 }
196
197 etl::handle<synfig::Transform>
get_transform() const198 Layer_MeshTransform::get_transform()const
199 {
200 return new Mesh_Trans(this);
201 }
202
203 RendDesc
get_sub_renddesc_vfunc(const RendDesc & renddesc) const204 Layer_MeshTransform::get_sub_renddesc_vfunc(const RendDesc &renddesc) const
205 {
206 // calculate texture size
207 RendDesc texture_renddesc(renddesc);
208 texture_renddesc.set_transformation_matrix(Matrix());
209 texture_renddesc.set_tl(texture_bounds.get_min());
210 texture_renddesc.set_br(texture_bounds.get_max());
211 {
212 int texture_width, texture_height;
213 Real pw = fabs(renddesc.get_pw());
214 Real ph = fabs(renddesc.get_ph());
215 if (approximate_equal(pw, 0.0) || approximate_equal(ph, 0.0))
216 return RendDesc::zero();
217 pw = 1.0/pw;
218 ph = 1.0/ph;
219 Vector texture_size = texture_bounds.get_max() - texture_bounds.get_min();
220 Real texture_pw = std::max(
221 texture_scale_dependency_from_x[0]*pw,
222 texture_scale_dependency_from_y[0]*ph );
223 Real texture_ph = std::max(
224 texture_scale_dependency_from_x[1]*pw,
225 texture_scale_dependency_from_y[1]*ph );
226 texture_width = std::max(1, (int)roundf(texture_pw*texture_size[0]));
227 texture_height = std::max(1, (int)roundf(texture_ph*texture_size[1]));
228 if (max_texture_size > 0)
229 {
230 if (texture_width > max_texture_size) texture_width = max_texture_size;
231 if (texture_height > max_texture_size) texture_height = max_texture_size;
232 }
233 texture_renddesc.set_w(texture_width);
234 texture_renddesc.set_h(texture_height);
235 }
236 return texture_renddesc;
237 }
238
239 bool
accelerated_render(Context context,Surface * surface,int quality,const RendDesc & renddesc,ProgressCallback * cb) const240 Layer_MeshTransform::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const
241 {
242 // initialize surface
243 surface->set_wh(renddesc.get_w(),renddesc.get_h());
244 surface->clear();
245
246 // calculate texture size
247 RendDesc texture_renddesc = get_sub_renddesc(renddesc);
248 if (texture_renddesc.is_zero())
249 return true;
250
251 // render texture
252 Surface texture;
253 if(!context.accelerated_render(&texture,quality,texture_renddesc,cb))
254 {
255 if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__));
256 return false;
257 }
258
259 { // render mask
260 Surface maskSurface;
261 maskSurface.set_wh(texture.get_w(), texture.get_h());
262 maskSurface.fill(Color::alpha());
263 rendering::TaskMeshSW::render_polygon(
264 maskSurface,
265 &*mask.vertices.begin(),
266 sizeof(*mask.vertices.begin()),
267 mask.triangles.begin()->vertices,
268 sizeof(*mask.triangles.begin()),
269 mask.triangles.size(),
270 texture_renddesc.get_transformation_matrix()
271 * texture_renddesc.get_world_to_pixels_matrix(),
272 Color::white(),
273 1.0,
274 Color::BLEND_COMPOSITE );
275
276 // apply mask
277 Surface::pen a(texture.get_pen(0, 0));
278 Surface::pen b(maskSurface.get_pen(0, 0));
279 for(int i = 0; i < texture.get_h(); ++i)
280 {
281 for(int j = 0; j < texture.get_w(); ++j)
282 {
283 a.put_value(a.get_value()*b.get_value().get_a());
284 a.inc_x();
285 b.inc_x();
286 }
287 a.dec_x(texture.get_w());
288 b.dec_x(texture.get_w());
289 a.inc_y();
290 b.inc_y();
291 }
292 }
293
294 // prepare transformation matrices
295 Matrix world_to_pixels_matrix =
296 renddesc.get_transformation_matrix()
297 * renddesc.get_world_to_pixels_matrix();
298 Matrix texture_to_texels_matrix =
299 texture_renddesc.get_world_to_pixels_matrix();
300
301 // render mesh
302 rendering::TaskMeshSW::render_mesh(
303 *surface,
304 &mesh.vertices.begin()->position,
305 sizeof(*mesh.vertices.begin()),
306 &mesh.vertices.begin()->tex_coords,
307 sizeof(*mesh.vertices.begin()),
308 mesh.triangles.begin()->vertices,
309 sizeof(*mesh.triangles.begin()),
310 mesh.triangles.size(),
311 texture,
312 world_to_pixels_matrix,
313 texture_to_texels_matrix,
314 1.0,
315 Color::BLEND_COMPOSITE
316 );
317
318 return true;
319 }
320
321 rendering::Task::Handle
build_rendering_task_vfunc(Context context) const322 Layer_MeshTransform::build_rendering_task_vfunc(Context context) const
323 { return Layer::build_rendering_task_vfunc(context); }
324