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