From 48cc1aa496de23a02fa3a236a0078f4df53d46f1 Mon Sep 17 00:00:00 2001 From: Ed Swartz Date: Fri, 17 Apr 2015 13:20:14 -0500 Subject: [PATCH 01/10] Implement an M_confined mouse mode to ensure mouse stays in window. --- panda/src/display/graphicsWindow.cxx | 22 +--- panda/src/display/windowProperties.I | 35 ++++-- panda/src/display/windowProperties.cxx | 4 + panda/src/display/windowProperties.h | 1 + panda/src/windisplay/winGraphicsWindow.cxx | 46 +++++++ panda/src/windisplay/winGraphicsWindow.h | 3 + panda/src/x11display/x11GraphicsWindow.cxx | 132 ++++++++++++++------- 7 files changed, 169 insertions(+), 74 deletions(-) diff --git a/panda/src/display/graphicsWindow.cxx b/panda/src/display/graphicsWindow.cxx index caee3ea4ed..6166f9cbac 100644 --- a/panda/src/display/graphicsWindow.cxx +++ b/panda/src/display/graphicsWindow.cxx @@ -736,24 +736,10 @@ set_properties_now(WindowProperties &properties) { // Fullscreen property specified, but unchanged. properties.clear_fullscreen(); } - if (properties.has_mouse_mode() ) { - - if (properties.get_mouse_mode() == _properties.get_mouse_mode()) { - properties.clear_mouse_mode(); - } - else { - if(properties.get_mouse_mode() == WindowProperties::M_absolute) { - _properties.set_mouse_mode(WindowProperties::M_absolute); - mouse_mode_absolute(); - properties.clear_mouse_mode(); - } - else - { - _properties.set_mouse_mode(WindowProperties::M_relative); - mouse_mode_relative(); - properties.clear_mouse_mode(); - } - } + if (properties.has_mouse_mode() && + properties.get_mouse_mode() == _properties.get_mouse_mode()) { + // Mouse mode specified, but unchanged. + properties.clear_mouse_mode(); } } diff --git a/panda/src/display/windowProperties.I b/panda/src/display/windowProperties.I index ca307062a4..3597adbc55 100644 --- a/panda/src/display/windowProperties.I +++ b/panda/src/display/windowProperties.I @@ -798,19 +798,30 @@ clear_z_order() { // Function: WindowProperties::set_mouse_mode // Access: Published // Description: Specifies the mode in which the window is to operate -// its mouse pointer. The default is M_absolute, which -// is the normal mode in which a mouse pointer operates; -// but you can also set M_relative, which is -// particularly useful for FPS-style mouse movements -// where you have hidden the mouse pointer and are are -// more interested in how fast the mouse is moving, -// rather than precisely where the pointer is hovering. +// its mouse pointer. +// +// M_absolute: the normal mode in which a mouse pointer +// operates, where the mouse can move outside the window +// and the mouse coordinates are relative to its +// position in the window. +// +// M_relative (OSX or Unix/X11 only): a mode where only +// relative movements are reported; particularly useful +// for FPS-style mouse movements where you have hidden +// the mouse pointer and are are more interested in how +// fast the mouse is moving, rather than precisely where +// the pointer is hovering. +// +// This has no effect on Windows. On Unix/X11, this +// requires the Xxf86dga extension to be available. +// +// M_confined: this mode reports absolute mouse +// positions, but confines the mouse pointer to +// the window boundary. It can portably replace +// M_relative for an FPS, but you need to periodically +// move the pointer to the center of the window +// and track movement deltas. // -// This has no effect on Windows, which does not -// have this concept; but is important to do on OSX -// and Unix/X11 to properly enable a smooth FPS-style -// mouselook mode. On Unix/X11, this requires the -// Xxf86dga extension to be available. //////////////////////////////////////////////////////////////////// INLINE void WindowProperties:: set_mouse_mode(MouseMode mode) { diff --git a/panda/src/display/windowProperties.cxx b/panda/src/display/windowProperties.cxx index d38241f2ce..8e4178526f 100644 --- a/panda/src/display/windowProperties.cxx +++ b/panda/src/display/windowProperties.cxx @@ -400,6 +400,8 @@ operator << (ostream &out, WindowProperties::MouseMode mode) { return out << "absolute"; case WindowProperties::M_relative: return out << "relative"; + case WindowProperties::M_confined: + return out << "confined"; } return out << "**invalid WindowProperties::MouseMode(" << (int)mode << ")**"; } @@ -413,6 +415,8 @@ operator >> (istream &in, WindowProperties::MouseMode &mode) { mode = WindowProperties::M_absolute; } else if (word == "relative") { mode = WindowProperties::M_relative; + } else if (word == "confined") { + mode = WindowProperties::M_confined; } else { display_cat.warning() << "Unknown mouse mode: " << word << "\n"; diff --git a/panda/src/display/windowProperties.h b/panda/src/display/windowProperties.h index 5f8a6bb32d..dc0fcac84f 100644 --- a/panda/src/display/windowProperties.h +++ b/panda/src/display/windowProperties.h @@ -40,6 +40,7 @@ PUBLISHED: enum MouseMode { M_absolute, M_relative, + M_confined, }; WindowProperties(); diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index 99d4c9629e..d4fcf6a9e2 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -35,6 +35,8 @@ WinGraphicsWindow *WinGraphicsWindow::_creating_window = NULL; WinGraphicsWindow *WinGraphicsWindow::_cursor_window = NULL; bool WinGraphicsWindow::_cursor_hidden = false; +RECT WinGraphicsWindow::_mouse_unconfined_cliprect; + // These are used to save the previous state of the fancy Win2000 // effects that interfere with rendering when the mouse wanders into a // window's client area. @@ -359,6 +361,50 @@ set_properties_now(WindowProperties &properties) { } } } + + if (properties.has_mouse_mode()) { + if (properties.get_mouse_mode() != _properties.get_mouse_mode()) { + switch (properties.get_mouse_mode()) { + case WindowProperties::M_absolute: + case WindowProperties::M_relative: // not implemented, treat as absolute + + if (_properties.get_mouse_mode() == WindowProperties::M_confined) { + ClipCursor(NULL); + windisplay_cat.info() << "Unconfining cursor from window\n"; + } + _properties.set_mouse_mode(WindowProperties::M_absolute); + break; + + case WindowProperties::M_confined: + { + RECT clip; + + if (!GetWindowRect(_hWnd, &clip)) { + if (windisplay_cat.is_debug()) { + windisplay_cat.debug() + << "GetWindowRect() failed in set_properties_now. Cannot confine cursor.\n"; + } + } else { + windisplay_cat.debug() + << "ClipCursor() to " << clip.left << "," << clip.top << " to " + << clip.right << "," << clip.bottom << endl; + + GetClipCursor(&_mouse_unconfined_cliprect); + if (!ClipCursor(&clip)) { + windisplay_cat.debug() + << "ClipCursor() failed in set_properties_now. Ignoring.\n"; + } else { + _properties.set_mouse_mode(WindowProperties::M_confined); + windisplay_cat.info() << "Confining cursor to window\n"; + } + } + } + break; + } + } + properties.clear_mouse_mode(); + } + } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index cbd7c46bb6..1b3ee93f95 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -214,6 +214,9 @@ private: static BOOL _saved_cursor_shadow; static BOOL _saved_mouse_vanish; + // The mouse constraints before applying mouse mode M_confined. + static RECT _mouse_unconfined_cliprect; + // Since the Panda API requests icons and cursors by filename, we // need a table mapping filenames to handles, so we can avoid // re-reading the file each time we change icons. diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 7f090ecd5c..f1484522a1 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -711,6 +711,92 @@ set_properties_now(WindowProperties &properties) { properties.clear_foreground(); } + if (properties.has_mouse_mode()) { + switch (properties.get_mouse_mode()) { + case WindowProperties::M_absolute: + XUngrabPointer(_display, CurrentTime); +#ifdef HAVE_XF86DGA + if (_dga_mouse_enabled) { + x11display_cat.info() << "Disabling relative mouse using XF86DGA extension\n"; + XF86DGADirectVideo(_display, _screen, 0); + _dga_mouse_enabled = false; + } +#endif + _properties.set_mouse_mode(WindowProperties::M_absolute); + properties.clear_mouse_mode(); + break; + + case WindowProperties::M_relative: +#ifdef HAVE_XF86DGA + if (!_dga_mouse_enabled) { + int major_ver, minor_ver; + if (XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) { + + X11_Cursor cursor = None; + if (_properties.get_cursor_hidden()) { + x11GraphicsPipe *x11_pipe; + DCAST_INTO_V(x11_pipe, _pipe); + cursor = x11_pipe->get_hidden_cursor(); + } + + if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, + GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) { + x11display_cat.error() << "Failed to grab pointer!\n"; + } else { + x11display_cat.info() << "Enabling relative mouse using XF86DGA extension\n"; + XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse); + + _properties.set_mouse_mode(WindowProperties::M_relative); + _dga_mouse_enabled = true; + + // Get the real mouse position, so we can add/subtract + // our relative coordinates later. + XEvent event; + XQueryPointer(_display, _xwindow, &event.xbutton.root, + &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, + &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); + _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); + } + } else { + x11display_cat.info() << "XF86DGA extension not available\n"; + _dga_mouse_enabled = false; + } + } + else +#endif + { + // can't change + properties.clear_mouse_mode(); + } + break; + + case WindowProperties::M_confined: + { +#ifdef HAVE_XF86DGA + if (_dga_mouse_enabled) { + XF86DGADirectVideo(_display, _screen, 0); + _dga_mouse_enabled = false; + } +#endif + X11_Cursor cursor = None; + if (_properties.get_cursor_hidden()) { + x11GraphicsPipe *x11_pipe; + DCAST_INTO_V(x11_pipe, _pipe); + cursor = x11_pipe->get_hidden_cursor(); + } + + if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, + GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) { + x11display_cat.error() << "Failed to grab pointer!\n"; + } else { + _properties.set_mouse_mode(WindowProperties::M_confined); + properties.clear_mouse_mode(); + } + } + break; + } + } + set_wm_properties(wm_properties, true); } @@ -721,14 +807,7 @@ set_properties_now(WindowProperties &properties) { //////////////////////////////////////////////////////////////////// void x11GraphicsWindow:: mouse_mode_absolute() { -#ifdef HAVE_XF86DGA - if (!_dga_mouse_enabled) return; - - XUngrabPointer(_display, CurrentTime); - x11display_cat.info() << "Disabling relative mouse using XF86DGA extension\n"; - XF86DGADirectVideo(_display, _screen, 0); - _dga_mouse_enabled = false; -#endif + // unused: remove in 1.10! } //////////////////////////////////////////////////////////////////// @@ -738,42 +817,7 @@ mouse_mode_absolute() { //////////////////////////////////////////////////////////////////// void x11GraphicsWindow:: mouse_mode_relative() { -#ifdef HAVE_XF86DGA - if (_dga_mouse_enabled) return; - - int major_ver, minor_ver; - if (XF86DGAQueryVersion(_display, &major_ver, &minor_ver)) { - - X11_Cursor cursor = None; - if (_properties.get_cursor_hidden()) { - x11GraphicsPipe *x11_pipe; - DCAST_INTO_V(x11_pipe, _pipe); - cursor = x11_pipe->get_hidden_cursor(); - } - - if (XGrabPointer(_display, _xwindow, True, 0, GrabModeAsync, - GrabModeAsync, _xwindow, cursor, CurrentTime) != GrabSuccess) { - x11display_cat.error() << "Failed to grab pointer!\n"; - return; - } - - x11display_cat.info() << "Enabling relative mouse using XF86DGA extension\n"; - XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse); - - _dga_mouse_enabled = true; - } else { - x11display_cat.info() << "XF86DGA extension not available\n"; - _dga_mouse_enabled = false; - } - - // Get the real mouse position, so we can add/subtract - // our relative coordinates later. - XEvent event; - XQueryPointer(_display, _xwindow, &event.xbutton.root, - &event.xbutton.window, &event.xbutton.x_root, &event.xbutton.y_root, - &event.xbutton.x, &event.xbutton.y, &event.xbutton.state); - _input_devices[0].set_pointer_in_window(event.xbutton.x, event.xbutton.y); -#endif + // unused: remove in 1.10! } //////////////////////////////////////////////////////////////////// From f6841d7fc5f043a9f7affeb999c81eebe54c7d7b Mon Sep 17 00:00:00 2001 From: Ed Swartz Date: Fri, 17 Apr 2015 14:58:53 -0500 Subject: [PATCH 02/10] Add sample program demonstrating the mouse modes --- samples/mouse-modes/main.py | 172 ++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 samples/mouse-modes/main.py diff --git a/samples/mouse-modes/main.py b/samples/mouse-modes/main.py new file mode 100644 index 0000000000..50e81f550e --- /dev/null +++ b/samples/mouse-modes/main.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python +''' +Demonstrate different mouse modes +''' + +# from panda3d.core import loadPrcFileData +# +# loadPrcFileData("", "notify-level-x11display debug") +# loadPrcFileData("", "notify-level-windisplay debug") +# +# loadPrcFileData("", "load-display p3tinydisplay") + +from panda3d.core import WindowProperties, TextNode +from direct.task.TaskManagerGlobal import taskMgr +from direct.gui.OnscreenText import OnscreenText +from direct.task import Task +from direct.showbase.ShowBase import ShowBase + +import sys + +class App(ShowBase): + def __init__(self): + ShowBase.__init__(self) + self.base = self + self.setup() + + def genLabelText(self, text, i): + text = OnscreenText(text = text, pos = (-1.3, .5-.05*i), fg=(0,1,0,1), + align = TextNode.ALeft, scale = .05) + return text + + + def setup(self): + # Disable the camera trackball controls. + self.disableMouse() + + self.mouseMagnitude = 144 + + self.rotateX, self.rotateY = 0, 0 + + self.genLabelText("[0] Absolute mode, [1] Relative mode, [2] Confined mode", 0) + + self.base.accept('0', lambda: self.setMouseMode(WindowProperties.M_absolute)) + self.base.accept('1', lambda: self.setMouseMode(WindowProperties.M_relative)) + self.base.accept('2', lambda: self.setMouseMode(WindowProperties.M_confined)) + + self.genLabelText("[C] Manually re-center mouse on each tick", 1) + self.base.accept('C', lambda: self.toggleRecenter()) + self.base.accept('c', lambda: self.toggleRecenter()) + + self.genLabelText("[S] Show mouse", 2) + self.base.accept('S', lambda: self.toggleMouse()) + self.base.accept('s', lambda: self.toggleMouse()) + + self.base.accept('escape', sys.exit, [0]) + + self.mouseText = self.genLabelText("", 5) + self.deltaText = self.genLabelText("", 6) + self.positionText = self.genLabelText("", 8) + + self.lastMouseX, self.lastMouseY = None, None + + self.hideMouse = False + + self.setMouseMode(WindowProperties.M_absolute) + self.manualRecenterMouse = True + + # make a box to move with the mouse + self.model = self.loader.loadModel("box.egg") + self.model.reparentTo(self.render) + + self.cam.setPos(0, -5, 0) + self.cam.lookAt(0, 0, 0) + + self.mouseTask = taskMgr.add(self.mouseTask, "Mouse Task") + + def setMouseMode(self, mode): + print "Changing mode to",mode + + self.mouseMode = mode + + wp = WindowProperties() + wp.setMouseMode(mode) + self.base.win.requestProperties(wp) + + # these changes may require a tick to apply + self.base.taskMgr.doMethodLater(0, self.resolveMouse, "Resolve mouse setting") + + def resolveMouse(self, t): + wp = self.base.win.getProperties() + + actualMode = wp.getMouseMode() + if self.mouseMode != actualMode: + print "ACTUAL MOUSE MODE:", actualMode + + self.mouseMode = actualMode + + self.rotateX, self.rotateY = -.5, -.5 + self.lastMouseX, self.lastMouseY = None, None + self.recenterMouse() + + def recenterMouse(self): + self.base.win.movePointer(0, + int(self.base.win.getProperties().getXSize() / 2), + int(self.base.win.getProperties().getYSize() / 2)) + + + def toggleRecenter(self): + print "Toggling re-center behavior" + self.manualRecenterMouse = not self.manualRecenterMouse + + def toggleMouse(self): + print "Toggling mouse visibility" + + self.hideMouse = not self.hideMouse + + wp = WindowProperties() + wp.setCursorHidden(self.hideMouse) + self.base.win.requestProperties(wp) + + def mouseTask(self, task): + mw = self.base.mouseWatcherNode + + hasMouse = mw.hasMouse() + if hasMouse: + # get the window manager's idea of the mouse position + x, y = mw.getMouseX(), mw.getMouseY() + + if self.lastMouseX is not None: + # get the delta + if self.manualRecenterMouse: + # when recentering, the position IS the delta + # since the center is reported as 0, 0 + dx, dy = x, y + else: + dx, dy = x - self.lastMouseX, y - self.lastMouseY + else: + # no data to compare with yet + dx, dy = 0, 0 + + self.lastMouseX, self.lastMouseY = x, y + + else: + x, y, dx, dy = 0, 0, 0, 0 + + if self.manualRecenterMouse: + # move mouse back to center + self.recenterMouse() + + # scale position and delta to pixels for user + w, h = self.win.getSize() + + self.mouseText.setText("Mode: {0}, Recenter: {1} | Mouse: {2}, {3} | hasMouse: {4}".format( + self.mouseMode, self.manualRecenterMouse, + int(x*w), int(y*h), + hasMouse)) + self.deltaText.setText("Delta: {0}, {1}".format( + int(dx*w), int(dy*h))) + + # rotate box by delta + self.rotateX += dx * 10 + self.rotateY += dy * 10 + + self.positionText.setText("Model rotation: {0}, {1}".format( + int(self.rotateX*1000)/1000., int(self.rotateY*1000)/1000.)) + + self.model.setH(self.rotateX) + self.model.setP(self.rotateY) + return Task.cont + +app = App() +app.run() From 0f5b1a819205f78d990374cfe360a04a1bb8e1ed Mon Sep 17 00:00:00 2001 From: Ed Swartz Date: Fri, 17 Apr 2015 15:50:11 -0500 Subject: [PATCH 03/10] Fix X11 M_relative case when missing XF86DGA --- panda/src/x11display/x11GraphicsWindow.cxx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index f1484522a1..c503bda1cc 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -747,6 +747,7 @@ set_properties_now(WindowProperties &properties) { XF86DGADirectVideo(_display, _screen, XF86DGADirectMouse); _properties.set_mouse_mode(WindowProperties::M_relative); + properties.clear_mouse_mode(); _dga_mouse_enabled = true; // Get the real mouse position, so we can add/subtract @@ -762,12 +763,7 @@ set_properties_now(WindowProperties &properties) { _dga_mouse_enabled = false; } } - else #endif - { - // can't change - properties.clear_mouse_mode(); - } break; case WindowProperties::M_confined: From 53171c93c853637af9a6d23a9ffa30e7701e62b5 Mon Sep 17 00:00:00 2001 From: Ed Swartz Date: Fri, 17 Apr 2015 15:55:46 -0500 Subject: [PATCH 04/10] Replace some debug() calls with info()/warning() calls. --- panda/src/windisplay/winGraphicsWindow.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index d4fcf6a9e2..a226dcde1b 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -380,18 +380,16 @@ set_properties_now(WindowProperties &properties) { RECT clip; if (!GetWindowRect(_hWnd, &clip)) { - if (windisplay_cat.is_debug()) { - windisplay_cat.debug() + windisplay_cat.warning() << "GetWindowRect() failed in set_properties_now. Cannot confine cursor.\n"; - } } else { - windisplay_cat.debug() + windisplay_cat.info() << "ClipCursor() to " << clip.left << "," << clip.top << " to " << clip.right << "," << clip.bottom << endl; GetClipCursor(&_mouse_unconfined_cliprect); if (!ClipCursor(&clip)) { - windisplay_cat.debug() + windisplay_cat.warning() << "ClipCursor() failed in set_properties_now. Ignoring.\n"; } else { _properties.set_mouse_mode(WindowProperties::M_confined); From 077d03a9f6a660473e3a17a5530848a70a03b696 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 25 Apr 2015 17:09:50 +0200 Subject: [PATCH 05/10] Center p3dCert on screen, and make it a modal dialog --- direct/src/plugin/p3dCert.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/direct/src/plugin/p3dCert.cxx b/direct/src/plugin/p3dCert.cxx index 528bde0d49..b920550092 100644 --- a/direct/src/plugin/p3dCert.cxx +++ b/direct/src/plugin/p3dCert.cxx @@ -157,6 +157,10 @@ AuthDialog(const string &cert_filename, const string &cert_dir) : _stack = NULL; _verify_result = -1; + // Center the window on the screen. + position((Fl::w() - w()) / 2, (Fl::h() - h()) / 2); + set_modal(); + read_cert_file(cert_filename); get_friendly_name(); verify_cert(); @@ -583,6 +587,10 @@ ViewCertDialog(AuthDialog *auth_dialog, X509 *cert) : _auth_dialog(auth_dialog), _cert(cert) { + // Center the window on the screen. + position((Fl::w() - w()) / 2, (Fl::h() - h()) / 2); + set_modal(); + layout(); } From f1ea25bfb1cc32549f7ad502bee0ed07a10453fb Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 25 Apr 2015 17:13:35 +0200 Subject: [PATCH 06/10] Unexpose BoundingVolume::around, add GraphicsOutput::get_fb_size --- panda/src/display/graphicsOutput.I | 48 ++++++++++++++++++++ panda/src/display/graphicsOutput.h | 3 ++ panda/src/mathutil/boundingVolume.h | 2 + panda/src/mathutil/geometricBoundingVolume.h | 2 + 4 files changed, 55 insertions(+) diff --git a/panda/src/display/graphicsOutput.I b/panda/src/display/graphicsOutput.I index 2b746ff09d..b24390146b 100644 --- a/panda/src/display/graphicsOutput.I +++ b/panda/src/display/graphicsOutput.I @@ -207,6 +207,20 @@ get_y_size() const { return _size.get_y(); } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsOutput::get_fb_size +// Access: Published +// Description: Returns the internal size of the window or buffer. +// This is almost always the same as get_size(), +// except when a pixel_zoom is in effect--see +// set_pixel_zoom(). +//////////////////////////////////////////////////////////////////// +INLINE LVecBase2i GraphicsOutput:: +get_fb_size() const { + return LVecBase2i(max(int(_size.get_x() * get_pixel_factor()), 1), + max(int(_size.get_y() * get_pixel_factor()), 1)); +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsOutput::get_fb_x_size // Access: Published @@ -233,6 +247,23 @@ get_fb_y_size() const { return max(int(_size.get_y() * get_pixel_factor()), 1); } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsOutput::get_sbs_left_size +// Access: Published +// Description: If side-by-side stereo is enabled, this returns the +// pixel size of the left eye, based on scaling +// get_size() by get_sbs_left_dimensions(). If +// side-by-side stereo is not enabled, this returns the +// same as get_size(). +//////////////////////////////////////////////////////////////////// +INLINE LVecBase2i GraphicsOutput:: +get_sbs_left_size() const { + PN_stdfloat left_w = _sbs_left_dimensions[1] - _sbs_left_dimensions[0]; + PN_stdfloat left_h = _sbs_left_dimensions[3] - _sbs_left_dimensions[2]; + return LVecBase2i(max(int(_size.get_x() * left_w), 1), + max(int(_size.get_y() * left_h), 1)); +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsOutput::get_sbs_left_x_size // Access: Published @@ -263,6 +294,23 @@ get_sbs_left_y_size() const { return max(int(_size.get_y() * left_h), 1); } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsOutput::get_sbs_right_size +// Access: Published +// Description: If side-by-side stereo is enabled, this returns the +// pixel size of the right eye, based on scaling +// get_size() by get_sbs_right_dimensions(). If +// side-by-side stereo is not enabled, this returns the +// same as get_size(). +//////////////////////////////////////////////////////////////////// +INLINE LVecBase2i GraphicsOutput:: +get_sbs_right_size() const { + PN_stdfloat right_w = _sbs_right_dimensions[1] - _sbs_right_dimensions[0]; + PN_stdfloat right_h = _sbs_right_dimensions[3] - _sbs_right_dimensions[2]; + return LVecBase2i(max(int(_size.get_x() * right_w), 1), + max(int(_size.get_y() * right_h), 1)); +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsOutput::get_sbs_right_x_size // Access: Published diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index cbcd787d90..7c01cff360 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -135,10 +135,13 @@ PUBLISHED: INLINE const LVecBase2i &get_size() const; INLINE int get_x_size() const; INLINE int get_y_size() const; + INLINE LVecBase2i get_fb_size() const; INLINE int get_fb_x_size() const; INLINE int get_fb_y_size() const; + INLINE LVecBase2i get_sbs_left_size() const; INLINE int get_sbs_left_x_size() const; INLINE int get_sbs_left_y_size() const; + INLINE LVecBase2i get_sbs_right_size() const; INLINE int get_sbs_right_x_size() const; INLINE int get_sbs_right_y_size() const; INLINE bool has_size() const; diff --git a/panda/src/mathutil/boundingVolume.h b/panda/src/mathutil/boundingVolume.h index ef7663ad2f..3af3e7fa2d 100644 --- a/panda/src/mathutil/boundingVolume.h +++ b/panda/src/mathutil/boundingVolume.h @@ -56,12 +56,14 @@ PUBLISHED: INLINE_MATHUTIL bool extend_by(const BoundingVolume *vol); +public: // It might be nice to make these template member functions so we // could have true STL-style first/last iterators, but that's // impossible for virtual functions. bool around(const BoundingVolume **first, const BoundingVolume **last); +PUBLISHED: // The contains() functions return the union of one or more of these // bits. enum IntersectionFlags { diff --git a/panda/src/mathutil/geometricBoundingVolume.h b/panda/src/mathutil/geometricBoundingVolume.h index 768db6063d..4bd53591e3 100644 --- a/panda/src/mathutil/geometricBoundingVolume.h +++ b/panda/src/mathutil/geometricBoundingVolume.h @@ -36,6 +36,7 @@ PUBLISHED: INLINE_MATHUTIL bool extend_by(const GeometricBoundingVolume *vol); INLINE_MATHUTIL bool extend_by(const LPoint3 &point); +public: // It might be nice to make these template member functions so we // could have true STL-style first/last iterators, but that's // impossible for virtual functions. @@ -43,6 +44,7 @@ PUBLISHED: const GeometricBoundingVolume **last); INLINE_MATHUTIL bool around(const LPoint3 *first, const LPoint3 *last); +PUBLISHED: INLINE_MATHUTIL int contains(const GeometricBoundingVolume *vol) const; INLINE_MATHUTIL int contains(const LPoint3 &point) const; INLINE_MATHUTIL int contains(const LPoint3 &a, const LPoint3 &b) const; From 66011a13526b89efc188469087672f5ffabce89c Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 25 Apr 2015 17:17:33 +0200 Subject: [PATCH 07/10] Expose _NET_WM_PID to window managers in X11 --- panda/src/x11display/x11GraphicsPipe.cxx | 1 + panda/src/x11display/x11GraphicsPipe.h | 1 + panda/src/x11display/x11GraphicsWindow.cxx | 57 ++++++++++++---------- panda/src/x11display/x11GraphicsWindow.h | 9 ---- 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index e6402ce255..83ba8de3d4 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -140,6 +140,7 @@ x11GraphicsPipe(const string &display) { // Get some X atom numbers. _wm_delete_window = XInternAtom(_display, "WM_DELETE_WINDOW", false); + _net_wm_pid = XInternAtom(_display, "_NET_WM_PID", false); _net_wm_window_type = XInternAtom(_display, "_NET_WM_WINDOW_TYPE", false); _net_wm_window_type_splash = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_SPLASH", false); _net_wm_window_type_fullscreen = XInternAtom(_display, "_NET_WM_WINDOW_TYPE_FULLSCREEN", false); diff --git a/panda/src/x11display/x11GraphicsPipe.h b/panda/src/x11display/x11GraphicsPipe.h index e9a54fa1ee..2cd07245b4 100644 --- a/panda/src/x11display/x11GraphicsPipe.h +++ b/panda/src/x11display/x11GraphicsPipe.h @@ -52,6 +52,7 @@ public: public: // Atom specifications. Atom _wm_delete_window; + Atom _net_wm_pid; Atom _net_wm_window_type; Atom _net_wm_window_type_splash; Atom _net_wm_window_type_fullscreen; diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index c503bda1cc..5195b8ac5d 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -105,15 +105,6 @@ x11GraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe, _awaiting_configure = false; _dga_mouse_enabled = false; _wm_delete_window = x11_pipe->_wm_delete_window; - _net_wm_window_type = x11_pipe->_net_wm_window_type; - _net_wm_window_type_splash = x11_pipe->_net_wm_window_type_splash; - _net_wm_window_type_fullscreen = x11_pipe->_net_wm_window_type_fullscreen; - _net_wm_state = x11_pipe->_net_wm_state; - _net_wm_state_fullscreen = x11_pipe->_net_wm_state_fullscreen; - _net_wm_state_above = x11_pipe->_net_wm_state_above; - _net_wm_state_below = x11_pipe->_net_wm_state_below; - _net_wm_state_add = x11_pipe->_net_wm_state_add; - _net_wm_state_remove = x11_pipe->_net_wm_state_remove; GraphicsWindowInputDevice device = GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse"); @@ -175,7 +166,6 @@ move_pointer(int device, int x, int y) { } } - //////////////////////////////////////////////////////////////////// // Function: x11GraphicsWindow::begin_frame // Access: Public, Virtual @@ -1037,6 +1027,9 @@ open_window() { //////////////////////////////////////////////////////////////////// void x11GraphicsWindow:: set_wm_properties(const WindowProperties &properties, bool already_mapped) { + x11GraphicsPipe *x11_pipe; + DCAST_INTO_V(x11_pipe, _pipe); + // Name the window if there is a name XTextProperty window_name; XTextProperty *window_name_p = (XTextProperty *)NULL; @@ -1117,15 +1110,15 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) { if (properties.get_fullscreen()) { // For a "fullscreen" request, we pass this through, hoping the // window manager will support EWMH. - type_data[next_type_data++] = _net_wm_window_type_fullscreen; + type_data[next_type_data++] = x11_pipe->_net_wm_window_type_fullscreen; // We also request it as a state. - state_data[next_state_data++] = _net_wm_state_fullscreen; + state_data[next_state_data++] = x11_pipe->_net_wm_state_fullscreen; // Don't ask me why this has to be 1/0 and not _net_wm_state_add. // It doesn't seem to work otherwise. - set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, 1); + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 1); } else { - set_data[next_set_data++] = SetAction(_net_wm_state_fullscreen, 0); + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_fullscreen, 0); } // If we asked for a window without a border, there's no excellent @@ -1152,26 +1145,32 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) { } if (properties.get_undecorated() && !properties.get_fullscreen()) { - type_data[next_type_data++] = _net_wm_window_type_splash; + type_data[next_type_data++] = x11_pipe->_net_wm_window_type_splash; } if (properties.has_z_order()) { switch (properties.get_z_order()) { case WindowProperties::Z_bottom: - state_data[next_state_data++] = _net_wm_state_below; - set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_add); - set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove); + state_data[next_state_data++] = x11_pipe->_net_wm_state_below; + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below, + x11_pipe->_net_wm_state_add); + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above, + x11_pipe->_net_wm_state_remove); break; case WindowProperties::Z_normal: - set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove); - set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_remove); + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below, + x11_pipe->_net_wm_state_remove); + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above, + x11_pipe->_net_wm_state_remove); break; case WindowProperties::Z_top: - state_data[next_state_data++] = _net_wm_state_above; - set_data[next_set_data++] = SetAction(_net_wm_state_below, _net_wm_state_remove); - set_data[next_set_data++] = SetAction(_net_wm_state_above, _net_wm_state_add); + state_data[next_state_data++] = x11_pipe->_net_wm_state_above; + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_below, + x11_pipe->_net_wm_state_remove); + set_data[next_set_data++] = SetAction(x11_pipe->_net_wm_state_above, + x11_pipe->_net_wm_state_add); break; } } @@ -1180,12 +1179,18 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) { nassertv(next_state_data < max_state_data); nassertv(next_set_data < max_set_data); - XChangeProperty(_display, _xwindow, _net_wm_window_type, + // Add the process ID as a convenience for other applications. + Cardinal pid = getpid(); + XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_pid, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *)&pid, 1); + + XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_window_type, XA_ATOM, 32, PropModeReplace, (unsigned char *)type_data, next_type_data); // Request the state properties all at once. - XChangeProperty(_display, _xwindow, _net_wm_state, + XChangeProperty(_display, _xwindow, x11_pipe->_net_wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)state_data, next_state_data); @@ -1204,7 +1209,7 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) { event.send_event = True; event.display = _display; event.window = _xwindow; - event.message_type = _net_wm_state; + event.message_type = x11_pipe->_net_wm_state; event.format = 32; event.data.l[0] = set_data[i]._action; event.data.l[1] = set_data[i]._state; diff --git a/panda/src/x11display/x11GraphicsWindow.h b/panda/src/x11display/x11GraphicsWindow.h index e032cd7109..9fc7210f60 100644 --- a/panda/src/x11display/x11GraphicsWindow.h +++ b/panda/src/x11display/x11GraphicsWindow.h @@ -100,15 +100,6 @@ protected: bool _awaiting_configure; bool _dga_mouse_enabled; Atom _wm_delete_window; - Atom _net_wm_window_type; - Atom _net_wm_window_type_splash; - Atom _net_wm_window_type_fullscreen; - Atom _net_wm_state; - Atom _net_wm_state_fullscreen; - Atom _net_wm_state_above; - Atom _net_wm_state_below; - Atom _net_wm_state_add; - Atom _net_wm_state_remove; struct MouseDeviceInfo { int _fd; From 92d40c314427acd34f17cf3c7ef373b35a7a85a9 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 25 Apr 2015 18:48:48 +0200 Subject: [PATCH 08/10] Default vertex column alignment should be 4 --- panda/src/gobj/config_gobj.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index ce1cdce7c6..a1d3c43d03 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -279,7 +279,7 @@ ConfigVariableBool vertices_float64 "slower.")); ConfigVariableInt vertex_column_alignment -("vertex-column-alignment", 1, +("vertex-column-alignment", 4, PRC_DESC("This specifies the default byte alignment for each column of " "data within a GeomVertexData when it is assembled using the default " "interfaces. Normally, you should not change this config variable " From 589a1b52ac9c13ff2c2060fa6f46e23e923fb320 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 26 Apr 2015 15:07:09 +0200 Subject: [PATCH 09/10] Revert unintentional debug message check-in --- .../glstuff/glGraphicsStateGuardian_src.cxx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 5471dfeb87..d24448189f 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -6928,8 +6928,8 @@ query_gl_version() { string_to_int(components[1], _gl_version_minor); } - if (GLCAT.is_info()) { - GLCAT.info() + if (GLCAT.is_debug()) { + GLCAT.debug() << "GL_VERSION = " << version << ", decoded to " << _gl_version_major << "." << _gl_version_minor << "\n"; @@ -6949,19 +6949,21 @@ query_gl_version() { _gl_shadlang_ver_major = 1; _gl_shadlang_ver_minor = 1; const char *verstr = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); - if (verstr == NULL || sscanf(verstr, "%d.%d", &_gl_shadlang_ver_major, &_gl_shadlang_ver_minor) != 2) { - GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n"; + if (verstr == NULL || + sscanf(verstr, "%d.%d", &_gl_shadlang_ver_major, + &_gl_shadlang_ver_minor) != 2) { + GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n"; } - cerr << verstr << " -> " << _gl_shadlang_ver_major << " . " << _gl_shadlang_ver_minor << "\n"; } #elif defined(OPENGLES_2) _gl_shadlang_ver_major = 1; _gl_shadlang_ver_minor = 0; const char *verstr = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); - if (verstr == NULL || sscanf(verstr, "OpenGL ES GLSL %d.%d", &_gl_shadlang_ver_major, &_gl_shadlang_ver_minor) != 2) { - GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n"; + if (verstr == NULL || + sscanf(verstr, "OpenGL ES GLSL %d.%d", &_gl_shadlang_ver_major, + &_gl_shadlang_ver_minor) != 2) { + GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n"; } - cerr << verstr << " -> " << _gl_shadlang_ver_major << " . " << _gl_shadlang_ver_minor << "\n"; #endif } } From a745184f25f22160de049e89718bec2d810f2a0e Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 26 Apr 2015 15:27:39 +0200 Subject: [PATCH 10/10] Fix X11 compile and interrogate issues --- panda/src/display/get_x11.h | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/panda/src/display/get_x11.h b/panda/src/display/get_x11.h index 88f3a21ff2..7ea150a963 100644 --- a/panda/src/display/get_x11.h +++ b/panda/src/display/get_x11.h @@ -17,7 +17,7 @@ #include "pandabase.h" -#ifdef HAVE_X11 +#ifdef HAVE_X11 // This header file is designed to help work around some of the // namespace spamming that X11 causes, by renaming the symbols that // X11 declares that are known to conflict with other library names @@ -30,14 +30,21 @@ #ifdef CPPPARSER // A simple hack so interrogate can get all of the necessary // typenames. -typedef int X11_Display; -typedef int X11_Window; -typedef int X11_Cursor; -typedef int XErrorEvent; -typedef int XVisualInfo; -typedef int Atom; -typedef int XIM; -typedef int XIC; +typedef struct _XDisplay X11_Display; +typedef unsigned int XID; +typedef unsigned int Atom; +typedef unsigned int Cardinal; +typedef XID Colormap; +typedef XID X11_Window; +typedef XID X11_Cursor; +typedef struct _XIM *XIM; +typedef struct _XIC *XIC; +struct XErrorEvent; +struct XVisualInfo; +#define Bool int +#define Status int +#define True 1 +#define False 0 #else #include "pre_x11_include.h" @@ -45,6 +52,7 @@ typedef int XIC; #include #include #include +#include #ifdef HAVE_XRANDR #include