Răsfoiți Sursa

Robustness, more features for WebGL renderer:
- handle context loss gracefully
- support mouse wheel events
- fix swapped comma and period keys
- map focus/blur status to WindowProperties.foreground
- map visibility status to WindowProperties.minimized
- don't register out-of-canvas mousedown events

rdb 10 ani în urmă
părinte
comite
8e473d5222

+ 4 - 4
dtool/src/prc/notify.cxx

@@ -454,10 +454,10 @@ assert_failure(const char *expression, int line,
     int *ptr = (int *)NULL;
     *ptr = 1;
 
-#elif defined(__EMSCRIPTEN__) && defined(_DEBUG)
-    // This should drop us into the browser's JavaScript debugger, but
-    // adding this disables ASM.js validation.
-    emscripten_debugger();
+#elif defined(__EMSCRIPTEN__)
+    // This should drop us into the browser's JavaScript debugger.
+    //emscripten_debugger();
+    EM_ASM(debugger;);
 
 #else  // WIN32
     abort();

+ 1 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -468,6 +468,7 @@ debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei l
 void CLP(GraphicsStateGuardian)::
 reset() {
   _last_error_check = -1.0;
+  _white_texture = 0;
 
   free_pointers();
   GraphicsStateGuardian::reset();

+ 19 - 3
panda/src/webgldisplay/webGLGraphicsStateGuardian.cxx

@@ -115,18 +115,34 @@ on_context_event(int type, const void *, void *user_data) {
   nassertr(gsg != NULL, false);
 
   if (type == EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST) {
-    webgldisplay_cat.warning() << "WebGL context lost!\n";
-    gsg->release_all();
+    webgldisplay_cat.info() << "WebGL context lost!\n";
+    gsg->context_lost();
     return true;
 
   } else if (type == EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED) {
-    webgldisplay_cat.warning() << "WebGL context restored!\n";
+    webgldisplay_cat.info() << "WebGL context restored!\n";
+    gsg->reset();
     return true;
   }
 
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WebGLGraphicsStateGuardian::context_lost
+//       Access: Protected
+//  Description: Called to indicate that we lost the WebGL context,
+//               and any resources we prepared previously are gone.
+////////////////////////////////////////////////////////////////////
+void WebGLGraphicsStateGuardian::
+context_lost() {
+  release_all();
+
+  // Assign a new PreparedGraphicsObjects to prevent the GSG from
+  // to trying to neatly clean up the old resources.
+  _prepared_objects = new PreparedGraphicsObjects;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WebGLGraphicsStateGuardian::get_extra_extensions
 //       Access: Protected, Virtual

+ 2 - 0
panda/src/webgldisplay/webGLGraphicsStateGuardian.h

@@ -43,6 +43,8 @@ private:
   bool _have_context;
 
 protected:
+  void context_lost();
+
   virtual void get_extra_extensions();
   virtual bool has_extension(const string &extension) const;
   virtual void *do_get_extension_func(const char *name);

+ 105 - 6
panda/src/webgldisplay/webGLGraphicsWindow.cxx

@@ -17,6 +17,7 @@
 #include "config_webgldisplay.h"
 #include "mouseButton.h"
 #include "keyboardButton.h"
+#include "throw_event.h"
 
 #include <emscripten.h>
 
@@ -93,6 +94,11 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   WebGLGraphicsStateGuardian *webgl_gsg;
   DCAST_INTO_R(webgl_gsg, _gsg, false);
 
+  if (emscripten_is_webgl_context_lost(0)) {
+    // The context was lost, and any GL calls we make will fail.
+    return false;
+  }
+
   if (emscripten_webgl_make_context_current(webgl_gsg->_context) != EMSCRIPTEN_RESULT_SUCCESS) {
     webgldisplay_cat.error()
       << "Failed to make context current.\n";
@@ -188,6 +194,8 @@ set_properties_now(WindowProperties &properties) {
     emscripten_set_canvas_size(properties.get_x_size(), properties.get_y_size());
     _properties.set_size(properties.get_size());
     properties.clear_size();
+    set_size_and_recalc(_properties.get_x_size(), _properties.get_y_size());
+    throw_event(get_window_event(), this);
   }
 
   if (properties.has_fullscreen() &&
@@ -269,6 +277,10 @@ close_window() {
   const char *target = NULL;
   emscripten_set_fullscreenchange_callback(target, NULL, false, NULL);
   emscripten_set_pointerlockchange_callback(target, NULL, false, NULL);
+  emscripten_set_visibilitychange_callback(NULL, false, NULL);
+
+  emscripten_set_focus_callback(target, NULL, false, NULL);
+  emscripten_set_blur_callback(target, NULL, false, NULL);
 
   emscripten_set_keypress_callback(target, NULL, false, NULL);
   emscripten_set_keydown_callback(target, NULL, false, NULL);
@@ -281,6 +293,8 @@ close_window() {
   emscripten_set_mouseenter_callback(target, NULL, false, NULL);
   emscripten_set_mouseleave_callback(target, NULL, false, NULL);
 
+  emscripten_set_wheel_callback(target, NULL, false, NULL);
+
   GraphicsWindow::close_window();
 }
 
@@ -324,6 +338,8 @@ open_window() {
     _properties.set_fullscreen(fullscreen > 0);
   }
 
+  _properties.set_undecorated(true);
+
   if (emscripten_webgl_make_context_current(webgl_gsg->_context) != EMSCRIPTEN_RESULT_SUCCESS) {
     webgldisplay_cat.error()
       << "Failed to make context current.\n";
@@ -353,6 +369,10 @@ open_window() {
   // Set callbacks.
   emscripten_set_fullscreenchange_callback(target, (void *)this, false, &on_fullscreen_event);
   emscripten_set_pointerlockchange_callback(target, (void *)this, false, &on_pointerlock_event);
+  emscripten_set_visibilitychange_callback((void *)this, false, &on_visibility_event);
+
+  emscripten_set_focus_callback(target, (void *)this, false, &on_focus_event);
+  emscripten_set_blur_callback(target, (void *)this, false, &on_focus_event);
 
   void *user_data = (void *)&_input_devices[0];
 
@@ -367,6 +387,8 @@ open_window() {
   emscripten_set_mouseenter_callback(target, user_data, false, &on_mouse_event);
   emscripten_set_mouseleave_callback(target, user_data, false, &on_mouse_event);
 
+  emscripten_set_wheel_callback(target, user_data, false, &on_wheel_event);
+
   return true;
 }
 
@@ -418,6 +440,51 @@ on_pointerlock_event(int type, const EmscriptenPointerlockChangeEvent *event, vo
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WebGLGraphicsWindow::on_visibility_event
+//       Access: Private, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+EM_BOOL WebGLGraphicsWindow::
+on_visibility_event(int type, const EmscriptenVisibilityChangeEvent *event, void *user_data) {
+  WebGLGraphicsWindow *window = (WebGLGraphicsWindow *)user_data;
+  nassertr(window != NULL, false);
+
+  if (type == EMSCRIPTEN_EVENT_VISIBILITYCHANGE) {
+    WindowProperties props;
+    props.set_minimized(event->hidden != 0);
+    window->system_changed_properties(props);
+    return true;
+  }
+
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WebGLGraphicsWindow::on_focus_event
+//       Access: Private, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+EM_BOOL WebGLGraphicsWindow::
+on_focus_event(int type, const EmscriptenFocusEvent *event, void *user_data) {
+  WebGLGraphicsWindow *window = (WebGLGraphicsWindow *)user_data;
+  nassertr(window != NULL, false);
+
+  if (type == EMSCRIPTEN_EVENT_FOCUS) {
+    WindowProperties props;
+    props.set_foreground(true);
+    window->system_changed_properties(props);
+    return true;
+  } else if (type == EMSCRIPTEN_EVENT_BLUR) {
+    WindowProperties props;
+    props.set_foreground(false);
+    window->system_changed_properties(props);
+    return true;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WebGLGraphicsWindow::on_keyboard_event
 //       Access: Private, Static
@@ -475,7 +542,7 @@ on_keyboard_event(int type, const EmscriptenKeyboardEvent *event, void *user_dat
       break;
 
     case 188:
-      handle = KeyboardButton::ascii_key('.');
+      handle = KeyboardButton::ascii_key(',');
       break;
 
     case 189:
@@ -483,7 +550,7 @@ on_keyboard_event(int type, const EmscriptenKeyboardEvent *event, void *user_dat
       break;
 
     case 190:
-      handle = KeyboardButton::ascii_key(',');
+      handle = KeyboardButton::ascii_key('.');
       break;
 
     case 191:
@@ -541,11 +608,15 @@ on_mouse_event(int type, const EmscriptenMouseEvent *event, void *user_data) {
   switch (type) {
   case EMSCRIPTEN_EVENT_MOUSEDOWN:
     // Don't register out-of-bounds mouse downs.
-    if (event->canvasX < 0 || event->canvasY < 0) {
-      return false;
+    if (event->canvasX >= 0 && event->canvasY >= 0) {
+      int w, h, f;
+      emscripten_get_canvas_size(&w, &h, &f);
+      if (event->canvasX < w && event->canvasY < h) {
+        device->button_down(MouseButton::button(event->button), time);
+        return true;
+      }
     }
-    device->button_down(MouseButton::button(event->button), time);
-    return true;
+    return false;
 
   case EMSCRIPTEN_EVENT_MOUSEUP:
     device->button_up(MouseButton::button(event->button), time);
@@ -579,3 +650,31 @@ on_mouse_event(int type, const EmscriptenMouseEvent *event, void *user_data) {
 
   return false;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: WebGLGraphicsWindow::on_wheel_event
+//       Access: Private, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+EM_BOOL WebGLGraphicsWindow::
+on_wheel_event(int type, const EmscriptenWheelEvent *event, void *user_data) {
+  GraphicsWindowInputDevice *device;
+  device = (GraphicsWindowInputDevice *)user_data;
+  nassertr(device != NULL, false);
+
+  double time = event->mouse.timestamp * 0.001;
+
+  if (type == EMSCRIPTEN_EVENT_WHEEL) {
+    if (event->deltaY < 0) {
+      device->button_down(MouseButton::wheel_up(), time);
+      device->button_up(MouseButton::wheel_up(), time);
+    }
+    if (event->deltaY > 0) {
+      device->button_down(MouseButton::wheel_down(), time);
+      device->button_up(MouseButton::wheel_down(), time);
+    }
+    return true;
+  }
+
+  return false;
+}

+ 5 - 4
panda/src/webgldisplay/webGLGraphicsWindow.h

@@ -53,10 +53,11 @@ protected:
 private:
   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,
-                                   void *user_data);
-  static EM_BOOL on_mouse_event(int type, const EmscriptenMouseEvent *event,
-                                void *user_data);
+  static EM_BOOL on_visibility_event(int type, const EmscriptenVisibilityChangeEvent *event, void *user_data);
+  static EM_BOOL on_focus_event(int type, const EmscriptenFocusEvent *event, void *user_data);
+  static EM_BOOL on_keyboard_event(int type, const EmscriptenKeyboardEvent *event, void *user_data);
+  static EM_BOOL on_mouse_event(int type, const EmscriptenMouseEvent *event, void *user_data);
+  static EM_BOOL on_wheel_event(int type, const EmscriptenWheelEvent *event, void *user_data);
 
   string _canvas_id;