Developer Documentation
QtLasso.cc
1/*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40\*===========================================================================*/
41
42
43
44
45
46//=============================================================================
47//
48// CLASS QtLasso - IMPLEMENTATION
49//
50//=============================================================================
51
52//== INCLUDES =================================================================
53
54
55//ACG
56#include "QtLasso.hh"
57#include "QtColorTranslator.hh"
58
59// stdc++
60
61
62
63//== NAMESPACES ===============================================================
64
65namespace ACG {
66
67
68//== IMPLEMENTATION ==========================================================
69
70
71
72#define MASK(x,y) (mask_[(x)+(y)*mask_width_])
73
74
75//-----------------------------------------------------------------------------
76
77
78QtLasso::
79QtLasso(GLState& _glstate) :
80 glstate_(_glstate),
81 mask_(0),
82 mask_width_(0),
83 mask_height_(0),
84 is_active_(false)
85{
86}
87
88
89//-----------------------------------------------------------------------------
90
91
92QtLasso::
93~QtLasso()
94{
95 free_mask();
96}
97
98
99//-----------------------------------------------------------------------------
100
101
102void
103QtLasso::
104slotMouseEvent(QMouseEvent* _event)
105{
106 bool emit_signal = false;
107
108
109 // setup 2D projection
110 unsigned int width = glstate_.viewport_width();
111 unsigned int height = glstate_.viewport_height();
112
113 ACG::GLState::drawBuffer( GL_FRONT );
114
115 glMatrixMode(GL_PROJECTION);
116 glPushMatrix();
117 GLMatrixf orthoProj;
118 orthoProj.identity();
119 orthoProj.ortho(0.0f, float(width-1), 0.0f, float(height-1), -1.0f, 1.0f);
120 glLoadMatrixf(orthoProj.data());
121
122
123 glMatrixMode(GL_MODELVIEW);
124 glPushMatrix();
125 glLoadIdentity();
126
127 ACG::GLState::disable(GL_DEPTH_TEST);
128 ACG::GLState::disable(GL_LIGHTING);
129 ACG::GLState::disable(GL_DITHER);
130 glLineWidth(2.0);
131 glColor3ub(0, 255, 10);
132
133 glFinish();
134
135
136
137 // process mouse event
138 switch(_event->type())
139 {
140 case QEvent::MouseButtonPress:
141 {
142 Vec2i p(_event->pos().x(), height-_event->pos().y()-1);
143
144 // initialize
145 if (!is_active())
146 {
147 is_active_ = true;
148 first_point_ = last_point_ = p;
149 }
150
151 // draw line
152 glBegin(GL_LINES);
153 glVertex(last_point_);
154 glVertex(p);
155 glEnd();
156 last_point_ = rubberband_point_ = p;
157 break;
158 }
159
160
161 case QEvent::MouseMove:
162 {
163 if (is_active())
164 {
165 Vec2i p(_event->pos().x(), height-_event->pos().y());
166
167 // draw freehand
168 if (_event->modifiers() & Qt::LeftButton)
169 {
170 glBegin(GL_LINES);
171 glVertex(last_point_);
172 glVertex(p);
173 glEnd();
174 last_point_ = rubberband_point_ = p;
175 }
176
177 // draw rubber band
178 else
179 {
180 ACG::GLState::enable(GL_COLOR_LOGIC_OP);
181 glLogicOp(GL_XOR);
182 glBegin(GL_LINES);
183 glVertex(last_point_);
184 glVertex(rubberband_point_);
185 glVertex(last_point_);
186 glVertex(p);
187 glEnd();
188 ACG::GLState::disable(GL_COLOR_LOGIC_OP);
189 rubberband_point_ = p;
190 }
191 }
192 break;
193 }
194
195
196 case QEvent::MouseButtonDblClick:
197 {
198 if (is_active())
199 {
200 // close polygon
201 glBegin(GL_LINES);
202 glVertex(last_point_);
203 glVertex(first_point_);
204 glEnd();
205 glFinish();
206
207
208 // mark reference point (0,0) with border color
209 glPointSize(1.0);
210 glBegin(GL_POINTS);
211 glVertex2i(0, 0);
212 glEnd();
213 glPointSize(glstate_.point_size());
214
215
216 // create mask and precompute matrix
217 create_mask();
218 is_active_ = false;
219
220 emit_signal = true;
221 }
222 break;
223 }
224
225
226 default: // avoid warning
227 break;
228 }
229
230
231 // restore GL settings
233 glReadBuffer(GL_BACK);
234
235 glLineWidth(glstate_.line_width());
236 glColor4fv(glstate_.base_color().data());
237 ACG::GLState::enable(GL_DEPTH_TEST);
238
239 glMatrixMode(GL_PROJECTION );
240 glPopMatrix();
241
242 glMatrixMode(GL_MODELVIEW);
243 glPopMatrix();
244
245 glFinish();
246
247
248
249 // emit signal
250 if (emit_signal)
251 {
252 if (_event->modifiers() & Qt::ShiftModifier)
253 emit(signalLassoSelection(AddToSelection));
254
255 else if (_event->modifiers() & Qt::ControlModifier)
256 emit(signalLassoSelection(DelFromSelection));
257
258 else
259 emit(signalLassoSelection(NewSelection));
260 }
261}
262
263
264//-----------------------------------------------------------------------------
265
266
267void
268QtLasso::
269create_mask()
270{
271 unsigned int x, y, xx, yy, i;
272 GLubyte *fbuffer;
273 QRgb rgb, borderRgb;
274
275
276 // GL context
277 const unsigned int w = glstate_.viewport_width();
278 const unsigned int h = glstate_.viewport_height();
279 const unsigned int size = w*h;
280
281
282 // alloc mask
283 free_mask();
284 mask_ = new unsigned char[size];
285 mask_width_ = w;
286 mask_height_ = h;
287
288
289 // alloc framebuffer
290 fbuffer = new GLubyte[3*size];
291 assert( fbuffer );
292
293
294 // read framebuffer
295 glReadBuffer( GL_FRONT );
296 glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, fbuffer);
297 glReadBuffer( GL_BACK );
298
299
300 // read lasso color
301 borderRgb = qRgb( fbuffer[0], fbuffer[1], fbuffer[2] );
302 fbuffer[0] = fbuffer[1] = fbuffer[2] = 0;
303
304
305 // mark lasso pixels
306 for (y = 0; y < h; ++y)
307 {
308 const unsigned int offset = y*w;
309
310 for (x = 0; x < w; ++x)
311 {
312 i = 3*(offset + x);
313 rgb = qRgb(fbuffer[i], fbuffer[i+1], fbuffer[i+2]);
314 mask_[offset+x] = (rgb == borderRgb) ? 3 : 1;
315 }
316 }
317
318
319 // seed fill
320 std::vector<Vec2i> toDo;
321 toDo.reserve(w*h);
322 toDo.push_back(Vec2i(0,0));
323
324 while (!toDo.empty())
325 {
326 Vec2i p = toDo.back();
327 toDo.pop_back();
328
329 x = p[0];
330 y = p[1];
331 unsigned char &s = MASK(x, y);
332
333 if (s != 3)
334 {
335 s = 0;
336
337 xx = x-1; yy = y;
338 if ((xx<w) && (MASK(xx,yy)==1))
339 {
340 toDo.push_back(Vec2i(xx,yy));
341 MASK(xx,yy) = 2;
342 }
343
344 xx = x+1; yy = y;
345 if ((xx<w) && (MASK(xx,yy)==1))
346 {
347 toDo.push_back(Vec2i(xx,yy));
348 MASK(xx,yy) = 2;
349 }
350
351 xx = x; yy = y-1;
352 if ((yy<h) && (MASK(xx,yy)==1))
353 {
354 toDo.push_back(Vec2i(xx,yy));
355 MASK(xx,yy) = 2;
356 }
357
358 xx = x; yy = y+1;
359 if ((yy<h) && (MASK(xx,yy)==1))
360 {
361 toDo.push_back(Vec2i(xx,yy));
362 MASK(xx,yy) = 2;
363 }
364 }
365 }
366
367
368 // free
369 delete[] fbuffer;
370}
371
372
373//-----------------------------------------------------------------------------
374
375
376void
377QtLasso::
378free_mask()
379{
380 if (mask_)
381 {
382 delete[] mask_;
383 mask_ = 0;
384 mask_width_ = mask_height_ = 0;
385 }
386}
387
388
389//-----------------------------------------------------------------------------
390
391
392bool
393QtLasso::
394is_vertex_selected(const Vec3d& _v)
395{
396 unsigned int x, y, w, h;
397
398
399 // size changed?
400 w = glstate_.viewport_width();
401 h = glstate_.viewport_height();
402 if ((w != mask_width_) || (h != mask_height_))
403 {
404 std::cerr << "Lasso: viewport size has changed.\n";
405 return false;
406 }
407
408
409 // project vertex to 2D integer coordinates
410 Vec3d v = glstate_.project(_v);
411 x = (unsigned int)(v[0] + 0.5);
412 y = (unsigned int)(v[1] + 0.5);
413
414
415 // near and far plane clipping
416 if (v[2] < 0.0 || v[2] > 1.0)
417 return false;
418
419
420 // visible ?
421 return ((v[2]>0.0) && (x<w) && (y<h) && (MASK(x,y)));
422}
423
424
425//=============================================================================
426} // namespace ACG
427//=============================================================================
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition: GLState.cc:2076
void identity()
setup an identity matrix
Namespace providing different geometric functions concerning angles.
GLMatrixT< float > GLMatrixf
typedef
Definition: GLMatrixT.hh:322
VectorT< signed int, 2 > Vec2i
Definition: VectorT.hh:98
void glVertex(const Vec2i &_v)
Wrapper: glVertex for Vec2i.
Definition: gl.hh:95