Developer Documentation
CursorPainter.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 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 
51 
52 
53 //=============================================================================
54 //
55 // CLASS CursorPainter - IMPLEMENTATION
56 //
57 //=============================================================================
58 
59 //== INCLUDES =================================================================
60 
61 #include <QPixmap>
62 #include <QBitmap>
63 
65 
66 #include "CursorPainter.hh"
67 #include "QtBaseViewer.hh"
68 
69 //== NAMESPACES ===============================================================
70 
71 CursorPainter::CursorPainter (QObject *_parent) :
72  QObject(_parent),
73  cursor_(),
74  initialized_(false),
75  enabled_(false),
76  mouseIn_(false),
77  forceNative_(false),
78  xOff_(0),
79  yOff_(0),
80  texture_(0),
81  hasCursor_(false)
82 {
83 }
84 
85 //-----------------------------------------------------------------------------
86 
88 {
89  if (initialized_)
90  {
91  glDeleteTextures (1, &texture_);
92  }
93 }
94 
95 //-----------------------------------------------------------------------------
96 
97 void CursorPainter::setCursor (const QCursor &_cursor)
98 {
99  nativeCursor_ = _cursor;
100  cursorToCursor ();
101  cursorToTexture ();
102  if (!(initialized_ && enabled_ && hasCursor_) || forceNative_) {
103  foreach (glViewer *v, views_)
104  v->setCursor ((forceNative_)? nativeCursor_ : cursor_);
105  }
106 }
107 
108 //-----------------------------------------------------------------------------
109 
111 {
112  if (initialized_)
113  return;
114  initialized_ = true;
115 
116  // setup cursor texture
117  glGenTextures (1, &texture_);
118 
119  ACG::GLState::bindTexture (GL_TEXTURE_2D, texture_);
120  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
121  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
122  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
123  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
124  ACG::GLState::bindTexture (GL_TEXTURE_2D, 0);
125 
126  cursorToTexture ();
127 
128  if (enabled_ && hasCursor_ && !forceNative_)
129  {
130  foreach (glViewer *v, views_)
131  v->setCursor (Qt::BlankCursor);
132 
133  }
134  else
135  {
136  foreach (glViewer *v, views_)
137  v->setCursor ((forceNative_)? nativeCursor_ : cursor_);
138 
139  }
140 }
141 
142 //-----------------------------------------------------------------------------
143 
145 {
146  views_.append (_viewer);
147  _viewer->setCursorPainter (this);
148 }
149 
150 //-----------------------------------------------------------------------------
151 
153 {
154  if (!initialized_)
155  return;
156 
157  if (!enabled())
158  return;
159 
160  // project (0, 0, 0) to get its position on the screen
161  ACG::Vec3d zPos = _state->project (ACG::Vec3d (0.0, 0.0, 0.0));
162  // unproject the result translated by 1px in x and y
163  zPos = _state->unproject (ACG::Vec3d (zPos[0] + 1, zPos[1] + 1, zPos[2]));
164 
165  // this gives us the size of one pixel in the current scene transformation
166  // now we can paint the cursor always with the same width/height
167  float xscale = zPos[0];
168  float yscale = -zPos[1];
169 
170  glPushAttrib (GL_ALL_ATTRIB_BITS);
171 
172  ACG::GLState::disable (GL_DEPTH_TEST);
173  ACG::GLState::disable(GL_LIGHTING);
174  ACG::GLState::enable(GL_BLEND);
175 
176  ACG::GLState::blendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
177 
178  // bind texture
179  ACG::GLState::enable (GL_TEXTURE_2D);
180  ACG::GLState::bindTexture (GL_TEXTURE_2D, texture_);
181 
182  glColor4f (1.0, 1.0, 1.0, 1.0);
183 
184  float x1 = -xOff_ * xscale;
185  float x2 = (32 - xOff_) * xscale;
186  float y1 = -yOff_ * yscale;
187  float y2 = (32 - yOff_) * yscale;
188 
189  // draw cursor quad
190  glBegin (GL_QUADS);
191  glTexCoord2f (0, 0);
192  glVertex3f (x1, y1, 0);
193  glTexCoord2f (0, 1);
194  glVertex3f (x1, y2, 0);
195  glTexCoord2f (1, 1);
196  glVertex3f (x2, y2, 0);
197  glTexCoord2f (1, 0);
198  glVertex3f (x2, y1, 0);
199  glEnd ();
200 
201 
202  glPopAttrib ();
203 }
204 
205 //-----------------------------------------------------------------------------
206 
207 void CursorPainter::updateCursorPosition (QPointF _scenePos)
208 {
209  cursorPos_ = _scenePos;
210  setMouseIn (true);
211 }
212 
213 //-----------------------------------------------------------------------------
214 
216 {
217  return cursorPos_;
218 }
219 
220 //-----------------------------------------------------------------------------
221 
222 void CursorPainter::setEnabled(bool _enabled)
223 {
224  enabled_ = _enabled;
225 
226  if (initialized_)
227  {
228  if (_enabled && hasCursor_)
229  {
230  foreach (glViewer *v, views_)
231  v->setCursor (Qt::BlankCursor);
232  }
233  else
234  {
235  foreach (glViewer *v, views_)
236  v->setCursor ((forceNative_)? nativeCursor_ : cursor_);
237  }
238  }
239 }
240 
241 //-----------------------------------------------------------------------------
242 
244 {
245  return initialized_ && enabled_ && hasCursor_ && mouseIn_ && !forceNative_;
246 }
247 
248 //-----------------------------------------------------------------------------
249 
251 {
252 
253  if (!initialized_) {
254  return;
255  }
256 
257  unsigned char buf[4096];
258  QImage cImg;
259 
260  hasCursor_ = false;
261 
262  // Initialize hotspot with default position in the upper left corner of the cursor
263  xOff_ = 0;
264  yOff_ = 0;
265 
267  switch (nativeCursor_.shape())
268  {
269  case Qt::ArrowCursor:
270  cImg.load (OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cursor_arrow.png");
271  break;
272  case Qt::PointingHandCursor:
273  cImg.load (OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cursor_move.png");
274  break;
275  case Qt::WhatsThisCursor:
276  cImg.load (OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cursor_whatsthis.png");
277  break;
278  case Qt::BitmapCursor:
279  // Get the image of the cursor
280  cImg = QImage(( nativeCursor_.pixmap().toImage() ) );
281 
282 
283  // get the hotspot from the cursor
284  xOff_ = nativeCursor_.hotSpot().x();
285  yOff_ = nativeCursor_.hotSpot().y();
286  break;
287  default:
288  std::cerr << "cursorToTexture: Unknown cursor shape!" << nativeCursor_.shape() << std::endl;
289  return;
290  }
291 
292  // Check if the cursor dimension is matching our requirements
293  if (cImg.width () != 32 || cImg.height () != 32) {
294  std::cerr << "cursorToTexture: Dimension error" << nativeCursor_.shape() << std::endl;
295  return;
296  }
297 
298  // convert ARGB QImage to RGBA for gl
299  int index = 0;
300  for (int y = 0; y < cImg.height (); y++)
301  for (int x = 0; x < cImg.width (); x++)
302  {
303  QRgb pix = cImg.pixel (x, y);
304  buf[index] = qRed (pix);
305  buf[index+1] = qGreen (pix);
306  buf[index+2] = qBlue (pix);
307  buf[index+3] = qAlpha (pix);
308  index += 4;
309  }
310 
311  ACG::GLState::enable (GL_TEXTURE_2D);
312  ACG::GLState::bindTexture (GL_TEXTURE_2D, texture_);
313  glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0,
314  GL_RGBA, GL_UNSIGNED_BYTE, buf);
315  ACG::GLState::bindTexture (GL_TEXTURE_2D, 0);
316  ACG::GLState::disable (GL_TEXTURE_2D);
317 
318  hasCursor_ = true;
319 }
320 
321 //-----------------------------------------------------------------------------
322 
324 {
325  mouseIn_ = _in;
326 }
327 
328 //-----------------------------------------------------------------------------
329 
331 {
332  return QRectF (-xOff_, -yOff_, 32, 32);
333 }
334 
335 //=============================================================================
336 //=============================================================================
337 
338 void CursorPainter::setForceNative(bool _enabled)
339 {
340  forceNative_ = _enabled;
341 
342  if (!(initialized_ && enabled_ && hasCursor_) || forceNative_)
343  {
344  foreach (glViewer *v, views_)
345  v->setCursor ((forceNative_)? nativeCursor_ : cursor_);
346 
347  }
348  else
349  {
350  foreach (glViewer *v, views_)
351  v->setCursor (Qt::BlankCursor);
352  }
353 }
354 
355 void CursorPainter::cursorToCursor()
356 {
357  QPixmap pix;
358 
359  switch (nativeCursor_.shape())
360  {
361  case Qt::ArrowCursor:
362  pix.load (OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cursor_arrow.png");
363  if (!pix.isNull() && pix.width() == 32 && pix.height() == 32)
364  {
365  cursor_ = QCursor (pix, 0, 0);
366  }
367  else
368  cursor_ = nativeCursor_;
369  break;
370  case Qt::PointingHandCursor:
371  pix.load (OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"cursor_move.png");
372  if (!pix.isNull() && pix.width() == 32 && pix.height() == 32)
373  {
374  cursor_ = QCursor (pix, 0, 0);
375  }
376  else
377  cursor_ = nativeCursor_;
378  break;
379  default:
380  cursor_ = nativeCursor_;
381  return;
382  }
383 }
384 
385 
386 
CursorPainter(QObject *_parent=0)
Constructor.
static void enable(GLenum _cap)
replaces glEnable, but supports locking
Definition: GLState.cc:1490
void setMouseIn(bool _in)
Inform the cursor painter about mouse enter / leave.
void updateCursorPosition(QPointF _scenePos)
Sets the current cursor position.
void registerViewer(glViewer *_viewer)
Add a glViewer that will use this CursorPainter.
void setEnabled(bool _enabled)
Enabled/Disables gl cursor painting.
bool enabled()
Returns true if cursor painting is enabled and compatible cursor is set.
QRectF cursorBoundingBox()
Bounding box of the cursor.
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:638
void paintCursor(ACG::GLState *_state)
Cursor painting function. The _state has to be setup that 0,0,0 is at the cursor position.
~CursorPainter()
Destructor.
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:649
QPointF cursorPosition()
Return the current cursor position.
static void disable(GLenum _cap)
replaces glDisable, but supports locking
Definition: GLState.cc:1504
void setForceNative(bool _enabled)
Enabled/Disables native cursors.
void initializeGL()
Needs to be called after the gl context has been set up to initialize internal values.
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1812
void setCursor(const QCursor &_cursor)
Sets the current used cursor.
void cursorToTexture()
void setCursorPainter(CursorPainter *_cursorPainter)
sets the current cursor painter
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:314