1 /* === S Y N F I G ========================================================= */
2 /*!	\file synfig/rendering/opengl/task/taskcontourgl.cpp
3 **	\brief TaskContourGL
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	......... ... 2015 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 #ifndef _WIN32
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <signal.h>
36 #endif
37 
38 #include "taskcontourgl.h"
39 
40 #include "../internal/environment.h"
41 #include "../surfacegl.h"
42 
43 #endif
44 
45 using namespace synfig;
46 using namespace rendering;
47 
48 /* === M A C R O S ========================================================= */
49 
50 /* === G L O B A L S ======================================================= */
51 
52 /* === P R O C E D U R E S ================================================= */
53 
54 /* === M E T H O D S ======================================================= */
55 
56 void
render_polygon(const std::vector<Vector> & polygon,const Rect & bounds,bool invert,bool antialias,Contour::WindingStyle winding_style,const Color & color)57 TaskContourGL::render_polygon(
58 	const std::vector<Vector> &polygon,
59 	const Rect &bounds,
60 	bool invert,
61 	bool antialias,
62 	Contour::WindingStyle winding_style,
63 	const Color &color )
64 {
65 	if (polygon.empty()) return;
66 	gl::Environment &e = gl::Environment::get_instance();
67 
68 	if (antialias) e.antialiasing.multisample_begin(false);
69 
70 	glClearColor(color.get_r(), color.get_g(), color.get_b(), 0.f);
71 	glClear(GL_COLOR_BUFFER_BIT);
72 	glClearColor(0.f, 0.f, 0.f, 0.f);
73 
74 	gl::Buffers::BufferLock quad_buf = e.buffers.get_default_quad_buffer();
75 	gl::Buffers::VertexArrayLock quad_va = e.buffers.get_vertex_array();
76 
77 	gl::Buffers::BufferLock polygon_buf = e.buffers.get_array_buffer(polygon);
78 	gl::Buffers::VertexArrayLock polygon_va = e.buffers.get_vertex_array();
79 
80 	bool even_odd = winding_style == Contour::WINDING_EVEN_ODD;
81 
82 	GLint vp[4] = { };
83 	glGetIntegerv(GL_VIEWPORT, vp);
84 	int x0 = (int)floor(vp[0] + (bounds.minx + 1.0)*0.5*vp[2]);
85 	int x1 = (int)ceil (vp[0] + (bounds.maxx + 1.0)*0.5*vp[2]);
86 	int y0 = (int)floor(vp[1] + (bounds.miny + 1.0)*0.5*vp[3]);
87 	int y1 = (int)ceil (vp[1] + (bounds.maxy + 1.0)*0.5*vp[3]);
88 	glScissor(x0, y0, x1-x0, y1-y0);
89 
90 	glEnable(GL_SCISSOR_TEST);
91 	glEnable(GL_STENCIL_TEST);
92 
93 	// render mask
94 
95 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
96 	glClear(GL_STENCIL_BUFFER_BIT);
97 	glStencilFunc(GL_ALWAYS, 0, 0);
98 	if (even_odd) {
99 		glStencilOp(GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);
100 	} else {
101 		glStencilOpSeparate(GL_FRONT, GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP);
102 		glStencilOpSeparate(GL_BACK, GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP);
103 	}
104 
105 	glBindVertexArray(polygon_va.get_id());
106 	glEnableVertexAttribArray(0);
107 	glBindBuffer(GL_ARRAY_BUFFER, polygon_buf.get_id());
108 	glVertexAttribPointer(0, 2, GL_DOUBLE, GL_TRUE, 0, polygon_buf.get_pointer());
109 	glBindBuffer(GL_ARRAY_BUFFER, 0);
110 
111 	e.shaders.simple();
112 	glDrawArrays(GL_TRIANGLE_FAN, 0, polygon.size());
113 
114 	glDisableVertexAttribArray(0);
115 	glBindVertexArray(0);
116 
117 	// fill mask
118 
119 	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
120 	if (!even_odd && !invert)
121 		glStencilFunc(GL_NOTEQUAL, 0, -1);
122 	if (!even_odd &&  invert)
123 		glStencilFunc(GL_EQUAL, 0, -1);
124 	if ( even_odd && !invert)
125 		glStencilFunc(GL_EQUAL, 1, 1);
126 	if ( even_odd &&  invert)
127 		glStencilFunc(GL_EQUAL, 0, 1);
128 
129 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
130 
131 	glBindVertexArray(quad_va.get_id());
132 	glEnableVertexAttribArray(0);
133 	glBindBuffer(GL_ARRAY_BUFFER, quad_buf.get_id());
134 	glVertexAttribPointer(0, 2, GL_DOUBLE, GL_TRUE, 0, quad_buf.get_pointer());
135 	glBindBuffer(GL_ARRAY_BUFFER, 0);
136 
137 	e.shaders.color(color);
138 	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
139 
140 	glDisableVertexAttribArray(0);
141 	glBindVertexArray(0);
142 
143 	glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
144 	glDisable(GL_STENCIL_TEST);
145 	glDisable(GL_SCISSOR_TEST);
146 
147 	if (antialias) e.antialiasing.multisample_end();
148 }
149 
150 void
render_contour(const Contour & contour,const Matrix & transform_matrix,bool invert,bool antialias,Contour::WindingStyle winding_style,const Color & color,Real detail)151 TaskContourGL::render_contour(
152 	const Contour &contour,
153 	const Matrix &transform_matrix,
154 	bool invert,
155 	bool antialias,
156 	Contour::WindingStyle winding_style,
157 	const Color &color,
158 	Real detail )
159 {
160 	GLint vp[4] = { };
161 	glGetIntegerv(GL_VIEWPORT, vp);
162 	if (!vp[2] || !vp[3]) return;
163 
164 	std::vector<Vector> polygon;
165 	Rect full_bounds(-1.0, -1.0, 1.0, 1.0);
166 	Rect bounds = full_bounds;
167 	Vector pixel_size(2.0/(Real)vp[2], 2.0/(Real)vp[3]);
168 
169 	contour.split(polygon, bounds, transform_matrix, pixel_size*detail);
170 
171 	if (invert) bounds = full_bounds;
172 	render_polygon(polygon, bounds, invert, antialias, winding_style, color);
173 }
174 
175 bool
run(RunParams &) const176 TaskContourGL::run(RunParams & /* params */) const
177 {
178 	gl::Context::Lock lock(env().context);
179 
180 	SurfaceGL::Handle target =
181 		SurfaceGL::Handle::cast_dynamic(target_surface);
182 
183 	// transformation
184 
185 	Vector rect_size = get_source_rect_rb() - get_source_rect_lt();
186 	Matrix bounds_transfromation;
187 	bounds_transfromation.m00 = fabs(rect_size[0]) > 1e-10 ? 2.0/rect_size[0] : 0.0;
188 	bounds_transfromation.m11 = fabs(rect_size[1]) > 1e-10 ? 2.0/rect_size[1] : 0.0;
189 	bounds_transfromation.m20 = -1.0 - get_source_rect_lt()[0]*bounds_transfromation.m00;
190 	bounds_transfromation.m21 = -1.0 - get_source_rect_lt()[1]*bounds_transfromation.m11;
191 
192 	Matrix matrix = transformation * bounds_transfromation;
193 
194 	if (valid_target())
195 	{
196 		// check bounds
197 		std::vector<Vector> polygon;
198 		Rect bounds(-1.0, -1.0, 1.0, 1.0);
199 		Vector pixel_size(
200 			2.0/(Real)(get_target_rect().maxx - get_target_rect().minx),
201 			2.0/(Real)(get_target_rect().maxy - get_target_rect().miny) );
202 		contour->split(polygon, bounds, matrix, pixel_size*detail);
203 
204 		// bind framebuffer
205 
206 		gl::Framebuffers::RenderbufferLock renderbuffer = env().framebuffers.get_renderbuffer(GL_STENCIL_INDEX8, target->get_width(), target->get_height());
207 		gl::Framebuffers::FramebufferLock framebuffer = env().framebuffers.get_framebuffer();
208 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer.get_id());
209 		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer.get_id());
210 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target->get_id(), 0);
211 		env().framebuffers.check("TaskContourGL::run bind framebuffer");
212 		glViewport(
213 			get_target_rect().minx,
214 			get_target_rect().miny,
215 			get_target_rect().maxx - get_target_rect().minx,
216 			get_target_rect().maxy - get_target_rect().miny );
217 		env().context.check("TaskContourGL::run viewport");
218 
219 		// render
220 
221 		render_polygon(
222 			polygon,
223 			bounds,
224 			contour->invert,
225 			allow_antialias && contour->antialias,
226 			contour->winding_style,
227 			contour->color );
228 
229 		// release framebuffer
230 
231 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
232 		glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
233 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
234 		env().context.check("TaskContourGL::run release contour");
235 	}
236 
237 	return true;
238 }
239 
240 /* === E N T R Y P O I N T ================================================= */
241