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