浏览代码

Merge branch 'release/1.10.x'

rdb 6 年之前
父节点
当前提交
cbb3c182a5

+ 1 - 1
README.md

@@ -22,7 +22,7 @@ Installing Panda3D
 ==================
 
 The latest Panda3D SDK can be downloaded from
-[this page](https://www.panda3d.org/download/sdk-1-10-0/).
+[this page](https://www.panda3d.org/download/sdk-1-10-1/).
 If you are familiar with installing Python packages, you can use
 the following comand:
 

+ 6 - 4
direct/src/gui/DirectScrolledFrame.py

@@ -100,8 +100,10 @@ class DirectScrolledFrame(DirectFrame):
                 simpleChildGui = self.guiDict.get(parts[-1])
                 if simpleChildGui:
                     simpleChildGui.destroy()
-        self.verticalScroll.destroy()
-        self.horizontalScroll.destroy()
-        del self.verticalScroll
-        del self.horizontalScroll
+        if self.verticalScroll:
+            self.verticalScroll.destroy()
+        if self.horizontalScroll:
+            self.horizontalScroll.destroy()
+        self.verticalScroll = None
+        self.horizontalScroll = None
         DirectFrame.destroy(self)

+ 15 - 16
direct/src/tkpanels/ParticlePanel.py

@@ -96,22 +96,21 @@ class ParticlePanel(AppShell):
 
         ## MENUBAR ENTRIES ##
         # FILE MENU
-        # Get a handle on the file menu so commands can be inserted
-        # before quit item
-        fileMenu = self.menuBar.component('File-menu')
-        # MRM: Need to add load and save effects methods
-        fileMenu.insert_command(
-            fileMenu.index('Quit'),
-            label = 'Load Params',
-            command = self.loadParticleEffectFromFile)
-        fileMenu.insert_command(
-            fileMenu.index('Quit'),
-            label = 'Save Params',
-            command = self.saveParticleEffectToFile)
-        fileMenu.insert_command(
-            fileMenu.index('Quit'),
-            label = 'Print Params',
-            command = lambda s = self: s.particles.printParams())
+        # Get a handle on the file menu, and delete the Quit item that AppShell
+        # created so we can add it back after adding the other items.
+        self.menuBar.deletemenuitems('File', 0, 0)
+        self.menuBar.addmenuitem('File', 'command',
+                                 label='Load Params',
+                                 command=self.loadParticleEffectFromFile)
+        self.menuBar.addmenuitem('File', 'command',
+                                 label='Save Params',
+                                 command=self.saveParticleEffectToFile)
+        self.menuBar.addmenuitem('File', 'command',
+                                 label='Print Params',
+                                 command=lambda s=self:s.particles.printParams())
+        self.menuBar.addmenuitem('File', 'command', 'Quit this application',
+                                 label='Quit',
+                                 command=self.quit)
 
         # PARTICLE MANAGER MENU
         self.menuBar.addmenu('ParticleMgr', 'ParticleMgr Operations')

+ 16 - 3
dtool/src/interrogate/functionRemap.cxx

@@ -397,17 +397,25 @@ get_call_str(const string &container, const vector_string &pexprs) const {
     }
 
     // It's not possible to assign arrays in C++, we have to copy them.
-    CPPArrayType *array_type = _parameters[_first_true_parameter]._remap->get_orig_type()->as_array_type();
+    bool paren_close = false;
+    CPPType *param_type = _parameters[_first_true_parameter]._remap->get_orig_type();
+    CPPArrayType *array_type = param_type->as_array_type();
     if (array_type != nullptr) {
       call << "std::copy(" << expr << ", " << expr << " + " << *array_type->_bounds << ", ";
-    } else {
+      paren_close = true;
+    }
+    else if (TypeManager::is_pointer_to_PyObject(param_type)) {
+      call << "Dtool_Assign_PyObject(" << expr << ", ";
+      paren_close = true;
+    }
+    else {
       call << expr << " = ";
     }
 
     _parameters[_first_true_parameter]._remap->pass_parameter(call,
                     get_parameter_expr(_first_true_parameter, pexprs));
 
-    if (array_type != nullptr) {
+    if (paren_close) {
       call << ')';
     }
 
@@ -772,6 +780,11 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     _return_value_destructor = builder.get_destructor_for(return_meat_type);
   }
 
+  if (_type == T_getter && TypeManager::is_pointer_to_PyObject(return_type)) {
+    _manage_reference_count = true;
+    _return_value_needs_management = true;
+  }
+
   // Check for a special meaning by name and signature.
   size_t first_param = 0;
   if (_has_this) {

+ 5 - 2
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -1690,7 +1690,6 @@ write_module_class(ostream &out, Object *obj) {
             SlottedFunctionDef def;
             def._answer_location = true_key;
             def._wrapper_type = slotted_def._wrapper_type;
-            def._min_version = 0x03000000;
             def._wrapper_name = func->_name + "_" + true_key;
             slots[true_key] = def;
           }
@@ -5993,7 +5992,11 @@ write_function_instance(ostream &out, FunctionRemap *remap,
       indent(out, indent_level) << "}\n";
     }
 
-    return_expr = manage_return_value(out, indent_level, remap, "return_value");
+    if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) {
+      indent(out, indent_level) << "Py_XINCREF(return_value);\n";
+    } else {
+      return_expr = manage_return_value(out, indent_level, remap, "return_value");
+    }
     return_expr = remap->_return_type->temporary_to_return(return_expr);
   }
 

+ 13 - 0
dtool/src/interrogatedb/py_panda.I

@@ -90,6 +90,19 @@ INLINE PyObject *DtoolInstance_RichComparePointers(PyObject *v1, PyObject *v2, i
   Py_RETURN_RICHCOMPARE(cmpval, 0, op);
 }
 
+/**
+ * Utility function for assigning a PyObject pointer while managing refcounts.
+ */
+ALWAYS_INLINE void
+Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value) {
+  PyObject *prev_value = ptr;
+  if (prev_value != value) {
+    Py_XINCREF(value);
+    ptr = value;
+    Py_XDECREF(prev_value);
+  }
+}
+
 /**
  * Converts the enum value to a C long.
  */

+ 2 - 0
dtool/src/interrogatedb/py_panda.h

@@ -238,6 +238,8 @@ EXPCL_PYPANDA PyObject *_Dtool_Return(PyObject *value);
 #define Dtool_Return(value) _Dtool_Return(value)
 #endif
 
+ALWAYS_INLINE void Dtool_Assign_PyObject(PyObject *&ptr, PyObject *value);
+
 /**
  * Wrapper around Python 3.4's enum library, which does not have a C API.
  */

+ 1 - 1
makepanda/makepanda.py

@@ -157,7 +157,7 @@ def usage(problem):
     print("  --everything      (enable every third-party lib)")
     print("  --directx-sdk=X   (specify version of DirectX SDK to use: jun2010, aug2009, mar2009, aug2006)")
     print("  --windows-sdk=X   (specify Windows SDK version, eg. 7.0, 7.1 or 10.  Default is 7.1)")
-    print("  --msvc-version=X  (specify Visual C++ version, eg. 10, 11, 12, 14.  Default is 14)")
+    print("  --msvc-version=X  (specify Visual C++ version, eg. 10, 11, 12, 14, 14.1, 14.2.  Default is 14)")
     print("  --use-icl         (experimental setting to use an intel compiler instead of MSVC on Windows)")
     print("")
     print("The simplest way to compile panda is to just type:")

+ 1 - 0
makepanda/makepandacore.py

@@ -78,6 +78,7 @@ MSVCVERSIONINFO = {
     (12,0): {"vsversion":(12,0), "vsname":"Visual Studio 2013"},
     (14,0): {"vsversion":(14,0), "vsname":"Visual Studio 2015"},
     (14,1): {"vsversion":(15,0), "vsname":"Visual Studio 2017"},
+    (14,2): {"vsversion":(16,0), "vsname":"Visual Studio 2019"},
 }
 
 ########################################################################

+ 1 - 1
panda/src/bullet/bulletRigidBodyNode.cxx

@@ -120,7 +120,7 @@ do_set_mass(PN_stdfloat mass) {
   btScalar bt_mass = mass;
   btVector3 bt_inertia(0.0, 0.0, 0.0);
 
-  if (bt_mass > 0.0) {
+  if (bt_mass > 0.0 && !_shapes.empty()) {
     _rigid->getCollisionShape()->calculateLocalInertia(bt_mass, bt_inertia);
   }
 

+ 1 - 1
panda/src/bullet/bulletWorld.h

@@ -43,7 +43,7 @@ class BulletPersistentManifold;
 class BulletShape;
 class BulletSoftBodyWorldInfo;
 
-extern PT(CallbackObject) bullet_contact_added_callback;
+extern EXPCL_PANDABULLET PT(CallbackObject) bullet_contact_added_callback;
 
 /**
  *

+ 4 - 1
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -711,8 +711,11 @@ close_window() {
   }
 
   if (_window != nil) {
-    [_window setReleasedWhenClosed: YES];
     [_window close];
+    
+    // Process events once more so any pending NSEvents are cleared. Not doing
+    // this causes the window to stick around after calling [_window close].
+    process_events();
     _window = nil;
   }
 

+ 0 - 1
panda/src/cocoadisplay/cocoaPandaWindowDelegate.h

@@ -34,7 +34,6 @@ class CocoaGraphicsWindow;
 - (void)windowDidBecomeKey:(NSNotification *)notification;
 - (void)windowDidResignKey:(NSNotification *)notification;
 - (BOOL)windowShouldClose:(id)sender;
-- (void)windowWillClose:(NSNotification *)notification;
 
 // TODO: handle fullscreen on Lion.
 

+ 5 - 5
panda/src/cocoadisplay/cocoaPandaWindowDelegate.mm

@@ -50,11 +50,11 @@
 }
 
 - (BOOL) windowShouldClose:(id)sender {
-  return _graphicsWindow->handle_close_request();
-}
-
-- (void) windowWillClose:(NSNotification *)notification {
-  _graphicsWindow->handle_close_event();
+  bool should_close = _graphicsWindow->handle_close_request();
+  if (should_close) {
+    _graphicsWindow->handle_close_event();
+  }
+  return should_close;
 }
 
 @end

+ 174 - 84
panda/src/device/winInputDeviceManager.cxx

@@ -17,6 +17,22 @@
 
 #if defined(_WIN32) && !defined(CPPPARSER)
 
+#ifdef HAVE_THREADS
+/**
+ *
+ */
+class InputThread : public Thread {
+public:
+  InputThread(WinInputDeviceManager *manager) :
+    Thread("input", "input"), _manager(manager) {}
+
+private:
+  virtual void thread_main();
+
+  WinInputDeviceManager *_manager;
+};
+#endif
+
 /**
  * Initializes the input device manager by scanning which devices are currently
  * connected and setting up any platform-dependent structures necessary for
@@ -37,7 +53,7 @@ WinInputDeviceManager() :
   _xinput_device2.local_object();
   _xinput_device3.local_object();
 
-// This function is only available in Vista and later, so we use a wrapper.
+  // This function is only available in Vista and later, so we use a wrapper.
   HMODULE module = LoadLibraryA("cfgmgr32.dll");
   if (module) {
     _CM_Get_DevNode_PropertyW = (pCM_Get_DevNode_Property)GetProcAddress(module, "CM_Get_DevNode_PropertyW");
@@ -45,83 +61,16 @@ WinInputDeviceManager() :
     _CM_Get_DevNode_PropertyW = nullptr;
   }
 
-  // Now create a message-only window for the raw input.
-  WNDCLASSEX wc = {};
-  wc.cbSize = sizeof(WNDCLASSEX);
-  wc.lpfnWndProc = window_proc;
-  wc.hInstance = GetModuleHandle(nullptr);
-  wc.lpszClassName = "InputDeviceManager";
-  if (!RegisterClassEx(&wc)) {
-    device_cat.warning()
-      << "Failed to register message-only window class.\n";
-    return;
-   }
-
-  _message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
-  if (!_message_hwnd) {
-    device_cat.warning()
-      << "Failed to create message-only window.\n";
-    return;
-  }
-
-  // Now listen for raw input devices using the created message loop.
-  RAWINPUTDEVICE rid[3];
-  rid[0].usUsagePage = 1;
-  rid[0].usUsage = 4; // Joysticks
-  rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
-  rid[0].hwndTarget = _message_hwnd;
-  rid[1].usUsagePage = 1;
-  rid[1].usUsage = 5; // Gamepads
-  rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
-  rid[1].hwndTarget = _message_hwnd;
-  rid[2].usUsagePage = 1;
-  rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice)
-  rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
-  rid[2].hwndTarget = _message_hwnd;
-  if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) {
-    device_cat.warning()
-      << "Failed to register raw input devices.\n";
-  }
-
-  // Do we have any XInput devices plugged in now?
-  int num_xinput = 0;
-  HANDLE xinput_handle;
-  RAWINPUTDEVICELIST devices[64];
-  UINT num_devices = 64;
-  num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST));
-  if (num_devices == (UINT)-1) {
-    return;
-  }
-  for (UINT i = 0; i < num_devices; ++i) {
-    if (devices[i].dwType != RIM_TYPEHID) {
-      continue;
-    }
-    HANDLE handle = devices[i].hDevice;
-    UINT size;
-    if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) {
-      continue;
-    }
-
-    char *path = (char *)alloca(size);
-    if (path == nullptr ||
-        GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) {
-      continue;
-    }
-
-    if (strstr(path, "&IG_") != nullptr) {
-      xinput_handle = handle;
-      ++num_xinput;
-    }
-  }
-  if (num_xinput == 1) {
-    // There's only one XInput device, so we know which one it is.
-    on_input_device_arrival(xinput_handle);
-  } else if (num_xinput > 0) {
-    // Just poll all the XInput devices.
-    _xinput_device0.detect(this);
-    _xinput_device1.detect(this);
-    _xinput_device2.detect(this);
-    _xinput_device3.detect(this);
+  // If we have threading enabled, start a thread with a message-only window
+  // loop to listen for input events.
+#ifdef HAVE_THREADS
+  if (Thread::is_threading_supported()) {
+    PT(Thread) thread = new InputThread(this);
+    thread->start(TP_normal, false);
+  } else
+#endif
+  {
+    setup_message_loop();
   }
 }
 
@@ -131,8 +80,17 @@ WinInputDeviceManager() :
 WinInputDeviceManager::
 ~WinInputDeviceManager() {
   if (_message_hwnd != nullptr) {
-    DestroyWindow(_message_hwnd);
-    _message_hwnd = nullptr;
+#ifdef HAVE_THREADS
+    if (Thread::is_threading_supported()) {
+      HWND hwnd = _message_hwnd;
+      if (hwnd) {
+        SendMessage(hwnd, WM_QUIT, 0, 0);
+      }
+    } else
+#endif
+    {
+      destroy_message_loop();
+    }
   }
 }
 
@@ -397,10 +355,110 @@ on_input_device_removal(HANDLE handle) {
  */
 void WinInputDeviceManager::
 update() {
-  MSG msg;
-  while (PeekMessage(&msg, _message_hwnd, WM_INPUT_DEVICE_CHANGE, WM_INPUT, PM_REMOVE)) {
-    TranslateMessage(&msg);
-    DispatchMessage(&msg);
+}
+
+/**
+ * Sets up a Windows message loop.  Should be called from the thread that will
+ * be handling the messages.
+ */
+HWND WinInputDeviceManager::
+setup_message_loop() {
+  _message_hwnd = 0;
+
+  // Now create a message-only window for the raw input.
+  WNDCLASSEX wc = {};
+  wc.cbSize = sizeof(WNDCLASSEX);
+  wc.lpfnWndProc = window_proc;
+  wc.hInstance = GetModuleHandle(nullptr);
+  wc.lpszClassName = "InputDeviceManager";
+  if (!RegisterClassEx(&wc)) {
+    device_cat.warning()
+      << "Failed to register message-only window class for input device detection.\n";
+  } else {
+    _message_hwnd = CreateWindowEx(0, wc.lpszClassName, "InputDeviceManager", 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
+    if (!_message_hwnd) {
+      device_cat.warning()
+        << "Failed to create message-only window for input device detection.\n";
+    }
+  }
+
+  // Now listen for raw input devices using the created message loop.
+  RAWINPUTDEVICE rid[3];
+  rid[0].usUsagePage = 1;
+  rid[0].usUsage = 4; // Joysticks
+  rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
+  rid[0].hwndTarget = _message_hwnd;
+  rid[1].usUsagePage = 1;
+  rid[1].usUsage = 5; // Gamepads
+  rid[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
+  rid[1].hwndTarget = _message_hwnd;
+  rid[2].usUsagePage = 1;
+  rid[2].usUsage = 8; // Multi-axis controllers (including 3D mice)
+  rid[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
+  rid[2].hwndTarget = _message_hwnd;
+  if (!RegisterRawInputDevices(rid, 3, sizeof(RAWINPUTDEVICE))) {
+    device_cat.warning()
+      << "Failed to register raw input devices.\n";
+  }
+
+  // Do we have any XInput devices plugged in now?
+  int num_xinput = 0;
+  HANDLE xinput_handle;
+  RAWINPUTDEVICELIST devices[64];
+  UINT num_devices = 64;
+  num_devices = GetRawInputDeviceList(devices, &num_devices, sizeof(RAWINPUTDEVICELIST));
+  if (num_devices == (UINT)-1) {
+    num_devices = 0;
+  }
+  for (UINT i = 0; i < num_devices; ++i) {
+    if (devices[i].dwType != RIM_TYPEHID) {
+      continue;
+    }
+    HANDLE handle = devices[i].hDevice;
+    UINT size;
+    if (GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, nullptr, &size) != 0) {
+      continue;
+    }
+
+    char *path = (char *)alloca(size);
+    if (path == nullptr ||
+        GetRawInputDeviceInfoA(handle, RIDI_DEVICENAME, (void *)path, &size) < 0) {
+      continue;
+    }
+
+    if (strstr(path, "&IG_") != nullptr) {
+      xinput_handle = handle;
+      ++num_xinput;
+    }
+  }
+  if (num_xinput == 1) {
+    // There's only one XInput device, so we know which one it is.
+    on_input_device_arrival(xinput_handle);
+  } else if (num_xinput > 0) {
+    // Just poll all the XInput devices.
+    _xinput_device0.detect(this);
+    _xinput_device1.detect(this);
+    _xinput_device2.detect(this);
+    _xinput_device3.detect(this);
+  }
+
+  return _message_hwnd;
+}
+
+/**
+ * Tears down the message loop.  Should be called from the thread that called
+ * setup_message_loop().
+ */
+void WinInputDeviceManager::
+destroy_message_loop() {
+  HWND hwnd = nullptr;
+  {
+    LightMutexHolder holder(_lock);
+    std::swap(_message_hwnd, hwnd);
+  }
+
+  if (hwnd) {
+    DestroyWindow(hwnd);
   }
 }
 
@@ -442,4 +500,36 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
   return DefWindowProcW(hwnd, msg, wparam, lparam);
 }
 
+#ifdef HAVE_THREADS
+/**
+ * Thread entry point for the input listener thread.
+ */
+void InputThread::
+thread_main() {
+  WinInputDeviceManager *manager = _manager;
+  HWND hwnd = manager->setup_message_loop();
+  if (!hwnd) {
+    return;
+  }
+
+  if (device_cat.is_debug()) {
+    device_cat.debug()
+      << "Started input device listener thread.\n";
+  }
+
+  MSG msg;
+  while (GetMessage(&msg, nullptr, 0, 0) > 0) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+
+  if (device_cat.is_debug()) {
+    device_cat.debug()
+      << "Stopping input device listener thread.\n";
+  }
+
+  manager->destroy_message_loop();
+}
+#endif  // HAVE_THREADS
+
 #endif

+ 3 - 0
panda/src/device/winInputDeviceManager.h

@@ -41,6 +41,9 @@ public:
   void on_input_device_arrival(HANDLE handle);
   void on_input_device_removal(HANDLE handle);
 
+  HWND setup_message_loop();
+  void destroy_message_loop();
+
 private:
   // There are always exactly four of these in existence.
   XInputDevice _xinput_device0;