1
2 /*
3 Copyright (c) 2008 Andrew Caudwell (acaudwell@gmail.com)
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "display.h"
30 #include "sdlapp.h"
31 #include <iostream>
32
33 #if SDL_VERSION_ATLEAST(2,0,0)
34 #include "SDL_syswm.h"
35 #endif
36
37 SDLAppDisplay display;
38
SDLAppDisplay()39 SDLAppDisplay::SDLAppDisplay() {
40 clear_colour = vec4(0.0f,0.0f,0.0f,1.0f);
41 zbuffer_depth = 16;
42 enable_alpha = false;
43 vsync = false;
44 resizable = false;
45 frameless = false;
46 multi_sample = 0;
47 width = 0;
48 height = 0;
49 desktop_width = 0;
50 desktop_height = 0;
51 windowed_width = 0;
52 windowed_height = 0;
53 #if SDL_VERSION_ATLEAST(2,0,0)
54 sdl_window = 0;
55 gl_context = 0;
56
57 framed_width = 0;
58 framed_height = 0;
59 framed_x = 0;
60 framed_y = 0;
61 #else
62 surface = 0;
63 #endif
64
65 }
66
~SDLAppDisplay()67 SDLAppDisplay::~SDLAppDisplay() {
68 }
69
setClearColour(vec3 colour)70 void SDLAppDisplay::setClearColour(vec3 colour) {
71 setClearColour(vec4(colour, enable_alpha ? 0.0f : 1.0f));
72 }
73
setClearColour(vec4 colour)74 void SDLAppDisplay::setClearColour(vec4 colour) {
75 clear_colour = colour;
76 }
77
SDLWindowFlags(bool fullscreen)78 Uint32 SDLAppDisplay::SDLWindowFlags(bool fullscreen) {
79 #if SDL_VERSION_ATLEAST(2,0,0)
80 Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
81
82 if (frameless) flags |= SDL_WINDOW_BORDERLESS;
83 if (resizable && !frameless) flags |= SDL_WINDOW_RESIZABLE;
84 if (fullscreen) flags |= SDL_WINDOW_FULLSCREEN;
85 #else
86 Uint32 flags = SDL_OPENGL | SDL_HWSURFACE | SDL_ANYFORMAT | SDL_DOUBLEBUF;
87
88 if (frameless) flags |= SDL_NOFRAME;
89 if (resizable && !fullscreen) flags |= SDL_RESIZABLE;
90 if (fullscreen) flags |= SDL_FULLSCREEN;
91 #endif
92 return flags;
93 }
94
enableVsync(bool vsync)95 void SDLAppDisplay::enableVsync(bool vsync) {
96 this->vsync = vsync;
97 }
98
setZBufferDepth(int zbuffer_depth)99 void SDLAppDisplay::setZBufferDepth(int zbuffer_depth) {
100 this->zbuffer_depth = zbuffer_depth;
101 }
102
enableResize(bool resizable)103 void SDLAppDisplay::enableResize(bool resizable) {
104 this->resizable = resizable;
105 }
106
enableFrameless(bool frameless)107 void SDLAppDisplay::enableFrameless(bool frameless) {
108 this->frameless = frameless;
109 }
110
enableAlpha(bool enable)111 void SDLAppDisplay::enableAlpha(bool enable) {
112 enable_alpha = enable;
113 }
114
multiSample(int samples)115 void SDLAppDisplay::multiSample(int samples) {
116 multi_sample = samples;
117 }
118
setupExtensions()119 void SDLAppDisplay::setupExtensions() {
120
121 GLenum err = glewInit();
122
123 if (GLEW_OK != err) {
124 /* Problem: glewInit failed, something is seriously wrong. */
125 char glewerr[1024];
126 snprintf(glewerr, 1024, "GLEW Error: %s", glewGetErrorString(err));
127
128 throw SDLInitException(std::string(glewerr));
129 }
130 }
131
multiSamplingEnabled()132 bool SDLAppDisplay::multiSamplingEnabled() {
133 int value;
134 SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &value );
135 return value==1;
136 }
137
138 #if SDL_VERSION_ATLEAST(2,0,0) && defined(_WIN32)
139 WNDPROC window_proc = 0;
140
window_filter_proc(HWND wnd,UINT msg,WPARAM wparam,LPARAM lparam)141 LRESULT CALLBACK window_filter_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) {
142
143 if (msg == WM_SYSCOMMAND && (wparam & 0xfff0) == SC_KEYMENU) {
144 return 0;
145 }
146
147 return CallWindowProc(window_proc, wnd, msg, wparam, lparam);
148 }
149 #endif
150
setVideoMode(int width,int height,bool fullscreen,int screen)151 void SDLAppDisplay::setVideoMode(int width, int height, bool fullscreen, int screen) {
152 #if SDL_VERSION_ATLEAST(2,0,0)
153
154 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
155 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, zbuffer_depth);
156
157 if(multi_sample > 0) {
158 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
159 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (GLuint) multi_sample);
160 }
161
162 if(enable_alpha) {
163 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
164 }
165
166 Uint32 flags = SDLWindowFlags(fullscreen);
167
168 if(gl_context != 0) SDL_GL_DeleteContext(gl_context);
169
170
171 int position_x = -1;
172 int position_y = -1;
173
174 int display_index = -1;
175
176 if(sdl_window != 0) {
177 display_index = SDL_GetWindowDisplayIndex(sdl_window);
178 SDL_GetWindowPosition(sdl_window, &position_x, &position_y);
179 SDL_DestroyWindow(sdl_window);
180
181 } else if(screen > 0 && screen <= SDL_GetNumVideoDisplays()) {
182 display_index = screen-1;
183 }
184
185 if(display_index != -1) {
186 sdl_window = SDL_CreateWindow(gSDLAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED_DISPLAY(display_index), SDL_WINDOWPOS_UNDEFINED_DISPLAY(display_index), width, height, flags);
187
188 if(sdl_window && position_x >= 0 && position_y >= 0) {
189 SDL_SetWindowPosition(sdl_window, position_x, position_y);
190 }
191
192 } else {
193 sdl_window = SDL_CreateWindow(gSDLAppTitle.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, flags);
194 }
195
196 if (!sdl_window) {
197
198 // retry without multi-sampling enabled
199 if(multi_sample > 0) {
200 multi_sample = 0;
201 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
202 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
203
204 if(display_index != -1) {
205 sdl_window = SDL_CreateWindow(gSDLAppTitle.c_str(), SDL_WINDOWPOS_UNDEFINED_DISPLAY(display_index), SDL_WINDOWPOS_UNDEFINED_DISPLAY(display_index), width, height, flags);
206
207 if(sdl_window && position_x >= 0 && position_y >= 0) {
208 SDL_SetWindowPosition(sdl_window, position_x, position_y);
209 }
210 } else {
211 sdl_window = SDL_CreateWindow(gSDLAppTitle.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, flags);
212 }
213 }
214
215 if(!sdl_window) {
216 std::string sdlerr(SDL_GetError());
217 throw SDLInitException(sdlerr);
218 }
219 }
220
221 gl_context = SDL_GL_CreateContext(sdl_window);
222
223 if(!gl_context) {
224 std::string sdlerr(SDL_GetError());
225 throw SDLInitException(sdlerr);
226 }
227
228 if(vsync) SDL_GL_SetSwapInterval(1);
229 else SDL_GL_SetSwapInterval(0);
230
231 #else
232 int bpp = 32;
233
234 int flags = SDLWindowFlags(fullscreen);
235
236 if(vsync) SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
237 else SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0);
238
239 if(multi_sample > 0) {
240 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
241 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (GLuint) multi_sample);
242 }
243
244 if(enable_alpha) {
245 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
246 }
247
248 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, zbuffer_depth);
249 surface = SDL_SetVideoMode(width, height, bpp, flags);
250
251 if (!surface) {
252 if (multi_sample > 0) {
253 #ifndef _WIN32
254 // Retry without multi-sampling before failing
255 std::cerr << "Failed to set video mode: " << SDL_GetError() << std::endl
256 << "Trying again without multi-sampling" << std::endl;
257 #endif
258 multi_sample = 0;
259 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
260 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
261 surface = SDL_SetVideoMode(width, height, bpp, flags);
262 }
263
264 if (!surface) {
265 std::string sdlerr(SDL_GetError());
266 throw SDLInitException(sdlerr);
267 }
268 }
269 #endif
270
271 setupExtensions();
272
273 #if SDL_VERSION_ATLEAST(2,0,0) && defined(_WIN32)
274 // suppress 'ding' noise when doing alt+key combinations
275 // solution from: http://forums.libsdl.org/viewtopic.php?t=6075
276
277 SDL_SysWMinfo sys_window_info;
278
279 SDL_VERSION(&sys_window_info.version);
280
281 if(SDL_GetWindowWMInfo(sdl_window, &sys_window_info)) {
282 HWND wnd = sys_window_info.info.win.window;
283 window_proc = (WNDPROC) GetWindowLongPtr(wnd, GWLP_WNDPROC);
284 SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR) &window_filter_proc);
285 }
286 #endif
287 }
288
getFullscreenResolution(int & width,int & height)289 void SDLAppDisplay::getFullscreenResolution(int& width, int& height) {
290
291 int fullscreen_width = desktop_width;
292 int fullscreen_height = desktop_height;
293
294 #if SDL_VERSION_ATLEAST(2,0,0)
295 // TODO: SDL2 api will have a nice way to do this ...
296 #else
297 float aspect_ratio = fullscreen_width / (float) fullscreen_height;
298
299 if(aspect_ratio > 2.5) {
300
301 SDL_Rect** modes = SDL_ListModes(0, SDLWindowFlags(true));
302
303 if(modes != (SDL_Rect**)0 && modes != (SDL_Rect**)-1) {
304
305 for (int i=0; modes[i]; i++) {
306 if(modes[i]->h == fullscreen_height && (modes[i]->w/(float)modes[i]->h) < 2.5) {
307 fullscreen_width = modes[i]->w;
308 break;
309 }
310 }
311 }
312 }
313 #endif
314 width = fullscreen_width;
315 height = fullscreen_height;
316 }
317
toggleFullscreen()318 void SDLAppDisplay::toggleFullscreen() {
319
320 int width = this->width;
321 int height = this->height;
322
323 if(!fullscreen) {
324
325 //save windowed width and height
326 windowed_width = width;
327 windowed_height = height;
328
329 getFullscreenResolution(width, height);
330
331 } else {
332 //switch back to window dimensions, if known
333 if(windowed_width != 0) {
334 width = windowed_width;
335 height = windowed_height;
336 }
337 }
338
339 fullscreen = !fullscreen;
340
341 int resized_width, resized_height;
342
343 #if SDL_VERSION_ATLEAST(2,0,0)
344 SDL_SetWindowFullscreen(sdl_window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
345 SDL_GetWindowSize(sdl_window, &resized_width, &resized_height);
346 #else
347 setVideoMode(width, height, fullscreen);
348
349 const SDL_VideoInfo* display_info = SDL_GetVideoInfo();
350
351 resized_width = display_info->current_w;
352 resized_height = display_info->current_h;
353 #endif
354
355 //set viewport to match what we ended up on
356 glViewport(0, 0, resized_width, resized_height);
357
358 this->width = resized_width;
359 this->height = resized_height;
360 }
361
toggleFrameless()362 void SDLAppDisplay::toggleFrameless() {
363 #if SDL_VERSION_ATLEAST(2,0,0)
364 if(fullscreen) return;
365
366 frameless = !frameless;
367
368 if(frameless) {
369
370 int position_x, position_y;
371 SDL_GetWindowPosition(sdl_window, &position_x, &position_y);
372
373 framed_width = width;
374 framed_height = height;
375 framed_x = position_x;
376 framed_y = position_y;
377
378 #ifdef _WIN32
379 SDL_SysWMinfo sys_window_info;
380 SDL_VERSION(&sys_window_info.version);
381
382 if(SDL_GetWindowWMInfo(sdl_window, &sys_window_info)) {
383
384 //make the new window equal the size of the old window including frame
385
386 HWND wnd = sys_window_info.info.win.window;
387
388 RECT rect;
389 GetWindowRect(wnd, &rect);
390
391 position_x = rect.left;
392 position_y = rect.top;
393
394 width = rect.right - rect.left;
395 height = rect.bottom - rect.top;
396 }
397 #endif
398
399 //work around window position changing when when frame is toggled
400 //related bug: https://bugzilla.libsdl.org/show_bug.cgi?id=2791
401
402 SDL_SetWindowBordered(sdl_window, SDL_FALSE);
403 SDL_SetWindowSize(sdl_window, width, height);
404 SDL_SetWindowPosition(sdl_window, position_x, position_y);
405
406 //window needs to be recreated to remove SDL_WINDOW_RESIZABLE flag
407 //otherwise there is still a weird border
408
409 setVideoMode(width, height, fullscreen);
410
411 } else {
412
413 #ifdef _WIN32
414 // handle computing framed window position
415 // if launched in frameless mode initially
416 if(framed_width == 0) {
417 SDL_SysWMinfo sys_window_info;
418 SDL_VERSION(&sys_window_info.version);
419
420 if(SDL_GetWindowWMInfo(sdl_window, &sys_window_info)) {
421
422 HWND wnd = sys_window_info.info.win.window;
423
424 RECT old_rect;
425 GetWindowRect(wnd, &old_rect);
426
427 SDL_SetWindowBordered(sdl_window, SDL_TRUE);
428
429 RECT new_rect;
430 GetWindowRect(wnd, &new_rect);
431
432 SDL_GetWindowSize(sdl_window, &framed_width, &framed_height);
433 SDL_GetWindowPosition(sdl_window, &framed_x, &framed_y);
434
435 int width_delta = (new_rect.right - new_rect.left) - (old_rect.right - old_rect.left);
436 int height_delta = (new_rect.bottom - new_rect.top) - (old_rect.bottom - old_rect.top);
437
438 framed_width = width - width_delta;
439 framed_height = height - height_delta;
440
441 framed_x += width_delta;
442 framed_y += height_delta;
443
444 // HACK: account for the resizable windows border being 2 pixels wider
445
446 if(resizable) {
447 framed_x += 2;
448 framed_y += 2;
449 }
450 }
451 }
452 #endif
453 SDL_SetWindowBordered(sdl_window, SDL_TRUE);
454
455 if(framed_width > 0) {
456 width = framed_width;
457 height = framed_height;
458 }
459
460 SDL_SetWindowSize(sdl_window, width, height);
461
462 if(framed_width > 0) {
463 SDL_SetWindowPosition(sdl_window, framed_x, framed_y);
464 }
465
466 setVideoMode(width, height, fullscreen);
467 }
468 #endif
469 }
470
isFullscreen() const471 bool SDLAppDisplay::isFullscreen() const {
472 return fullscreen;
473 }
474
isFrameless() const475 bool SDLAppDisplay::isFrameless() const {
476 return frameless;
477 }
478
resize(int width,int height)479 void SDLAppDisplay::resize(int width, int height) {
480
481 int resized_width, resized_height;
482
483 #if SDL_VERSION_ATLEAST(2,0,0)
484 SDL_GetWindowSize(sdl_window, &resized_width, &resized_height);
485 #else
486 setVideoMode(width, height, fullscreen);
487
488 const SDL_VideoInfo* display_info = SDL_GetVideoInfo();
489
490 resized_width = display_info->current_w;
491 resized_height = display_info->current_h;
492 #endif
493
494 //set viewport to match what we ended up on
495 glViewport(0, 0, resized_width, resized_height);
496
497 this->width = resized_width;
498 this->height = resized_height;
499 }
500
init(std::string window_title,int width,int height,bool fullscreen,int screen)501 void SDLAppDisplay::init(std::string window_title, int width, int height, bool fullscreen, int screen) {
502
503 if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO) != 0) {
504 throw SDLInitException(SDL_GetError());
505 }
506
507
508 #if SDL_VERSION_ATLEAST(2,0,0)
509
510 // check screen is valid
511 if(screen <= 0 || screen > SDL_GetNumVideoDisplays()) {
512 screen = -1;
513 }
514
515 SDL_Rect display_rect;
516 SDL_GetDisplayBounds(screen > 0 ? screen-1 : 0, &display_rect);
517
518 desktop_width = display_rect.w;
519 desktop_height = display_rect.h;
520
521 #else
522 const SDL_VideoInfo* display_info = SDL_GetVideoInfo();
523
524 //save the desktop resolution
525 desktop_width = display_info->current_w;
526 desktop_height = display_info->current_h;
527 #endif
528
529 //initialize width and height to desktop resolution if un-specified
530 if(!width || !height) {
531 if(fullscreen) {
532 getFullscreenResolution(width, height);
533 } else {
534 if(!width) width = desktop_width;
535 if(!height) height = desktop_height;
536 }
537 }
538
539 atexit(SDL_Quit);
540
541 #if SDL_VERSION_ATLEAST(2,0,0)
542
543 #else
544 SDL_EnableUNICODE(1);
545 SDL_WM_SetCaption(window_title.c_str(),0);
546 #endif
547
548 setVideoMode(width, height, fullscreen, screen);
549
550 //get actual opengl viewport
551 GLint viewport[4];
552 glGetIntegerv( GL_VIEWPORT, viewport );
553
554 this->width = viewport[2];
555 this->height = viewport[3];
556 this->fullscreen = fullscreen;
557
558 glViewport(0, 0, this->width, this->height);
559 }
560
quit()561 void SDLAppDisplay::quit() {
562
563 #if SDL_VERSION_ATLEAST(2,0,0)
564 if(gl_context != 0) SDL_GL_DeleteContext(gl_context);
565 if(sdl_window != 0) SDL_DestroyWindow(sdl_window);
566 #endif
567
568 texturemanager.purge();
569 shadermanager.purge();
570 fontmanager.purge();
571 fontmanager.destroy();
572 }
573
update()574 void SDLAppDisplay::update() {
575 #if SDL_VERSION_ATLEAST(2,0,0)
576 SDL_GL_SwapWindow(sdl_window);
577 #else
578 SDL_GL_SwapBuffers();
579 #endif
580 }
581
clear()582 void SDLAppDisplay::clear() {
583 glClearColor(clear_colour.x, clear_colour.y, clear_colour.z, clear_colour.w);
584 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
585 }
586
mode3D(float fov,float znear,float zfar)587 void SDLAppDisplay::mode3D(float fov, float znear, float zfar) {
588 glMatrixMode(GL_PROJECTION);
589 glLoadIdentity();
590 gluPerspective(fov, (GLfloat)width/(GLfloat)height, znear, zfar);
591 glMatrixMode(GL_MODELVIEW);
592 glLoadIdentity();
593 }
594
mode2D()595 void SDLAppDisplay::mode2D() {
596 glMatrixMode(GL_PROJECTION);
597 glLoadIdentity();
598 glOrtho(0, width, height, 0, -1.0, 1.0);
599 glMatrixMode(GL_MODELVIEW);
600 glLoadIdentity();
601 }
602
push2D()603 void SDLAppDisplay::push2D() {
604 glMatrixMode(GL_PROJECTION);
605 glPushMatrix();
606 glLoadIdentity();
607 glOrtho(0, display.width, display.height, 0, -1.0, 1.0);
608
609 glMatrixMode(GL_MODELVIEW);
610 glPushMatrix();
611 glLoadIdentity();
612 }
613
pop2D()614 void SDLAppDisplay::pop2D() {
615 glMatrixMode(GL_PROJECTION);
616 glPopMatrix();
617 glMatrixMode(GL_MODELVIEW);
618 glPopMatrix();
619 }
620
currentColour()621 vec4 SDLAppDisplay::currentColour() {
622 vec4 colour;
623 glGetFloatv(GL_CURRENT_COLOR, glm::value_ptr(colour));
624 return colour;
625 }
626
project(vec3 pos)627 vec3 SDLAppDisplay::project(vec3 pos) {
628 GLint viewport[4];
629 GLdouble modelview[16];
630 GLdouble projection[16];
631 GLdouble winX, winY, winZ;
632
633 glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
634 glGetDoublev( GL_PROJECTION_MATRIX, projection );
635 glGetIntegerv( GL_VIEWPORT, viewport );
636
637 gluProject( pos.x, pos.y, pos.z, modelview, projection, viewport, &winX, &winY, &winZ);
638
639 winY = (float)viewport[3] - winY;
640
641 return vec3((float) winX, (float) winY, (float) winZ);
642 }
643
unproject(vec2 pos)644 vec3 SDLAppDisplay::unproject(vec2 pos) {
645 GLint viewport[4];
646 GLdouble modelview[16];
647 GLdouble projection[16];
648 GLfloat winX, winY, winZ;
649 GLdouble posX, posY, posZ;
650
651 glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
652 glGetDoublev( GL_PROJECTION_MATRIX, projection );
653 glGetIntegerv( GL_VIEWPORT, viewport );
654
655 winX = pos.x;
656 winY = (float)viewport[3] - pos.y;
657 glReadPixels( int(winX), int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
658 gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
659
660 return vec3((float) posX, (float) posY, (float) posZ);
661 }
662