From b67c7dd84f6174f439ccafc3339cd2e850e47930 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 17 Dec 2019 22:32:06 +0100 Subject: [PATCH 01/10] device: support digitizers via Win32 raw input API --- panda/src/device/inputDevice.cxx | 6 ++++++ panda/src/device/inputDevice.h | 6 ++++++ panda/src/device/phidsdi.h | 1 + panda/src/device/winInputDeviceManager.cxx | 9 +++++++-- panda/src/device/winRawInputDevice.cxx | 13 +++++++++++++ 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/panda/src/device/inputDevice.cxx b/panda/src/device/inputDevice.cxx index cce2f975b4..71869abc64 100644 --- a/panda/src/device/inputDevice.cxx +++ b/panda/src/device/inputDevice.cxx @@ -578,6 +578,9 @@ format_device_class(DeviceClass dc) { case InputDevice::DeviceClass::spatial_mouse: return "spatial_mouse"; + + case InputDevice::DeviceClass::digitizer: + return "digitizer"; } return "**invalid**"; } @@ -644,6 +647,9 @@ format_axis(Axis axis) { case InputDevice::Axis::brake: return "brake"; + + case InputDevice::Axis::pressure: + return "pressure"; } return "**invalid**"; } diff --git a/panda/src/device/inputDevice.h b/panda/src/device/inputDevice.h index f3f500e378..83038075a8 100644 --- a/panda/src/device/inputDevice.h +++ b/panda/src/device/inputDevice.h @@ -80,6 +80,9 @@ PUBLISHED: // 3D mouse, such as produced by 3Dconnexion. spatial_mouse, + + // A graphics tablet with stylus/pen. + digitizer, }; enum class Feature { @@ -128,6 +131,9 @@ PUBLISHED: wheel, accelerator, brake, + + // Pen pressure + pressure, }; enum State { diff --git a/panda/src/device/phidsdi.h b/panda/src/device/phidsdi.h index 647b3ed322..5917155b0c 100644 --- a/panda/src/device/phidsdi.h +++ b/panda/src/device/phidsdi.h @@ -28,6 +28,7 @@ typedef USHORT USAGE, *PUSAGE; #define HID_USAGE_PAGE_KEYBOARD ((USAGE) 0x07) #define HID_USAGE_PAGE_LED ((USAGE) 0x08) #define HID_USAGE_PAGE_BUTTON ((USAGE) 0x09) +#define HID_USAGE_PAGE_DIGITIZER ((USAGE) 0x0d) #define HID_USAGE_GENERIC_POINTER ((USAGE) 0x01) #define HID_USAGE_GENERIC_MOUSE ((USAGE) 0x02) diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 2ca4540ae6..0d2c69f216 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -14,6 +14,7 @@ #include "winInputDeviceManager.h" #include "winRawInputDevice.h" #include "throw_event.h" +#include "phidsdi.h" #if defined(_WIN32) && !defined(CPPPARSER) @@ -385,7 +386,7 @@ setup_message_loop() { } // Now listen for raw input devices using the created message loop. - RAWINPUTDEVICE rid[3]; + RAWINPUTDEVICE rid[4]; rid[0].usUsagePage = 1; rid[0].usUsage = 4; // Joysticks rid[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; @@ -398,7 +399,11 @@ setup_message_loop() { 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))) { + rid[3].usUsagePage = HID_USAGE_PAGE_DIGITIZER; + rid[3].usUsage = 1; // Digitizers + rid[3].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; + rid[3].hwndTarget = _message_hwnd; + if (!RegisterRawInputDevices(rid, 4, sizeof(RAWINPUTDEVICE))) { device_cat.warning() << "Failed to register raw input devices.\n"; } diff --git a/panda/src/device/winRawInputDevice.cxx b/panda/src/device/winRawInputDevice.cxx index 10262d124c..843e434a16 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -199,6 +199,11 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { info.hid.usUsage == HID_USAGE_GENERIC_KEYBOARD) { _device_class = DeviceClass::keyboard; + // Digitizers + } else if (info.hid.usUsagePage == HID_USAGE_PAGE_DIGITIZER && + info.hid.usUsage == 1) { + _device_class = DeviceClass::digitizer; + // 3Dconnexion SpaceNavigator and friends. } else if (_vendor_id == 0x046d && (_product_id == 0xc623 || @@ -504,6 +509,14 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { continue; } break; + + case HID_USAGE_PAGE_DIGITIZER: + switch (usage) { + case 0x30: + axis = Axis::pressure; + break; + } + break; } // If this axis already exists, don't double-map it, but take the first From 986b803e71cc7ea71e3ce8dc2163a86a8dcebef7 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 17 Dec 2019 22:56:26 +0100 Subject: [PATCH 02/10] device: recognize digitizers and pressure axis as well in evdev Note that the Y axis is still inverted compared to on Windows; we need to decide what convention to follow here. --- panda/src/device/evdevInputDevice.cxx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index 69d2979f7f..b41bb15ffd 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -364,7 +364,7 @@ init_device() { // Try to detect which type of device we have here if (_device_class == DeviceClass::unknown) { - int device_scores[(size_t)DeviceClass::spatial_mouse] = {0}; + int device_scores[(size_t)DeviceClass::digitizer + 1] = {0}; // Test for specific keys if (test_bit(BTN_GAMEPAD, keys) && test_bit(ABS_X, axes) && test_bit(ABS_RX, axes)) { @@ -385,6 +385,9 @@ init_device() { if (test_bit(BTN_MOUSE, keys) && test_bit(EV_REL, evtypes)) { device_scores[(size_t)DeviceClass::mouse] += 20; } + if (test_bit(BTN_DIGI, keys) && test_bit(EV_ABS, evtypes)) { + device_scores[(size_t)DeviceClass::digitizer] += 20; + } uint8_t unknown_keys[] = {KEY_POWER}; for (int i = 0; i < 1; i++) { if (test_bit(unknown_keys[i], keys)) { @@ -424,7 +427,7 @@ init_device() { // Check which device type got the most points int highest_score = 0; - for (size_t i = 0; i < (size_t)DeviceClass::spatial_mouse; i++) { + for (size_t i = 0; i <= (size_t)DeviceClass::digitizer; i++) { if (device_scores[i] > highest_score) { highest_score = device_scores[i]; _device_class = (DeviceClass)i; @@ -619,6 +622,9 @@ init_device() { have_analog_triggers = true; } break; + case ABS_PRESSURE: + axis = InputDevice::Axis::pressure; + break; } // Check the initial value and ranges. From 0b52241e95de60f582b89cffbcff52ec2c36f4d5 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 17 Dec 2019 22:58:12 +0100 Subject: [PATCH 03/10] stdpy: return number of bytes from write() method --- direct/src/stdpy/file.py | 1 + 1 file changed, 1 insertion(+) diff --git a/direct/src/stdpy/file.py b/direct/src/stdpy/file.py index 458406a1e0..49896c2109 100644 --- a/direct/src/stdpy/file.py +++ b/direct/src/stdpy/file.py @@ -304,6 +304,7 @@ class StreamIOWrapper(io.IOBase): self.__stream.clear() # clear eof flag self.__write(b) self.__lastWrite = True + return len(b) def writelines(self, lines): if not self.__writer: From 4c62260291db6f3301d574669091bf673cb50fca Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 18 Dec 2019 08:41:11 -0500 Subject: [PATCH 04/10] makepanda: add -framework AudioUnit for OpenAL Soft (#678) --- makepanda/makepanda.py | 1 + 1 file changed, 1 insertion(+) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 39e6805f61..f62ffda6b2 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -978,6 +978,7 @@ if (COMPILER=="GCC"): PkgDisable("OPENCV") if GetTarget() == "darwin" and not PkgSkip("OPENAL"): + LibName("OPENAL", "-framework AudioUnit") LibName("OPENAL", "-framework AudioToolbox") LibName("OPENAL", "-framework CoreAudio") From 0456fdcd92f6789e340fa6969200b506a9dc0372 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 18 Dec 2019 08:42:43 -0500 Subject: [PATCH 05/10] makepanda: update CommandLineTools paths for newer XCode versions --- makepanda/makepanda.py | 2 ++ makepanda/makepandacore.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index f62ffda6b2..884b79733a 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -2044,6 +2044,8 @@ def CompileRsrc(target, src, opts): ipath = GetListOption(opts, "DIR:") if os.path.isfile("/usr/bin/Rez"): cmd = "Rez -useDF" + elif os.path.isfile("/Library/Developer/CommandLineTools/usr/bin/Rez"): + cmd = "/Library/Developer/CommandLineTools/usr/bin/Rez -useDF" else: cmd = "/Developer/Tools/Rez -useDF" cmd += " -o " + BracketNameWithQuotes(target) diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 18be690671..d450926df4 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -2383,7 +2383,9 @@ def SdkLocateMacOSX(osxtarget = None): if (GetHost() != "darwin"): return if (osxtarget != None): sdkname = "MacOSX%d.%d" % osxtarget - if (os.path.exists("/Developer/SDKs/%su.sdk" % sdkname)): + if (os.path.exists("/Library/Developer/CommandLineTools/SDKs/%s.sdk" % sdkname)): + SDK["MACOSX"] = "/Library/Developer/CommandLineTools/SDKs/%s.sdk" % sdkname + elif (os.path.exists("/Developer/SDKs/%su.sdk" % sdkname)): SDK["MACOSX"] = "/Developer/SDKs/%su.sdk" % sdkname elif (os.path.exists("/Developer/SDKs/%s.sdk" % sdkname)): SDK["MACOSX"] = "/Developer/SDKs/%s.sdk" % sdkname From 8645e9d2a41008d42b364b2f77256eff01e6f101 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 18 Dec 2019 09:06:15 -0500 Subject: [PATCH 06/10] makepanda: distinguish macOS 10.6 from 10.9 libs in thirdparties This is specifically for C++ thirdparty libraries, which are linked against either libc++ or libstdc++, and can now both be present in the thirdparty download, in order to address #584 This is a temporary fix for 1.10.5 that will not be present on master (due to #300) --- makepanda/makepandacore.py | 65 ++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index d450926df4..9cb726e20a 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -1345,6 +1345,52 @@ def GetThirdpartyDir(): return THIRDPARTYDIR +def GetThirdpartyLibDir(pkg): + pkg_dir = os.path.join(GetThirdpartyDir(), pkg.lower()) + lib_dir = os.path.join(pkg_dir, "lib") + + if GetTarget() != 'darwin': + return lib_dir + + osxtarget = SDK["OSXTARGET"] + if osxtarget >= (10, 9): + return lib_dir + elif osxtarget >= (10, 8) and os.path.isdir(lib_dir + "-10.8"): + return lib_dir + "-10.8" + elif osxtarget >= (10, 7) and os.path.isdir(lib_dir + "-10.7"): + return lib_dir + "-10.7" + elif os.path.isdir(lib_dir + "-10.6"): + return lib_dir + "-10.6" + else: + return lib_dir + +def GetThirdpartyIncDir(pkg): + pkg_dir = os.path.join(GetThirdpartyDir(), pkg.lower()) + inc_dir = os.path.join(pkg_dir, "include") + + if GetTarget() != 'darwin': + return inc_dir + + osxtarget = SDK["OSXTARGET"] + lib_dir = os.path.join(pkg_dir, "lib") + if osxtarget >= (10, 9): + return inc_dir + elif osxtarget >= (10, 8) and os.path.isdir(lib_dir + "-10.8"): + suffix = "-10.8" + elif osxtarget >= (10, 7) and os.path.isdir(lib_dir + "-10.7"): + suffix = "-10.7" + elif os.path.isdir(lib_dir + "-10.6"): + suffix = "-10.6" + else: + suffix = "" + + # Make sure we pick the include dir matching the lib dir we picked, or fall + # back to a generic include dir. + if os.path.isdir(inc_dir + suffix): + return inc_dir + suffix + else: + return inc_dir + ######################################################################## ## ## Gets or sets the output directory, by default "built". @@ -1633,7 +1679,7 @@ def ChooseLib(libs, thirdparty=None): lpath = [] if thirdparty is not None: - lpath.append(os.path.join(GetThirdpartyDir(), thirdparty.lower(), "lib")) + lpath.append(GetThirdpartyLibDir(thirdparty)) lpath += SYS_LIB_DIRS for l in libs: @@ -1690,18 +1736,20 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None, LibName(target_pkg, "-framework " + framework) return - if os.path.isdir(os.path.join(pkg_dir, "include")): - IncDirectory(target_pkg, os.path.join(pkg_dir, "include")) + inc_dir = GetThirdpartyIncDir(thirdparty_dir) + if os.path.isdir(inc_dir): + IncDirectory(target_pkg, inc_dir) # Handle cases like freetype2 where the include dir is a subdir under "include" for i in incs: - if os.path.isdir(os.path.join(pkg_dir, "include", i)): - IncDirectory(target_pkg, os.path.join(pkg_dir, "include", i)) + if os.path.isdir(os.path.join(inc_dir, i)): + IncDirectory(target_pkg, os.path.join(inc_dir, i)) - lpath = [os.path.join(pkg_dir, "lib")] + lib_dir = GetThirdpartyLibDir(thirdparty_dir) + lpath = [lib_dir] if not PkgSkip("PYTHON"): - py_lib_dir = os.path.join(pkg_dir, "lib", SDK["PYTHONVERSION"]) + py_lib_dir = os.path.join(lib_dir, SDK["PYTHONVERSION"]) if os.path.isdir(py_lib_dir): lpath.append(py_lib_dir) @@ -2401,8 +2449,11 @@ def SdkLocateMacOSX(osxtarget = None): SDK["MACOSX"] = "%s/Platforms/MacOSX.platform/Developer/SDKs/%s.sdk" % (result, sdkname) else: exit("Couldn't find any MacOSX SDK for OSX version %s!" % sdkname) + SDK["OSXTARGET"] = osxtarget else: SDK["MACOSX"] = "" + maj, min = platform.mac_ver()[0].split('.')[:2] + SDK["OSXTARGET"] = int(maj), int(min) # Latest first PHYSXVERSIONINFO = [ From 8e6ae703c12bfa1dbf0d6e9a44439ec633ec0c06 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 18 Dec 2019 09:10:28 -0500 Subject: [PATCH 07/10] dist: use macosx_10_9_x86_64 by default for Python 3.8+ This is because Python 3.8 is only available for macOS 10.9+, and no longer for 10.6. --- direct/src/dist/commands.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index cdd8628bc4..36c98949c0 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -240,6 +240,9 @@ class build_apps(setuptools.Command): 'macosx_10_6_x86_64', 'win_amd64', ] + if sys.version_info >= (3, 8): + # This version of Python is only available for 10.9+. + self.platforms[1] = 'macosx_10_9_x86_64' self.plugins = [] self.embed_prc_data = True self.extra_prc_files = [] From b6161a68adcd6111d3e7ea0a27114819277ded13 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 18 Dec 2019 09:22:09 -0500 Subject: [PATCH 08/10] readme: update macOS thirdparty link to 1.10.5 [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62f0d044df..623052b7fa 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ macOS ----- On macOS, you will need to download a set of precompiled thirdparty packages in order to -compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.4.1/panda3d-1.10.4.1-tools-mac.tar.gz). +compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.5/panda3d-1.10.5-tools-mac.tar.gz). After placing the thirdparty directory inside the panda3d source directory, you may build Panda3D using a command like the following: From 02b0fe0063808887b318483c177cd23c2b4b713b Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 18 Dec 2019 16:53:23 +0100 Subject: [PATCH 09/10] installpanda: add note about needing to call "sudo ldconfig" This note only appears when not using --destdir This should help avoid user confusion (such as in #818) [skip ci] --- makepanda/installpanda.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index dcb18a72bf..529913aadf 100644 --- a/makepanda/installpanda.py +++ b/makepanda/installpanda.py @@ -322,3 +322,8 @@ if (__name__ == "__main__"): outputdir=options.outputdir, python_versions=ReadPythonVersionInfoFile()) print("Installation finished!") + + if not destdir: + warn_prefix = "%sNote:%s " % (GetColor("red"), GetColor()) + print(warn_prefix + "You may need to call this command to update the library cache:") + print(" sudo ldconfig") From 72c5555dc068fcd7c0c569073c509a51f209aeba Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 18 Dec 2019 17:55:44 +0100 Subject: [PATCH 10/10] device: invert digitizer Y axis on Linux to match Windows It may intuitively feel upside down, but the current behaviour actually matches base.mouseWatcherNode, so this is probably the most consistent thing to do. --- panda/src/device/evdevInputDevice.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/panda/src/device/evdevInputDevice.cxx b/panda/src/device/evdevInputDevice.cxx index b41bb15ffd..26bb83186e 100644 --- a/panda/src/device/evdevInputDevice.cxx +++ b/panda/src/device/evdevInputDevice.cxx @@ -636,7 +636,8 @@ init_device() { // Also T.Flight Hotas X throttle is reversed and can go backwards. if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y || (axis == Axis::throttle && (quirks & QB_reversed_throttle) != 0) || - (_device_class == DeviceClass::spatial_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll))) { + (_device_class == DeviceClass::spatial_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll)) || + (_device_class == DeviceClass::digitizer && axis == Axis::y)) { std::swap(absinfo.maximum, absinfo.minimum); } if (axis == Axis::throttle && (quirks & QB_centered_throttle) != 0) {