Browse Source

Support pointerlock when running in WebGL mode

rdb 10 years ago
parent
commit
8ce1518799

+ 85 - 1
panda/src/webgldisplay/webGLGraphicsWindow.cxx

@@ -63,6 +63,12 @@ WebGLGraphicsWindow::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool WebGLGraphicsWindow::
 bool WebGLGraphicsWindow::
 move_pointer(int device, int x, int y) {
 move_pointer(int device, int x, int y) {
+  if (device == 0 && _properties.get_mouse_mode() == WindowProperties::M_relative) {
+    // The pointer position is meaningless in relative mode, so we
+    // silently pretend that this worked.
+    _input_devices[0].set_pointer_in_window(x, y);
+    return true;
+  }
   return false;
   return false;
 }
 }
 
 
@@ -207,6 +213,43 @@ set_properties_now(WindowProperties &properties) {
       }
       }
     }
     }
   }
   }
+
+  if (properties.has_mouse_mode() &&
+      properties.get_mouse_mode() != _properties.get_mouse_mode()) {
+
+    if (properties.get_mouse_mode() == WindowProperties::M_relative) {
+      EMSCRIPTEN_RESULT result = emscripten_request_pointerlock(NULL, true);
+
+      if (result == EMSCRIPTEN_RESULT_SUCCESS) {
+        // Great, we're in pointerlock mode.
+        _properties.set_mouse_mode(WindowProperties::M_absolute);
+        _properties.set_cursor_hidden(true);
+        properties.clear_mouse_mode();
+
+      } else if (result == EMSCRIPTEN_RESULT_DEFERRED) {
+        // We can't switch to pointerlock just yet - this action is deferred
+        // until we're in an event handler.  We can't know for sure yet that
+        // pointerlock will be supported, but we shouldn't report failure.
+        properties.clear_mouse_mode();
+        if (properties.has_cursor_hidden() && properties.get_cursor_hidden()) {
+          properties.clear_cursor_hidden();
+        }
+      }
+    } else {
+      if (emscripten_exit_pointerlock() == EMSCRIPTEN_RESULT_SUCCESS) {
+        _properties.set_mouse_mode(WindowProperties::M_absolute);
+        properties.clear_mouse_mode();
+        properties.clear_cursor_hidden();
+      }
+    }
+  }
+
+  if (properties.has_cursor_hidden() &&
+      properties.get_cursor_hidden() == (_properties.get_mouse_mode() == WindowProperties::M_relative)) {
+    // A hidden cursor comes for free with pointerlock.  Without pointerlock,
+    // though, we can't hdide the cursor.
+    properties.clear_cursor_hidden();
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -225,6 +268,7 @@ close_window() {
   // Clear the assigned callbacks.
   // Clear the assigned callbacks.
   const char *target = NULL;
   const char *target = NULL;
   emscripten_set_fullscreenchange_callback(target, NULL, false, NULL);
   emscripten_set_fullscreenchange_callback(target, NULL, false, NULL);
+  emscripten_set_pointerlockchange_callback(target, NULL, false, NULL);
 
 
   emscripten_set_keypress_callback(target, NULL, false, NULL);
   emscripten_set_keypress_callback(target, NULL, false, NULL);
   emscripten_set_keydown_callback(target, NULL, false, NULL);
   emscripten_set_keydown_callback(target, NULL, false, NULL);
@@ -308,6 +352,7 @@ open_window() {
 
 
   // Set callbacks.
   // Set callbacks.
   emscripten_set_fullscreenchange_callback(target, (void *)this, false, &on_fullscreen_event);
   emscripten_set_fullscreenchange_callback(target, (void *)this, false, &on_fullscreen_event);
+  emscripten_set_pointerlockchange_callback(target, (void *)this, false, &on_pointerlock_event);
 
 
   void *user_data = (void *)&_input_devices[0];
   void *user_data = (void *)&_input_devices[0];
 
 
@@ -345,6 +390,34 @@ on_fullscreen_event(int type, const EmscriptenFullscreenChangeEvent *event, void
   return false;
   return false;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: WebGLGraphicsWindow::on_pointerlock_event
+//       Access: Private, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+EM_BOOL WebGLGraphicsWindow::
+on_pointerlock_event(int type, const EmscriptenPointerlockChangeEvent *event, void *user_data) {
+  WebGLGraphicsWindow *window = (WebGLGraphicsWindow *)user_data;
+  nassertr(window != NULL, false);
+
+  if (type == EMSCRIPTEN_EVENT_POINTERLOCKCHANGE) {
+    WindowProperties props;
+    if (event->isActive) {
+      cout << "pointerlock engaged\n";
+      props.set_mouse_mode(WindowProperties::M_relative);
+      props.set_cursor_hidden(true);
+    } else {
+      cout << "pointerlock disabled\n";
+      props.set_mouse_mode(WindowProperties::M_absolute);
+      props.set_cursor_hidden(false);
+    }
+    window->system_changed_properties(props);
+    return true;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: WebGLGraphicsWindow::on_keyboard_event
 //     Function: WebGLGraphicsWindow::on_keyboard_event
 //       Access: Private, Static
 //       Access: Private, Static
@@ -479,7 +552,18 @@ on_mouse_event(int type, const EmscriptenMouseEvent *event, void *user_data) {
     return true;
     return true;
 
 
   case EMSCRIPTEN_EVENT_MOUSEMOVE:
   case EMSCRIPTEN_EVENT_MOUSEMOVE:
-    device->set_pointer_in_window(event->canvasX, event->canvasY, time);
+    {
+      EmscriptenPointerlockChangeEvent ev;
+      emscripten_get_pointerlock_status(&ev);
+
+      if (ev.isActive) {
+        MouseData md = device->get_pointer();
+        device->set_pointer_in_window(md.get_x() + event->movementX,
+                                      md.get_y() + event->movementY, time);
+      } else {
+        device->set_pointer_in_window(event->canvasX, event->canvasY, time);
+      }
+    }
     return true;
     return true;
 
 
   case EMSCRIPTEN_EVENT_MOUSEENTER:
   case EMSCRIPTEN_EVENT_MOUSEENTER:

+ 1 - 0
panda/src/webgldisplay/webGLGraphicsWindow.h

@@ -52,6 +52,7 @@ protected:
 
 
 private:
 private:
   static EM_BOOL on_fullscreen_event(int type, const EmscriptenFullscreenChangeEvent *event, void *user_data);
   static EM_BOOL on_fullscreen_event(int type, const EmscriptenFullscreenChangeEvent *event, void *user_data);
+  static EM_BOOL on_pointerlock_event(int type, const EmscriptenPointerlockChangeEvent *event, void *user_data);
   static EM_BOOL on_keyboard_event(int type, const EmscriptenKeyboardEvent *event,
   static EM_BOOL on_keyboard_event(int type, const EmscriptenKeyboardEvent *event,
                                    void *user_data);
                                    void *user_data);
   static EM_BOOL on_mouse_event(int type, const EmscriptenMouseEvent *event,
   static EM_BOOL on_mouse_event(int type, const EmscriptenMouseEvent *event,