Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:639
static void disable(GLenum _cap)
replaces glDisable, but supports locking
Definition: GLState.cc:1518
bool enabled()
Returns true if cursor painting is enabled and compatible cursor is set.
void setForceNative(bool _enabled)
Enabled/Disables native cursors.
static void enable(GLenum _cap)
replaces glEnable, but supports locking
Definition: GLState.cc:1504
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1855
QRectF cursorBoundingBox()
Bounding box of the cursor.
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:314
CursorPainter(QObject *_parent=0)
Constructor.
void setCursor(const QCursor &_cursor)
Sets the current used cursor.
void updateCursorPosition(QPointF _scenePos)
Sets the current cursor position.
QPointF cursorPosition()
Return the current cursor position.
void initializeGL()
Needs to be called after the gl context has been set up to initialize internal values.
void registerViewer(glViewer *_viewer)
Add a glViewer that will use this CursorPainter.
void setCursorPainter(CursorPainter *_cursorPainter)
sets the current cursor painter
void cursorToTexture()
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.
void setMouseIn(bool _in)
Inform the cursor painter about mouse enter / leave.
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:650
void setEnabled(bool _enabled)
Enabled/Disables gl cursor painting.