Line data Source code
1 :
2 : /* Copyright (c) 2014-2015, Daniel Nachbaur <danielnachbaur@gmail.com>
3 : * Juan Hernando <jhernando@fi.upm.es>
4 : * Stefan.Eilemann@epfl.ch
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #ifndef EQ_QT_WINDOWIMPL_H
21 : #define EQ_QT_WINDOWIMPL_H
22 :
23 : #include "eventHandler.h"
24 :
25 : #include <eq/util/frameBufferObject.h>
26 : #include <lunchbox/monitor.h>
27 :
28 : #include <QExposeEvent>
29 : #include <QOpenGLContext>
30 : #include <QOffscreenSurface>
31 : #include <QWindow>
32 :
33 : namespace eq
34 : {
35 : namespace qt
36 : {
37 : namespace detail
38 : {
39 : namespace
40 : {
41 : #define getAttribute( attr ) settings.getIAttribute( WindowSettings::attr )
42 :
43 0 : QSurfaceFormat _createFormat( const WindowSettings& settings )
44 : {
45 : // defaults: http://doc.qt.io/qt-5/qsurfaceformat.html
46 0 : QSurfaceFormat format;
47 :
48 0 : const int coreProfile = getAttribute( IATTR_HINT_CORE_PROFILE );
49 0 : if( coreProfile == ON )
50 : {
51 0 : format.setMajorVersion( getAttribute( IATTR_HINT_OPENGL_MAJOR ));
52 0 : format.setMinorVersion( getAttribute( IATTR_HINT_OPENGL_MINOR ));
53 0 : format.setProfile( QSurfaceFormat::CoreProfile );
54 : }
55 :
56 0 : const int colorSize = getAttribute( IATTR_PLANES_COLOR );
57 0 : if( colorSize > 0 || colorSize == eq::AUTO )
58 : {
59 0 : const int colorBits = ( colorSize > 0 ? colorSize : 8 );
60 0 : format.setRedBufferSize( colorBits );
61 0 : format.setGreenBufferSize( colorBits );
62 0 : format.setBlueBufferSize( colorBits );
63 : }
64 :
65 0 : const int alphaPlanes = getAttribute( IATTR_PLANES_ALPHA );
66 0 : if( alphaPlanes > 0 || alphaPlanes == eq::AUTO )
67 : {
68 0 : const int alphaBits = ( alphaPlanes > 0 ? alphaPlanes : 8 );
69 0 : format.setAlphaBufferSize( alphaBits );
70 : }
71 :
72 0 : const int depthPlanes = getAttribute( IATTR_PLANES_DEPTH );
73 0 : if( depthPlanes > 0 || depthPlanes == eq::AUTO )
74 : {
75 0 : const int depthBits = ( depthPlanes > 0 ? depthPlanes : 8 );
76 0 : format.setDepthBufferSize( depthBits );
77 : }
78 : else
79 0 : format.setDepthBufferSize( 0 );
80 :
81 0 : const int stencilPlanes = getAttribute( IATTR_PLANES_STENCIL );
82 0 : if( stencilPlanes > 0 || stencilPlanes == eq::AUTO )
83 : {
84 0 : const int stencilBits = ( stencilPlanes > 0 ? stencilPlanes : 8 );
85 0 : format.setStencilBufferSize( stencilBits );
86 : }
87 : else
88 0 : format.setStencilBufferSize( 0 );
89 :
90 0 : const int samplesPlanes = getAttribute( IATTR_PLANES_SAMPLES );
91 0 : if( samplesPlanes >= 0 )
92 : {
93 0 : format.setSamples( samplesPlanes );
94 : }
95 :
96 0 : if( getAttribute( IATTR_HINT_STEREO ) == eq::ON )
97 : {
98 0 : format.setStereo( true );
99 : }
100 :
101 0 : if( getAttribute( IATTR_HINT_DOUBLEBUFFER ) == eq::ON ||
102 0 : ( getAttribute( IATTR_HINT_DOUBLEBUFFER ) == eq::AUTO &&
103 0 : getAttribute( IATTR_HINT_DRAWABLE ) == eq::WINDOW ))
104 : {
105 0 : format.setSwapBehavior( QSurfaceFormat::DoubleBuffer );
106 : }
107 : else
108 0 : format.setSwapBehavior( QSurfaceFormat::SingleBuffer );
109 :
110 0 : return format;
111 : }
112 : }
113 :
114 : class Window
115 : {
116 : public:
117 0 : Window() : _eventHandler( 0 ) {}
118 :
119 0 : virtual ~Window() {}
120 : virtual QOpenGLContext* getContext() const = 0;
121 : virtual void makeCurrent() = 0;
122 : virtual void doneCurrent() = 0;
123 : virtual void swapBuffers() = 0;
124 0 : virtual bool configInit( eq::qt::Window& window )
125 : {
126 0 : _eventHandler = new EventHandler( window );
127 0 : return true;
128 : }
129 0 : virtual bool configExit()
130 : {
131 0 : delete _eventHandler;
132 0 : _eventHandler = 0;
133 0 : return true;
134 : }
135 :
136 0 : virtual QObject *getEventProcessor() { return _eventHandler; }
137 :
138 : protected:
139 : EventHandler* _eventHandler;
140 : };
141 :
142 0 : class QWindowWrapper : public Window, public QWindow
143 : {
144 : public:
145 0 : QWindowWrapper( const WindowSettings& settings,
146 : QScreen* screen_, QOpenGLContext* shareContext )
147 0 : : _context( new QOpenGLContext )
148 0 : , _exposed( false )
149 : {
150 0 : setScreen( screen_ );
151 0 : const QSurfaceFormat& format_ = _createFormat( settings );
152 0 : setFormat( format_ );
153 0 : const PixelViewport& pvp = settings.getPixelViewport();
154 0 : setGeometry( pvp.x, pvp.y, pvp.w, pvp.h );
155 0 : setSurfaceType( QSurface::OpenGLSurface );
156 :
157 0 : _context->setFormat( format( ));
158 0 : _context->setShareContext( shareContext );
159 :
160 0 : if( settings.getIAttribute(
161 0 : WindowSettings::IATTR_HINT_FULLSCREEN ) == eq::ON )
162 : {
163 0 : showFullScreen();
164 : }
165 : else
166 0 : show();
167 0 : }
168 :
169 0 : QOpenGLContext* getContext() const final
170 : {
171 0 : return _context.data();
172 : }
173 :
174 0 : void makeCurrent() final
175 : {
176 0 : if( !_context->makeCurrent( this ))
177 0 : LBWARN << "QOpenGLContext::makeCurrent failed: "
178 0 : << _context.data() << std::endl;
179 0 : }
180 :
181 0 : void doneCurrent() final
182 : {
183 0 : _context->doneCurrent();
184 0 : }
185 :
186 0 : void swapBuffers() final
187 : {
188 0 : if( isExposed( ))
189 0 : _context->swapBuffers( this );
190 0 : }
191 :
192 0 : bool configInit( eq::qt::Window& window ) final
193 : {
194 0 : if( !Window::configInit( window ))
195 0 : return false;
196 :
197 : // The application thread must be running the event loop somewhere
198 : // else. Otherwise this code will wait forever.
199 0 : _exposed.waitEQ( true );
200 :
201 0 : if( !_context->create( ))
202 0 : return false;
203 :
204 : // Adjusting the actual window viewport in case the window manager
205 : // disobeyed the requested geometry.
206 0 : _adjustEqWindowSize( window );
207 0 : return true;
208 : }
209 :
210 0 : QObject *getEventProcessor() final { return this; }
211 :
212 : protected:
213 0 : void exposeEvent( QExposeEvent* qevent ) final
214 : {
215 0 : _exposed = !qevent->region().isEmpty();
216 0 : _eventHandler->exposeEvent();
217 0 : }
218 :
219 0 : void hideEvent( QHideEvent* ) final
220 : {
221 0 : _exposed = false;
222 0 : _eventHandler->hideEvent();
223 0 : }
224 :
225 0 : bool event( QEvent *qevent ) final
226 : {
227 0 : if( qevent->type() == QEvent::Close )
228 0 : _eventHandler->closeEvent();
229 :
230 0 : return QWindow::event( qevent );
231 : }
232 :
233 0 : void resizeEvent( QResizeEvent* qevent ) final
234 : {
235 0 : _eventHandler->resizeEvent( qevent );
236 0 : }
237 :
238 0 : void mousePressEvent( QMouseEvent* qevent ) final
239 : {
240 0 : _eventHandler->mousePressEvent( qevent );
241 0 : }
242 :
243 0 : void mouseReleaseEvent( QMouseEvent* qevent ) final
244 : {
245 0 : _eventHandler->mouseReleaseEvent( qevent );
246 0 : }
247 :
248 0 : void mouseMoveEvent( QMouseEvent* qevent ) final
249 : {
250 0 : _eventHandler->mouseMoveEvent( qevent );
251 0 : }
252 :
253 : #ifndef QT_NO_WHEELEVENT
254 0 : void wheelEvent( QWheelEvent* qevent ) final
255 : {
256 0 : _eventHandler->wheelEvent( qevent );
257 0 : }
258 : #endif
259 0 : void keyPressEvent( QKeyEvent* qevent ) final
260 : {
261 0 : _eventHandler->keyPressEvent( qevent );
262 0 : }
263 :
264 0 : void keyReleaseEvent( QKeyEvent* qevent ) final
265 : {
266 0 : _eventHandler->keyReleaseEvent( qevent );
267 0 : }
268 :
269 : private:
270 : QScopedPointer< QOpenGLContext > _context;
271 :
272 : lunchbox::Monitorb _exposed;
273 :
274 0 : void _adjustEqWindowSize( eq::qt::Window& window )
275 : {
276 0 : PixelViewport pvp;
277 0 : pvp.x = x();
278 0 : pvp.y = y();
279 0 : pvp.w = width();
280 0 : pvp.h = height();
281 0 : window.setPixelViewport( pvp );
282 0 : }
283 : };
284 :
285 0 : class QOffscreenSurfaceWrapper : public Window, public QOffscreenSurface
286 : {
287 : public:
288 0 : QOffscreenSurfaceWrapper( const WindowSettings& settings,
289 : QScreen* screen_, QOpenGLContext* shareContext )
290 0 : : _context( new QOpenGLContext )
291 : {
292 0 : setScreen( screen_ );
293 0 : const QSurfaceFormat& format_ = _createFormat( settings );
294 0 : setFormat( format_ );
295 :
296 0 : _context->setFormat( format( ));
297 0 : _context->setShareContext( shareContext );
298 0 : create();
299 0 : }
300 :
301 0 : QOpenGLContext* getContext() const final { return _context.data(); }
302 :
303 0 : void makeCurrent() final
304 : {
305 0 : if( !_context->makeCurrent( this ))
306 0 : LBWARN << "QOpenGLContext::makeCurrent failed: "
307 0 : << _context.data() << std::endl;
308 0 : }
309 :
310 0 : void doneCurrent() final
311 : {
312 0 : _context->doneCurrent();
313 0 : }
314 :
315 0 : void swapBuffers() final
316 : {
317 0 : if( isValid( ))
318 0 : _context->swapBuffers( this );
319 0 : }
320 :
321 0 : bool configInit( eq::qt::Window& window ) final
322 : {
323 0 : return Window::configInit( window ) && isValid() && _context->create();
324 : }
325 :
326 : private:
327 : QScopedPointer< QOpenGLContext > _context;
328 : };
329 :
330 : }
331 : }
332 : }
333 :
334 : #endif
|