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