Browse Source

Merge branch 'master' into webgl-port

rdb 5 years ago
parent
commit
6084366946
100 changed files with 1630 additions and 1074 deletions
  1. 22 0
      .editorconfig
  2. 25 0
      .github/ISSUE_TEMPLATE/bug.md
  3. 15 0
      .github/ISSUE_TEMPLATE/enhancement.md
  4. 15 0
      .github/PULL_REQUEST_TEMPLATE.md
  5. 16 0
      .github/codecov.yml
  6. 3 32
      .github/workflows/ci.yml
  7. 1 0
      .gitignore
  8. 0 60
      .travis.yml
  9. 1 0
      CMakeLists.txt
  10. 55 0
      CONTRIBUTING.md
  11. 6 6
      README.md
  12. 50 0
      cmake/macros/PerConfigOption.cmake
  13. 7 0
      cmake/templates/METADATA.in
  14. 7 0
      contrib/src/contribbase/contribsymbols.h
  15. 21 21
      contrib/src/rplight/rpLight.I
  16. 0 0
      contrib/src/speedtree/config_speedtree.cxx
  17. 1 1
      contrib/src/speedtree/config_speedtree.h
  18. 0 0
      contrib/src/speedtree/loaderFileTypeSrt.cxx
  19. 1 1
      contrib/src/speedtree/loaderFileTypeSrt.h
  20. 0 0
      contrib/src/speedtree/loaderFileTypeStf.cxx
  21. 1 1
      contrib/src/speedtree/loaderFileTypeStf.h
  22. 0 0
      contrib/src/speedtree/pandaspeedtree_composite1.cxx
  23. 0 0
      contrib/src/speedtree/speedTreeNode.I
  24. 1 1
      contrib/src/speedtree/speedTreeNode.cxx
  25. 1 1
      contrib/src/speedtree/speedTreeNode.h
  26. 0 0
      contrib/src/speedtree/speedtree_api.cxx
  27. 0 0
      contrib/src/speedtree/speedtree_api.h
  28. 0 0
      contrib/src/speedtree/stBasicTerrain.I
  29. 0 0
      contrib/src/speedtree/stBasicTerrain.cxx
  30. 1 1
      contrib/src/speedtree/stBasicTerrain.h
  31. 0 0
      contrib/src/speedtree/stTerrain.I
  32. 0 0
      contrib/src/speedtree/stTerrain.cxx
  33. 1 1
      contrib/src/speedtree/stTerrain.h
  34. 0 0
      contrib/src/speedtree/stTransform.I
  35. 0 0
      contrib/src/speedtree/stTransform.cxx
  36. 1 1
      contrib/src/speedtree/stTransform.h
  37. 0 0
      contrib/src/speedtree/stTree.I
  38. 0 0
      contrib/src/speedtree/stTree.cxx
  39. 1 1
      contrib/src/speedtree/stTree.h
  40. 15 1
      direct/CMakeLists.txt
  41. 5 1
      direct/src/actor/Actor.py
  42. 3 0
      direct/src/actor/__init__.py
  43. 3 3
      direct/src/dcparser/dcClass.cxx
  44. 3 2
      direct/src/dcparser/dcClass.h
  45. 3 0
      direct/src/dcparser/dcLexer.cxx.prebuilt
  46. 3 1
      direct/src/dcparser/dcLexer.lxx
  47. 5 3
      direct/src/dcparser/dcPacker.I
  48. 1 1
      direct/src/dcparser/dcPacker.cxx
  49. 1 3
      direct/src/dcparser/dcPackerCatalog.cxx
  50. 1 3
      direct/src/dcparser/dcPackerInterface.cxx
  51. 3 9
      direct/src/dcparser/dcSwitch.cxx
  52. 2 0
      direct/src/dcparser/dcbase.h
  53. 1 1
      direct/src/directbase/DirectStart.py
  54. 1 0
      direct/src/directscripts/Doxyfile.cxx
  55. 1 1
      direct/src/directtools/DirectManipulation.py
  56. 0 10
      direct/src/directutil/DirectMySQLdb.py
  57. 0 117
      direct/src/directutil/DirectMySQLdbConnection.py
  58. 138 16
      direct/src/dist/FreezeTool.py
  59. 27 13
      direct/src/dist/commands.py
  60. 1 0
      direct/src/distributed/ConnectionRepository.py
  61. 3 2
      direct/src/distributed/ServerRepository.py
  62. 3 0
      direct/src/distributed/__init__.py
  63. 2 5
      direct/src/extensions_native/CInterval_extensions.py
  64. 119 3
      direct/src/filter/CommonFilters.py
  65. 7 1
      direct/src/filter/FilterManager.py
  66. 3 0
      direct/src/filter/__init__.py
  67. 2 19
      direct/src/fsm/State.py
  68. 16 0
      direct/src/gui/DirectGuiGlobals.py
  69. 1 2
      direct/src/interval/FunctionInterval.py
  70. 5 5
      direct/src/showbase/DirectObject.py
  71. 9 9
      direct/src/showbase/Loader.py
  72. 2 3
      direct/src/showbase/Messenger.py
  73. 3 3
      direct/src/showbase/OnScreenDebug.py
  74. 0 1
      direct/src/showbase/ProfileSession.py
  75. 4 3
      direct/src/showbase/PythonUtil.py
  76. 277 141
      direct/src/showbase/ShowBase.py
  77. 10 5
      direct/src/showbase/ShowBaseGlobal.py
  78. 3 0
      direct/src/showbase/__init__.py
  79. 6 3
      direct/src/showutil/TexMemWatcher.py
  80. 2 1
      direct/src/stdpy/__init__.py
  81. 1 3
      direct/src/task/Task.py
  82. 14 8
      direct/src/tkpanels/Inspector.py
  83. 71 0
      doc/ReleaseNotes
  84. 57 63
      dtool/Config.cmake
  85. 7 4
      dtool/LocalSetup.cmake
  86. 2 2
      dtool/Package.cmake
  87. 1 50
      dtool/PandaVersion.cmake
  88. 432 353
      dtool/src/cppparser/cppBison.cxx.prebuilt
  89. 6 2
      dtool/src/cppparser/cppBison.h.prebuilt
  90. 13 37
      dtool/src/cppparser/cppBison.yxx
  91. 47 9
      dtool/src/cppparser/cppExpression.cxx
  92. 3 1
      dtool/src/cppparser/cppExpression.h
  93. 11 1
      dtool/src/cppparser/cppInstance.cxx
  94. 1 1
      dtool/src/cppparser/cppInstanceIdentifier.cxx
  95. 2 2
      dtool/src/cppparser/cppInstanceIdentifier.h
  96. 1 3
      dtool/src/cppparser/cppManifest.cxx
  97. 2 2
      dtool/src/dtoolbase/cmath.I
  98. 6 2
      dtool/src/dtoolbase/deletedChain.h
  99. 6 2
      dtool/src/dtoolbase/memoryBase.h
  100. 0 10
      dtool/src/dtoolbase/pandaVersion.h.in

+ 22 - 0
.editorconfig

@@ -0,0 +1,22 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{py,pyw}]
+indent_style = space
+indent_size = 4
+
+[*.{h,c,cxx,cpp,I,T}]
+indent_style = space
+indent_size = 2
+
+[{CMakeLists.txt,*.cmake}]
+indent_style = space
+indent_size = 2
+
+[*.bat]
+end_of_line = crlf

+ 25 - 0
.github/ISSUE_TEMPLATE/bug.md

@@ -0,0 +1,25 @@
+---
+name: Bug report
+about: Report a defect
+title:
+labels:
+assignees:
+---
+
+## Description
+<!-- Provide a clear and concise description of the bug: what you expected to
+     happen, and what actually happened instead.  If you have a log file or
+     crash report, please attach those! -->
+
+## Steps to Reproduce
+<!-- The most minimal but complete set of steps to reproduce the bug, with a
+     code snippet that clearly demonstrates the bug.  We must be able to run
+     the code, ie. you must include any required assets. -->
+
+## Environment
+ * Operating system:
+ * System architecture:
+ * Panda3D version: <!-- import panda3d; print(panda3d.__version__) -->
+ * Installation method: (eg. pip, wheel, SDK, built from source)
+ * Python version (if using Python):
+ * Compiler (if using C++):

+ 15 - 0
.github/ISSUE_TEMPLATE/enhancement.md

@@ -0,0 +1,15 @@
+---
+name: Enhancement request
+about: Request new functionality or improvement to existing functionality
+title:
+labels: enhancement
+assignees:
+---
+
+## Description
+<!-- Please clearly describe which change you want to be made. -->
+
+## Use Case
+<!-- Describe why you need this change, how it will help you, including any
+     other imagined scenarios in which it will be useful.  If this request is
+     urgent and you have no alternatives, please state so as well. -->

+ 15 - 0
.github/PULL_REQUEST_TEMPLATE.md

@@ -0,0 +1,15 @@
+## Issue description
+<!-- What is this change intended to accomplish?  What problem does it solve?
+     If this change resolves a GitHub issue, include the issue number. -->
+
+## Solution description
+<!-- Explain here how your PR solves the problem, what approach it takes. -->
+
+## Checklist
+I have done my best to ensure that…
+* [ ] …I have familiarized myself with the CONTRIBUTING.md file
+* [ ] …this change follows the coding style and design patterns of the codebase
+* [ ] …I own the intellectual property rights to this code
+* [ ] …the intent of this change is clearly explained
+* [ ] …existing uses of the Panda3D API are not broken
+* [ ] …the changed code is adequately covered by the test suite, where possible.

+ 16 - 0
.github/codecov.yml

@@ -0,0 +1,16 @@
+coverage:
+  status:
+    project:
+      default:
+        threshold: 0.1
+    patch:
+      default:
+        target: 0%
+codecov:
+  require_ci_to_pass: true
+  notify:
+    after_n_builds: 2
+    wait_for_ci: true
+comment:
+  require_changes: true
+  after_n_builds: 2

+ 3 - 32
.github/workflows/ci.yml

@@ -4,6 +4,7 @@ on: [push, pull_request]
 jobs:
   cmake:
     name: CMake Buildsystem
+    if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
 
     strategy:
       fail-fast: false
@@ -181,37 +182,6 @@ jobs:
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
 
-    - name: Setup Python (Python 3.5)
-      if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v1
-      with:
-        python-version: 3.5
-    - name: Configure (Python 3.5)
-      if: contains(matrix.python, 'YES')
-      working-directory: build
-      shell: bash
-      run: >
-        cmake -DWANT_PYTHON_VERSION=3.5
-        -DPython_FIND_REGISTRY=NEVER -DPython_ROOT=$pythonLocation .
-    - name: Build (Python 3.5)
-      if: contains(matrix.python, 'YES')
-      # BEGIN A
-      working-directory: build
-      run: cmake --build . --config ${{ matrix.config }} --parallel 4
-      # END A
-    - name: Test (Python 3.5)
-      # BEGIN B
-      if: contains(matrix.python, 'YES')
-      working-directory: build
-      shell: bash
-      env:
-        PYTHONPATH: ${{ matrix.config }}
-      run: |
-        PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//')
-        $PYTHON_EXECUTABLE -m pip install pytest
-        $PYTHON_EXECUTABLE -m pytest ../tests
-      # END B
-
     - name: Setup Python (Python 3.6)
       if: contains(matrix.python, 'YES')
       uses: actions/setup-python@v1
@@ -323,9 +293,10 @@ jobs:
 
         llvm-profdata merge pid-*.profraw -o coverage.profdata
         llvm-cov show $(grep -Rl LLVM_PROFILE_FILE . | sed 's/^/-object /') -instr-profile=coverage.profdata > coverage.txt
-        bash <(curl -s https://codecov.io/bash)
+        bash <(curl -s https://codecov.io/bash) -y ../.github/codecov.yml
 
   makepanda:
+    if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
     strategy:
       matrix:
         os: [ubuntu-16.04, windows-2016, macOS-latest]

+ 1 - 0
.gitignore

@@ -3,6 +3,7 @@
 /thirdparty/
 /targetroot/
 /dstroot/
+/sdks/
 
 # Core dumps and traces
 core

+ 0 - 60
.travis.yml

@@ -1,60 +0,0 @@
-language: cpp
-sudo: false
-matrix:
-  include:
-    - compiler: clang
-      env: PYTHONV=python3 FLAGS=--installer
-    - compiler: clang
-      env: PYTHONV=python3 FLAGS=--override=STDFLOAT_DOUBLE=1
-    - compiler: gcc
-      env: PYTHONV=python3 FLAGS=--optimize=4
-      before_install:
-        - export CC=gcc-4.7
-        - export CXX=g++-4.7
-    - compiler: clang
-      env: PYTHONV=python3 FLAGS=--no-python SKIP_TESTS=1
-addons:
-  apt:
-    sources:
-    - ubuntu-toolchain-r-test
-    packages:
-    - gcc-4.7
-    - g++-4.7
-    - bison
-    - flex
-    - libfreetype6-dev
-    - libgl1-mesa-dev
-    - libjpeg-dev
-    - libode-dev
-    - libopenal-dev
-    - libpng-dev
-    - libssl-dev
-    - libvorbis-dev
-    - libx11-dev
-    - libxcursor-dev
-    - libxrandr-dev
-    - nvidia-cg-toolkit
-    - python-dev
-    - python3-dev
-    - python-virtualenv
-    - zlib1g-dev
-    - fakeroot
-install:
-    - virtualenv --python=$PYTHONV venv && source venv/bin/activate
-    - $PYTHONV -m pip install pytest
-script:
-    - $PYTHONV makepanda/makepanda.py --everything --git-commit $TRAVIS_COMMIT $FLAGS --threads 4
-    - test -n "$SKIP_TESTS" || LD_LIBRARY_PATH=built/lib PYTHONPATH=built $PYTHONV -m pytest -v tests
-notifications:
-  irc:
-    channels:
-      - secure: "jfwHT9RHAVOGRGTMY8TpYKJI6rq8nFoIj41Y0soZdJQNWtSSFEK9AyzZeMY+2dHga7cR/X+/0NWZ2ehhedTnd9FvlzOnMWWC3K0I/b3XWbEdVEqIZnggFkKGqs82Gy3omguRC63yWupeJCcSCckIhoWbLzWy6xV8lF5WC80iXi8="
-    on_success: change
-    on_failure: always
-    use_notice: true
-    skip_join: false
-  webhooks:
-    urls:
-      - https://www.panda3d.org/webhooks/travis-ci.php
-    on_success: change
-    on_failure: always

+ 1 - 0
CMakeLists.txt

@@ -79,6 +79,7 @@ include(GNUInstallDirs)     # Defines CMAKE_INSTALL_<dir> variables
 
 # Include global modules needed for configure scripts
 include(PackageConfig)      # Defines package_option
+include(PerConfigOption)    # Defines per_config_option
 
 # Configure Panda3D
 include(dtool/CompilerFlags.cmake)

+ 55 - 0
CONTRIBUTING.md

@@ -0,0 +1,55 @@
+# Contributing to Panda3D
+
+Panda3D is an open-source, community-driven project, completely dependent on the
+contribution of volunteers.  As such we highly welcome you to contribute code to
+the project.  This document aims to outline some guidelines for doing so.
+
+If you would like to contribute but aren't sure where to start, please visit the
+[Get Involved](https://www.panda3d.org/get-involved/) page on our website, or
+the excellent [Open Source Guide](https://opensource.guide/how-to-contribute/).
+
+## Before implementing a change
+
+We highly recommend that you file issues before making a change.  Issues are
+used to track bugs and feature requests but also to get feedback from the other
+developers about design decisions or a specific implementation strategy.
+
+It is important for acceptance that the change is implemented in a way that fits
+the general design principles of the Panda3D API, and fits well with the general
+priorities of the team.  Therefore, prior discussion with other developers is
+critical.  Issues can be used to facilitate this, but we also invite you to
+visit the #development channel on Discord (or #panda3d-devel on FreeNode IRC).
+
+We also recommend that you familiarize yourself with the established coding
+style and design patterns of Panda3D, to reduce the amount of changes that have
+to be made during the review process.
+
+## Submitting a change
+
+All changes from non-core contributors are made via pull requests.  This
+requires you to fork the Panda3D repository, create a branch for your change,
+push your changes to this branch, and request that this branch is merged into
+the upstream branch.  Each pull request is reviewed by a maintainer and
+automatically tested for regressions and unit test coverage.  The maintainer
+will suggest any changes, which you can add by committing more code to the same
+branch (you can do a force push if necessary).  Once the change is deemed
+acceptable, the maintainer will merge your change into the appropriate branch of
+the repository.
+
+To make it easier for the maintainer to review your changes, we highly recommend
+that you give a clear and concise description of intent (linking to any issues
+that are resolved by the change), as well as the inclusion of unit tests, which
+contribute to a high level of confidence that this change does not break any
+existing behaviours.  We also recommend breaking up separate changes into
+separate PRs, rather than submitting one big PR with several unrelated changes.
+
+If your change is still a work in progress, please mark the PR as "draft".  This
+will prevent other contributors from receiving an email every time you push a
+new change to your branch.  Draft PRs can also be used to invite early feedback
+on your change, especially if you are uncertain about whether you are going in
+the right direction.
+
+The code in the Panda3D repository is copyrighted to Carnegie Mellon University
+and licensed under the Modified BSD License.  By submitting your changes, you
+accept that your code becomes placed under the same license.  Except in specific
+agreed-upon cases, we do not accept code contributions under alternate licenses.

+ 6 - 6
README.md

@@ -24,7 +24,7 @@ Installing Panda3D
 ==================
 
 The latest Panda3D SDK can be downloaded from
-[this page](https://www.panda3d.org/download/sdk-1-10-6/).
+[this page](https://www.panda3d.org/download/sdk-1-10-7/).
 If you are familiar with installing Python packages, you can use
 the following command:
 
@@ -64,8 +64,8 @@ depending on whether you are on a 32-bit or 64-bit system, or you can
 [click here](https://github.com/rdb/panda3d-thirdparty) for instructions on
 building them from source.
 
-- https://www.panda3d.org/download/panda3d-1.10.6/panda3d-1.10.6-tools-win64.zip
-- https://www.panda3d.org/download/panda3d-1.10.6/panda3d-1.10.6-tools-win32.zip
+- https://www.panda3d.org/download/panda3d-1.10.7/panda3d-1.10.7-tools-win64.zip
+- https://www.panda3d.org/download/panda3d-1.10.7/panda3d-1.10.7-tools-win32.zip
 
 After acquiring these dependencies, you can build Panda3D from the command
 prompt using the following command.  Change the `--msvc-version` option based
@@ -100,7 +100,7 @@ for you to install, depending on your distribution).
 The following command illustrates how to build Panda3D with some common
 options:
 ```bash
-python makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-gles2 --no-opencv
+python3 makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-gles2 --no-opencv
 ```
 
 You will probably see some warnings saying that it's unable to find several
@@ -113,7 +113,7 @@ If you are on Ubuntu, this command should cover the most frequently
 used third-party packages:
 
 ```bash
-sudo apt-get install build-essential pkg-config fakeroot python-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev libassimp-dev libopenexr-dev
+sudo apt-get install build-essential pkg-config fakeroot python3-dev libpng-dev libjpeg-dev libtiff-dev zlib1g-dev libssl-dev libx11-dev libgl1-mesa-dev libxrandr-dev libxxf86dga-dev libxcursor-dev bison flex libfreetype6-dev libvorbis-dev libeigen3-dev libopenal-dev libode-dev libbullet-dev nvidia-cg-toolkit libgtk2.0-dev libassimp-dev libopenexr-dev
 ```
 
 Once Panda3D has built, you can either install the .deb or .rpm package that
@@ -136,7 +136,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.6/panda3d-1.10.6-tools-mac.tar.gz).
+compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.7/panda3d-1.10.7-tools-mac.tar.gz).
 
 After placing the thirdparty directory inside the panda3d source directory,
 you may build Panda3D using a command like the following:

+ 50 - 0
cmake/macros/PerConfigOption.cmake

@@ -0,0 +1,50 @@
+# Filename: PerConfigOption.cmake
+#
+# This contains a convenience function for defining per-config options.
+# In single-config generators, it will set the option based on the defined
+# CMAKE_BUILD_TYPE.  In multi-config generators, it will create separate
+# options, one per config.
+#
+# Function: per_config_option
+# Usage:
+#   option(name "help string" [Config1] [Config2] [...ConfigN])
+#
+# Example:
+#   per_config_option(DO_DEBUGGING "Enables debugging." Debug Standard)
+
+set(_PER_CONFIG_OPTIONS CACHE INTERNAL "Internal variable")
+
+function(per_config_option name help)
+  set(_configs ${ARGN})
+
+  # In single-config generatotrs, we simply create one config.
+  if(NOT IS_MULTICONFIG)
+    list(FIND _configs "${CMAKE_BUILD_TYPE}" _index)
+    if(${_index} GREATER -1)
+      option("${name}" "${help}" ON)
+    else()
+      option("${name}" "${help}" OFF)
+    endif()
+
+  elseif(DEFINED "${name}")
+    # It's been explicitly defined, so that makes it not a multi-configuration
+    # variable anymore.
+    option("${name}" "${help}")
+    return()
+
+  else()
+    foreach(_config ${CMAKE_CONFIGURATION_TYPES})
+      string(TOUPPER "${_config}" _config_upper)
+      list(FIND _configs "${_config}" _index)
+      if(${_index} GREATER -1)
+        option("${name}_${_config_upper}" "${help}" ON)
+      else()
+        option("${name}_${_config_upper}" "${help}" OFF)
+      endif()
+    endforeach()
+
+  endif()
+
+  list(APPEND _PER_CONFIG_OPTIONS "${name}")
+  set(_PER_CONFIG_OPTIONS "${_PER_CONFIG_OPTIONS}" CACHE INTERNAL "Internal variable")
+endfunction(per_config_option)

+ 7 - 0
cmake/templates/METADATA.in

@@ -0,0 +1,7 @@
+Metadata-Version: 2.0
+Name: Panda3D
+Version: ${PROJECT_VERSION}
+License: BSD
+Home-page: https://www.panda3d.org/
+Author: Panda3D Team
+Author-email: [email protected]

+ 7 - 0
contrib/src/contribbase/contribsymbols.h

@@ -29,4 +29,11 @@
   #define EXPTP_PANDAAI IMPORT_TEMPL
 #endif
 
+#ifdef BUILDING_PANDASPEEDTREE
+  #define EXPCL_PANDASPEEDTREE EXPORT_CLASS
+  #define EXPTP_PANDASPEEDTREE EXPORT_TEMPL
+#else
+  #define EXPCL_PANDASPEEDTREE IMPORT_CLASS
+  #define EXPTP_PANDASPEEDTREE IMPORT_TEMPL
+#endif
 #endif

+ 21 - 21
contrib/src/rplight/rpLight.I

@@ -148,7 +148,7 @@ inline void RPLight::assign_slot(int slot) {
  *   changed. This will cause all shadow sources to be updated, emitting a
  *   shadow update. Be careful when calling this method if you don't want all
  *   sources to get updated. If you only have to invalidate a single shadow source,
- *   use get_shadow_source(n)->set_needs_update(true).
+ *   use `get_shadow_source(n)->set_needs_update(true)`.
  */
 inline void RPLight::invalidate_shadows() {
   for (size_t i = 0; i < _shadow_sources.size(); ++i) {
@@ -296,14 +296,14 @@ inline bool RPLight::get_casts_shadows() const {
 }
 
 /**
- * @brief Sets the lights shadow map resolution
- * @details This sets the lights shadow map resolution. This has no effect
+ * @brief Sets the light's shadow map resolution
+ * @details This sets the light's shadow map resolution. This has no effect
  *   when the light is not told to cast shadows (Use RPLight::set_casts_shadows).
  *
- *   When calling this on a light with multiple shadow sources (e.g. PointLight),
- *   this controls the resolution of each source. If the light has 6 shadow sources,
- *   and you use a resolution of 512x512, the lights shadow map will occur a
- *   space of 6 * 512x512 maps in the shadow atlas.
+ *   When calling this on a light with multiple shadow sources (e.g.
+ *   RPPointLight), this controls the resolution of each source. If the light
+ *   has 6 shadow sources, and you use a resolution of 512x512, the light's
+ *   shadow map will occupy a space of 6 * 512x512 maps in the shadow atlas.
  *
  * @param resolution Resolution of the shadow map in pixels
  */
@@ -326,14 +326,14 @@ inline size_t RPLight::get_shadow_map_resolution() const {
 }
 
 /**
- * @brief Sets the ies profile
+ * @brief Sets the IES profile
  * @details This sets the ies profile of the light. The parameter should be a
  *   handle previously returned by RenderPipeline.load_ies_profile. Using a
  *   value of -1 indicates no ies profile.
  *
- *   Notice that for ies profiles which cover a whole range, you should use
- *   PointLights, whereas for ies profiles which only cover the lower hemisphere
- *   you should use SpotLights for the best performance.
+ *   Notice that for IES profiles which cover a whole range, you should use an
+ *   RPPointLight, whereas for ies profiles which only cover the lower
+ *   hemisphere you should use an RPSpotLight for the best performance.
  *
  * @param profile IES Profile handle
  */
@@ -343,8 +343,8 @@ inline void RPLight::set_ies_profile(int profile) {
 }
 
 /**
- * @brief Returns the lights ies profile
- * @details This returns the ies profile of a light, previously set with
+ * @brief Returns the light's IES profile
+ * @details This returns the IES profile of a light, previously set with
  *   RPLight::set_ies_profile. In case no ies profile was set, returns -1.
  *
  * @return IES Profile handle
@@ -354,20 +354,20 @@ inline int RPLight::get_ies_profile() const {
 }
 
 /**
- * @brief Returns whether the light has an ies profile assigned
- * @details This returns whether the light has an ies profile assigned,
+ * @brief Returns whether the light has an IES profile assigned
+ * @details This returns whether the light has an IES profile assigned,
  *   previously done with RPLight::set_ies_profile.
  *
- * @return true if the light has an ies profile assigned, false otherwise
+ * @return true if the light has an IES profile assigned, false otherwise
  */
 inline bool RPLight::has_ies_profile() const {
   return _ies_profile >= 0;
 }
 
 /**
- * @brief Clears the ies profile
- * @details This clears the ies profile of the light, telling it to no longer
- *   use an ies profile, and instead use the default attenuation.
+ * @brief Clears the IES profile
+ * @details This clears the IES profile of the light, telling it to no longer
+ *   use an IES profile, and instead use the default attenuation.
  */
 inline void RPLight::clear_ies_profile() {
   set_ies_profile(-1);
@@ -377,7 +377,7 @@ inline void RPLight::clear_ies_profile() {
  * @brief Sets the near plane of the light
  * @details This sets the near plane of all shadow sources of the light. It has
  *   no effects if the light does not cast shadows. This prevents artifacts from
- *   objects near to the light. It behaves like Lens::set_near_plane.
+ *   objects near to the light. It behaves like Lens::set_near().
  *
  *   It can also help increasing shadow map precision, low near planes will
  *   cause the precision to suffer. Try setting the near plane as big as possible.
@@ -394,7 +394,7 @@ inline void RPLight::set_near_plane(float near_plane) {
 
 /**
  * @brief Returns the near plane of the light
- * @details This returns the lights near plane, previously set with
+ * @details This returns the light's near plane, previously set with
  *   RPLight::set_near_plane. If the light does not cast shadows, this value
  *   is meaningless.
  *

+ 0 - 0
panda/src/speedtree/config_speedtree.cxx → contrib/src/speedtree/config_speedtree.cxx


+ 1 - 1
panda/src/speedtree/config_speedtree.h → contrib/src/speedtree/config_speedtree.h

@@ -14,7 +14,7 @@
 #ifndef CONFIG_SPEEDTREE_H
 #define CONFIG_SPEEDTREE_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 #include "notifyCategoryProxy.h"
 #include "configVariableBool.h"
 #include "configVariableDouble.h"

+ 0 - 0
panda/src/speedtree/loaderFileTypeSrt.cxx → contrib/src/speedtree/loaderFileTypeSrt.cxx


+ 1 - 1
panda/src/speedtree/loaderFileTypeSrt.h → contrib/src/speedtree/loaderFileTypeSrt.h

@@ -14,7 +14,7 @@
 #ifndef LOADERFILETYPESRT_H
 #define LOADERFILETYPESRT_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 
 #include "loaderFileType.h"
 

+ 0 - 0
panda/src/speedtree/loaderFileTypeStf.cxx → contrib/src/speedtree/loaderFileTypeStf.cxx


+ 1 - 1
panda/src/speedtree/loaderFileTypeStf.h → contrib/src/speedtree/loaderFileTypeStf.h

@@ -14,7 +14,7 @@
 #ifndef LOADERFILETYPESTF_H
 #define LOADERFILETYPESTF_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 
 #include "loaderFileType.h"
 

+ 0 - 0
panda/src/speedtree/pandaspeedtree_composite1.cxx → contrib/src/speedtree/pandaspeedtree_composite1.cxx


+ 0 - 0
panda/src/speedtree/speedTreeNode.I → contrib/src/speedtree/speedTreeNode.I


+ 1 - 1
panda/src/speedtree/speedTreeNode.cxx → contrib/src/speedtree/speedTreeNode.cxx

@@ -11,7 +11,7 @@
  * @date 2009-03-13
  */
 
-#include "pandabase.h"
+#include "contribbase.h"
 #include "speedTreeNode.h"
 #include "stBasicTerrain.h"
 #include "virtualFileSystem.h"

+ 1 - 1
panda/src/speedtree/speedTreeNode.h → contrib/src/speedtree/speedTreeNode.h

@@ -14,7 +14,7 @@
 #ifndef SPEEDTREENODE_H
 #define SPEEDTREENODE_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 #include "pandaNode.h"
 #include "pointerTo.h"
 #include "stTree.h"

+ 0 - 0
panda/src/speedtree/speedtree_api.cxx → contrib/src/speedtree/speedtree_api.cxx


+ 0 - 0
panda/src/speedtree/speedtree_api.h → contrib/src/speedtree/speedtree_api.h


+ 0 - 0
panda/src/speedtree/stBasicTerrain.I → contrib/src/speedtree/stBasicTerrain.I


+ 0 - 0
panda/src/speedtree/stBasicTerrain.cxx → contrib/src/speedtree/stBasicTerrain.cxx


+ 1 - 1
panda/src/speedtree/stBasicTerrain.h → contrib/src/speedtree/stBasicTerrain.h

@@ -14,7 +14,7 @@
 #ifndef STBASICTERRAIN_H
 #define STBASICTERRAIN_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 #include "stTerrain.h"
 #include "luse.h"
 #include "pvector.h"

+ 0 - 0
panda/src/speedtree/stTerrain.I → contrib/src/speedtree/stTerrain.I


+ 0 - 0
panda/src/speedtree/stTerrain.cxx → contrib/src/speedtree/stTerrain.cxx


+ 1 - 1
panda/src/speedtree/stTerrain.h → contrib/src/speedtree/stTerrain.h

@@ -14,7 +14,7 @@
 #ifndef STTERRAIN_H
 #define STTERRAIN_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 #include "typedReferenceCount.h"
 #include "namable.h"
 #include "geomVertexData.h"

+ 0 - 0
panda/src/speedtree/stTransform.I → contrib/src/speedtree/stTransform.I


+ 0 - 0
panda/src/speedtree/stTransform.cxx → contrib/src/speedtree/stTransform.cxx


+ 1 - 1
panda/src/speedtree/stTransform.h → contrib/src/speedtree/stTransform.h

@@ -14,7 +14,7 @@
 #ifndef STTRANSFORM_H
 #define STTRANSFORM_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 #include "transformState.h"
 #include "speedtree_api.h"
 #include "deg_2_rad.h"

+ 0 - 0
panda/src/speedtree/stTree.I → contrib/src/speedtree/stTree.I


+ 0 - 0
panda/src/speedtree/stTree.cxx → contrib/src/speedtree/stTree.cxx


+ 1 - 1
panda/src/speedtree/stTree.h → contrib/src/speedtree/stTree.h

@@ -14,7 +14,7 @@
 #ifndef STTREE_H
 #define STTREE_H
 
-#include "pandabase.h"
+#include "contribbase.h"
 #include "typedReferenceCount.h"
 #include "namable.h"
 #include "speedtree_api.h"

+ 15 - 1
direct/CMakeLists.txt

@@ -53,7 +53,8 @@ if(HAVE_PYTHON)
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pandac/PandaModules.py"
     "\"This module is deprecated.  Import from panda3d.core and other panda3d.* modules instead.\"
 
-print(\"Warning: pandac.PandaModules is deprecated, import from panda3d.core instead\")\n")
+if __debug__:
+    print(\"Warning: pandac.PandaModules is deprecated, import from panda3d.core instead\")\n")
 
   foreach(module ${ALL_INTERROGATE_MODULES})
     string(REGEX REPLACE "^.*\\." "" module_name "${module}")
@@ -66,6 +67,19 @@ except ImportError as err:
 ")
   endforeach()
 
+  file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pandac/PandaModules.py"
+    "from direct.showbase import DConfig
+
+def get_config_showbase():
+    return DConfig
+
+def get_config_express():
+    return DConfig
+
+getConfigShowbase = get_config_showbase
+getConfigExpress = get_config_express
+")
+
   # Now install ourselves:
   install_python_package(pandac SOURCE "${CMAKE_CURRENT_BINARY_DIR}/pandac" LIB COMPONENT Direct)
 endif()

+ 5 - 1
direct/src/actor/Actor.py

@@ -1,4 +1,8 @@
-"""Actor module: contains the Actor class"""
+"""Actor module: contains the Actor class.
+
+See the :ref:`models-and-actors` page in the Programming Guide to learn
+more about loading models and animated actors.
+"""
 
 __all__ = ['Actor']
 

+ 3 - 0
direct/src/actor/__init__.py

@@ -4,4 +4,7 @@ distributed variant thereof.  Actor is a high-level interface around
 the lower-level :class:`panda3d.core.Character` implementation.
 It loads and controls an animated character and manages the animations
 playing on it.
+
+See the :ref:`models-and-actors` page in the Programming Guide to learn
+more about loading models and animated actors.
 """

+ 3 - 3
direct/src/dcparser/dcClass.cxx

@@ -77,7 +77,9 @@ DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) :
   _number = -1;
   _constructor = nullptr;
 
+#ifdef WITHIN_PANDA
   _python_class_defs = nullptr;
+#endif
 }
 
 /**
@@ -85,9 +87,7 @@ DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) :
  */
 DCClass::
 ~DCClass() {
-  if (_constructor != nullptr) {
-    delete _constructor;
-  }
+  delete _constructor;
 
   Fields::iterator fi;
   for (fi = _fields.begin(); fi != _fields.end(); ++fi) {

+ 3 - 2
direct/src/dcparser/dcClass.h

@@ -172,6 +172,9 @@ private:
   typedef pmap<int, DCField *> FieldsByIndex;
   FieldsByIndex _fields_by_index;
 
+  friend class DCField;
+
+#ifdef WITHIN_PANDA
   // See pandaNode.h for an explanation of this trick
   class PythonClassDefs : public ReferenceCount {
   public:
@@ -179,8 +182,6 @@ private:
   };
   PT(PythonClassDefs) _python_class_defs;
 
-  friend class DCField;
-#ifdef WITHIN_PANDA
   friend class Extension<DCClass>;
 #endif
 };

+ 3 - 0
direct/src/dcparser/dcLexer.cxx.prebuilt

@@ -599,7 +599,10 @@ char *dcyytext;
 #include "dcParser.h"
 #include "dcFile.h"
 #include "dcindent.h"
+
+#ifdef WITHIN_PANDA
 #include "pstrtod.h"
+#endif
 
 
 static int yyinput(void);        // declared by flex.

+ 3 - 1
direct/src/dcparser/dcLexer.lxx

@@ -11,8 +11,10 @@
 #include "dcParser.h"
 #include "dcFile.h"
 #include "dcindent.h"
-#include "pstrtod.h"
 
+#ifdef WITHIN_PANDA
+#include "pstrtod.h"
+#endif
 
 static int yyinput(void);        // declared by flex.
 extern "C" int dcyywrap();

+ 5 - 3
direct/src/dcparser/dcPacker.I

@@ -1124,7 +1124,9 @@ operator new(size_t size) {
  */
 INLINE void DCPacker::StackElement::
 operator delete(void *ptr) {
-  StackElement *obj = (StackElement *)ptr;
-  obj->_next = _deleted_chain;
-  _deleted_chain = obj;
+  if (ptr != nullptr) {
+    StackElement *obj = (StackElement *)ptr;
+    obj->_next = _deleted_chain;
+    _deleted_chain = obj;
+  }
 }

+ 1 - 1
direct/src/dcparser/dcPacker.cxx

@@ -769,7 +769,7 @@ enquote_string(ostream &out, char quote_mark, const string &str) {
     if ((*pi) == quote_mark || (*pi) == '\\') {
       out << '\\' << (*pi);
 
-    } else if (!isprint(*pi)) {
+    } else if (!isprint(*pi) || (*pi) == '\t') {
       char buffer[10];
       sprintf(buffer, "%02x", (unsigned char)(*pi));
       out << "\\x" << buffer;

+ 1 - 3
direct/src/dcparser/dcPackerCatalog.cxx

@@ -44,9 +44,7 @@ DCPackerCatalog(const DCPackerCatalog &copy) :
  */
 DCPackerCatalog::
 ~DCPackerCatalog() {
-  if (_live_catalog != nullptr) {
-    delete _live_catalog;
-  }
+  delete _live_catalog;
 
   SwitchCatalogs::iterator si;
   for (si = _switch_catalogs.begin(); si != _switch_catalogs.end(); ++si) {

+ 1 - 3
direct/src/dcparser/dcPackerInterface.cxx

@@ -60,9 +60,7 @@ DCPackerInterface(const DCPackerInterface &copy) :
  */
 DCPackerInterface::
 ~DCPackerInterface() {
-  if (_catalog != nullptr) {
-    delete _catalog;
-  }
+  delete _catalog;
 }
 
 /**

+ 3 - 9
direct/src/dcparser/dcSwitch.cxx

@@ -42,21 +42,15 @@ DCSwitch::
   nassertv(_key_parameter != nullptr);
   delete _key_parameter;
 
-  Cases::iterator ci;
-  for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
-    SwitchCase *dcase = (*ci);
+  for (SwitchCase *dcase : _cases) {
     delete dcase;
   }
 
-  CaseFields::iterator fi;
-  for (fi = _case_fields.begin(); fi != _case_fields.end(); ++fi) {
-    SwitchFields *fields = (*fi);
+  for (SwitchFields *fields : _case_fields) {
     delete fields;
   }
 
-  Fields::iterator ni;
-  for (ni = _nested_fields.begin(); ni != _nested_fields.end(); ++ni) {
-    DCField *field = (*ni);
+  for (DCField *field : _nested_fields) {
     delete field;
   }
 }

+ 2 - 0
direct/src/dcparser/dcbase.h

@@ -70,6 +70,7 @@
 #define BEGIN_PUBLISH
 #define END_PUBLISH
 #define BLOCKING
+#define EXTENSION(x)
 
 // These control the declspec(dllexport/dllimport) on Windows.  When compiling
 // outside of Panda, we assume we aren't part of a DLL.
@@ -100,6 +101,7 @@ typedef std::string Filename;
 #define pmap std::map
 #define pset std::set
 #define vector_uchar std::vector<unsigned char>
+#define patof(x) atof(x)
 
 #include <stdint.h>
 #include <string.h>

+ 1 - 1
direct/src/directbase/DirectStart.py

@@ -4,7 +4,7 @@ opening a graphical window and setting up the scene graph.
 This example demonstrates its use:
 
    import direct.directbase.DirectStart
-   run()
+   base.run()
 
 While it may be considered useful for quick prototyping in the interactive
 Python shell, using it in applications is not considered good style.

+ 1 - 0
direct/src/directscripts/Doxyfile.cxx

@@ -789,6 +789,7 @@ RECURSIVE              = YES
 EXCLUDE                = dtool/src/parser-inc \
                          dtool/src/cppparser \
                          dtool/src/interrogate \
+                         direct/src/directscripts \
                          direct/src/plugin \
                          direct/src/plugin_standalone \
                          direct/src/plugin_npapi \

+ 1 - 1
direct/src/directtools/DirectManipulation.py

@@ -1066,7 +1066,7 @@ class ObjectHandles(NodePath, DirectObject):
         # Load up object handles model and assign it to self
         self.assign(loader.loadModel('models/misc/objectHandles'))
         self.setName(name)
-        self.scalingNode = NodePath(self)
+        self.scalingNode = self.getChild(0)
         self.scalingNode.setName('ohScalingNode')
         self.ohScalingFactor = 1.0
         self.directScalingFactor = 1.0

+ 0 - 10
direct/src/directutil/DirectMySQLdb.py

@@ -1,10 +0,0 @@
-from MySQLdb import *
-
-### DCR: from MySQLdb __init__.py
-def Connect(*args, **kwargs):
-    """Factory function for connections.Connection."""
-    ### DCR: use DirectMySQLdbConnection to prevent memory leaks
-    from direct.directutil.DirectMySQLdbConnection import DirectMySQLdbConnection
-    return DirectMySQLdbConnection(*args, **kwargs)
-
-connect = Connection = Connect

+ 0 - 117
direct/src/directutil/DirectMySQLdbConnection.py

@@ -1,117 +0,0 @@
-import MySQLdb
-from MySQLdb.connections import *
-
-class DirectMySQLdbConnection(Connection):
-    ### DCR: from MySQLdb connections.py Connection.__init__
-    def __init__(self, *args, **kwargs):
-        ### DCR: fixed up relative imports
-        from MySQLdb.constants import CLIENT, FIELD_TYPE
-        from MySQLdb.converters import conversions
-        from weakref import proxy, WeakValueDictionary
-
-        import types
-
-        kwargs2 = kwargs.copy()
-
-        conv = kwargs.get('conv', conversions)
-
-        kwargs2['conv'] = dict([ (k, v) for k, v in conv.items()
-                                 if type(k) is int ])
-
-        self.cursorclass = kwargs2.pop('cursorclass', self.default_cursor)
-        charset = kwargs2.pop('charset', '')
-
-        if charset:
-            use_unicode = True
-        else:
-            use_unicode = False
-
-        use_unicode = kwargs2.pop('use_unicode', use_unicode)
-        sql_mode = kwargs2.pop('sql_mode', '')
-
-        client_flag = kwargs.get('client_flag', 0)
-        ### DCR: fixed up module reference
-        client_version = tuple([ int(n) for n in MySQLdb.connections._mysql.get_client_info().split('.')[:2] ])
-        if client_version >= (4, 1):
-            client_flag |= CLIENT.MULTI_STATEMENTS
-        if client_version >= (5, 0):
-            client_flag |= CLIENT.MULTI_RESULTS
-
-        kwargs2['client_flag'] = client_flag
-
-        ### DCR: skip over the Connection __init__
-        #super(Connection, self).__init__(*args, **kwargs2)
-        MySQLdb._mysql.connection.__init__(self, *args, **kwargs2)
-
-        self.encoders = dict([ (k, v) for k, v in conv.items()
-                               if type(k) is not int ])
-
-        self._server_version = tuple([ int(n) for n in self.get_server_info().split('.')[:2] ])
-
-        db = proxy(self)
-        ### DCR: these functions create memory leaks with gc.DEBUG_SAVEALL turned on
-        """
-        def _get_string_literal():
-            def string_literal(obj, dummy=None):
-                return db.string_literal(obj)
-            return string_literal
-
-        def _get_unicode_literal():
-            def unicode_literal(u, dummy=None):
-                return db.literal(u.encode(unicode_literal.charset))
-            return unicode_literal
-
-        def _get_string_decoder():
-            def string_decoder(s):
-                return s.decode(string_decoder.charset)
-            return string_decoder
-        """
-
-        ### DCR: use methods rather than inline-defined functions to prevent memory leaks
-        string_literal = self._get_string_literal(db)
-        self.unicode_literal = unicode_literal = self._get_unicode_literal(db)
-        self.string_decoder = string_decoder = self._get_string_decoder()
-        if not charset:
-            charset = self.character_set_name()
-        self.set_character_set(charset)
-
-        if sql_mode:
-            self.set_sql_mode(sql_mode)
-
-        if use_unicode:
-            self.converter[FIELD_TYPE.STRING].insert(-1, (None, string_decoder))
-            self.converter[FIELD_TYPE.VAR_STRING].insert(-1, (None, string_decoder))
-            self.converter[FIELD_TYPE.BLOB].insert(-1, (None, string_decoder))
-
-        self.encoders[types.StringType] = string_literal
-        self.encoders[types.UnicodeType] = unicode_literal
-        self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
-        if self._transactional:
-            # PEP-249 requires autocommit to be initially off
-            self.autocommit(False)
-        self.messages = []
-
-    ### DCR: make inline-defined functions into member methods to avoid garbage
-    def _string_literal(self, db, obj, dummy=None):
-        return db.string_literal(obj)
-    def _get_string_literal(self, db):
-        return Functor(self._string_literal, db)
-
-    def _unicode_literal(self, db, u, dummy=None):
-        return db.literal(u.encode(unicode_literal.charset))
-    def _get_unicode_literal(self, db):
-        return Functor(self._unicode_literal, db)
-
-    def _string_decoder(self, s):
-        return s.decode(string_decoder.charset)
-    def _get_string_decoder(self):
-        # make it into a Functor since MySQLdb.connections.Connection wants to set
-        # attributes on its string_decoder
-        return Functor(self._string_decoder)
-
-    def close(self):
-        Connection.close(self)
-        # break garbage cycles
-        self.unicode_literal = None
-        self.string_decoder = None
-        self.encoders = None

+ 138 - 16
direct/src/dist/FreezeTool.py

@@ -639,6 +639,51 @@ okMissing = [
     'direct.extensions_native.extensions_darwin',
     ]
 
+# Since around macOS 10.15, Apple's codesigning process has become more strict.
+# Appending data to the end of a Mach-O binary is now explicitly forbidden. The
+# solution is to embed our own segment into the binary so it can be properly
+# signed.
+mach_header_64_layout = '<IIIIIIII'
+
+# Each load command is guaranteed to start with the command identifier and
+# command size. We'll call this the "lc header".
+lc_header_layout = '<II'
+
+# Each Mach-O segment is made up of sections. We need to change both the segment
+# and section information, so we'll need to know the layout of a section as
+# well.
+section64_header_layout = '<16s16sQQIIIIIIII'
+
+# These are all of the load commands we'll need to modify parts of.
+LC_SEGMENT_64 = 0x19
+LC_DYLD_INFO_ONLY = 0x80000022
+LC_SYMTAB = 0x02
+LC_DYSYMTAB = 0x0B
+LC_FUNCTION_STARTS = 0x26
+LC_DATA_IN_CODE = 0x29
+
+lc_layouts = {
+    LC_SEGMENT_64: '<II16sQQQQIIII',
+    LC_DYLD_INFO_ONLY: '<IIIIIIIIIIII',
+    LC_SYMTAB: '<IIIIII',
+    LC_DYSYMTAB: '<IIIIIIIIIIIIIIIIIIII',
+    LC_FUNCTION_STARTS: '<IIII',
+    LC_DATA_IN_CODE: '<IIII',
+}
+
+# All of our modifications involve sliding some offsets, since we need to insert
+# our data in the middle of the binary (we can't just put the data at the end
+# since __LINKEDIT must be the last segment).
+lc_indices_to_slide = {
+    b'__PANDA': [4, 6],
+    b'__LINKEDIT': [3, 5],
+    LC_DYLD_INFO_ONLY: [2, 4, 8, 10],
+    LC_SYMTAB: [2, 4],
+    LC_DYSYMTAB: [14],
+    LC_FUNCTION_STARTS: [2],
+    LC_DATA_IN_CODE: [2],
+}
+
 class Freezer:
     class ModuleDef:
         def __init__(self, moduleName, filename = None,
@@ -1288,7 +1333,8 @@ class Freezer:
         for moduleName, module in list(self.mf.modules.items()):
             if module.__code__:
                 origPathname = module.__code__.co_filename
-                replace_paths.append((origPathname, moduleName))
+                if origPathname:
+                    replace_paths.append((origPathname, moduleName))
         self.mf.replace_paths = replace_paths
 
         # Now that we have built up the replacement mapping, go back
@@ -1676,6 +1722,8 @@ class Freezer:
 
     def generateRuntimeFromStub(self, target, stub_file, use_console, fields={},
                                 log_append=False):
+        self.__replacePaths()
+
         # We must have a __main__ module to make an exe file.
         if not self.__writingModule('__main__'):
             message = "Can't generate an executable without a __main__ module."
@@ -1799,21 +1847,36 @@ class Freezer:
             # Align to page size, so that it can be mmapped.
             blob_align = 4096
 
-        # Add padding before the blob if necessary.
-        blob_offset = len(stub_data)
-        if (blob_offset & (blob_align - 1)) != 0:
-            pad = (blob_align - (blob_offset & (blob_align - 1)))
-            stub_data += (b'\0' * pad)
-            blob_offset += pad
-        assert (blob_offset % blob_align) == 0
-        assert blob_offset == len(stub_data)
-
         # Also determine the total blob size now.  Add padding to the end.
         blob_size = pool_offset + len(pool)
-        if blob_size & 31 != 0:
-            pad = (32 - (blob_size & 31))
+        if blob_size & (blob_align - 1) != 0:
+            pad = (blob_align - (blob_size & (blob_align - 1)))
             blob_size += pad
 
+        # TODO: Support creating custom sections in universal binaries.
+        append_blob = True
+        if self.platform.startswith('macosx') and len(bitnesses) == 1:
+            # If our deploy-stub has a __PANDA segment, we know we're meant to
+            # put our blob there rather than attach it to the end.
+            load_commands = self._parse_macho_load_commands(stub_data)
+            if b'__PANDA' in load_commands.keys():
+                append_blob = False
+
+        if self.platform.startswith("macosx") and not append_blob:
+            # Take this time to shift any Mach-O structures around to fit our
+            # blob. We don't need to worry about aligning the offset since the
+            # compiler already took care of that when creating the segment.
+            blob_offset = self._shift_macho_structures(stub_data, load_commands, blob_size)
+        else:
+            # Add padding before the blob if necessary.
+            blob_offset = len(stub_data)
+            if (blob_offset & (blob_align - 1)) != 0:
+                pad = (blob_align - (blob_offset & (blob_align - 1)))
+                stub_data += (b'\0' * pad)
+                blob_offset += pad
+            assert (blob_offset % blob_align) == 0
+            assert blob_offset == len(stub_data)
+
         # Calculate the offsets for the variables.  These are pointers,
         # relative to the beginning of the blob.
         field_offsets = {}
@@ -1893,9 +1956,13 @@ class Freezer:
             blob += struct.pack('<Q', blob_offset)
 
         with open(target, 'wb') as f:
-            f.write(stub_data)
-            assert f.tell() == blob_offset
-            f.write(blob)
+            if append_blob:
+                f.write(stub_data)
+                assert f.tell() == blob_offset
+                f.write(blob)
+            else:
+                stub_data[blob_offset:blob_offset + blob_size] = blob
+                f.write(stub_data)
 
         os.chmod(target, 0o755)
         return target
@@ -2153,7 +2220,9 @@ class Freezer:
                     symoff += nlist_size
                     name = strings[strx : strings.find(b'\0', strx)]
 
-                    if name == b'_' + symbol_name:
+                    # If the entry's type has any bits at 0xe0 set, it's a debug
+                    # symbol, and will point us to the wrong place.
+                    if name == b'_' + symbol_name and type & 0xe0 == 0:
                         # Find out in which segment this is.
                         for vmaddr, vmsize, fileoff in segments:
                             # Is it defined in this segment?
@@ -2163,6 +2232,59 @@ class Freezer:
                                 return fileoff + rel
                         print("Could not find memory address for symbol %s" % (symbol_name))
 
+    def _parse_macho_load_commands(self, macho_data):
+        """Returns the list of load commands from macho_data."""
+        mach_header_64 = list(
+            struct.unpack_from(mach_header_64_layout, macho_data, 0))
+
+        num_load_commands = mach_header_64[4]
+
+        load_commands = {}
+
+        curr_lc_offset = struct.calcsize(mach_header_64_layout)
+        for i in range(num_load_commands):
+            lc = struct.unpack_from(lc_header_layout, macho_data, curr_lc_offset)
+            layout = lc_layouts.get(lc[0])
+            if layout:
+                # Make it a list since we want to mutate it.
+                lc = list(struct.unpack_from(layout, macho_data, curr_lc_offset))
+
+                if lc[0] == LC_SEGMENT_64:
+                    stripped_name = lc[2].rstrip(b'\0')
+                    if stripped_name in [b'__PANDA', b'__LINKEDIT']:
+                        load_commands[stripped_name] = (curr_lc_offset, lc)
+                else:
+                    load_commands[lc[0]] = (curr_lc_offset, lc)
+
+            curr_lc_offset += lc[1]
+
+        return load_commands
+
+    def _shift_macho_structures(self, macho_data, load_commands, blob_size):
+        """Given the stub and the size of our blob, make room for it and edit
+        all of the necessary structures to keep the binary valid. Returns the
+        offset where the blob should be placed."""
+
+        for lc_key in load_commands.keys():
+            for index in lc_indices_to_slide[lc_key]:
+                load_commands[lc_key][1][index] += blob_size
+
+            if lc_key == b'__PANDA':
+                section_header_offset = load_commands[lc_key][0] + struct.calcsize(lc_layouts[LC_SEGMENT_64])
+                section_header = list(struct.unpack_from(section64_header_layout, macho_data, section_header_offset))
+                section_header[3] = blob_size
+                struct.pack_into(section64_header_layout, macho_data, section_header_offset, *section_header)
+
+            layout = LC_SEGMENT_64 if lc_key in [b'__PANDA', b'__LINKEDIT'] else lc_key
+            struct.pack_into(lc_layouts[layout], macho_data, load_commands[lc_key][0], *load_commands[lc_key][1])
+
+        blob_offset = load_commands[b'__PANDA'][1][5]
+
+        # Write in some null bytes until we write in the actual blob.
+        macho_data[blob_offset:blob_offset] = b'\0' * blob_size
+
+        return blob_offset
+
     def makeModuleDef(self, mangledName, code):
         result = ''
         result += 'static unsigned char %s[] = {' % (mangledName)

+ 27 - 13
direct/src/dist/commands.py

@@ -4,8 +4,6 @@ See the :ref:`distribution` section of the programming manual for information
 on how to use these commands.
 """
 
-from __future__ import print_function
-
 import collections
 import os
 import plistlib
@@ -31,9 +29,6 @@ import panda3d.core as p3d
 
 
 if sys.version_info < (3, 0):
-    # Python 3 defines these subtypes of IOError, but Python 2 doesn't.
-    FileNotFoundError = IOError
-
     # Warn the user.  They might be using Python 2 by accident.
     print("=================================================================")
     print("WARNING: You are using Python 2, which has reached the end of its")
@@ -218,6 +213,7 @@ class build_apps(setuptools.Command):
             'dciman32.dll', 'comdlg32.dll', 'comctl32.dll', 'ole32.dll',
             'oleaut32.dll', 'gdiplus.dll', 'winmm.dll', 'iphlpapi.dll',
             'msvcrt.dll', 'kernelbase.dll', 'msimg32.dll', 'msacm32.dll',
+            'setupapi.dll', 'version.dll',
 
             # manylinux1/linux
             'libdl.so.*', 'libstdc++.so.*', 'libm.so.*', 'libgcc_s.so.*',
@@ -235,6 +231,12 @@ class build_apps(setuptools.Command):
             '/usr/lib/libedit.*.dylib',
             '/System/Library/**',
         ]
+
+        if sys.version_info >= (3, 5):
+            # Python 3.5+ requires at least Windows Vista to run anyway, so we
+            # shouldn't warn about DLLs that are shipped with Vista.
+            self.exclude_dependencies += ['bcrypt.dll']
+
         self.package_data_dirs = {}
 
         # We keep track of the zip files we've opened.
@@ -374,12 +376,13 @@ class build_apps(setuptools.Command):
                     os.remove(os.path.join(whldir, whl))
 
         pip_args = [
+            '--disable-pip-version-check',
             'download',
             '-d', whldir,
             '-r', self.requirements_path,
             '--only-binary', ':all:',
             '--platform', platform,
-            '--abi', abi_tag
+            '--abi', abi_tag,
         ]
 
         if self.use_optimized_wheels:
@@ -623,12 +626,16 @@ class build_apps(setuptools.Command):
                     rootdir = wf.split(os.path.sep, 1)[0]
                     search_path.append(os.path.join(whl, rootdir, '.libs'))
 
+                    # Also look for eg. numpy.libs or Pillow.libs in the root
+                    whl_name = os.path.basename(whl).split('-', 1)[0]
+                    search_path.append(os.path.join(whl, whl_name + '.libs'))
+
                     # Also look for more specific per-package cases, defined in
                     # PACKAGE_LIB_DIRS at the top of this file.
-                    whl_name = os.path.basename(whl).split('-', 1)[0]
                     extra_dirs = PACKAGE_LIB_DIRS.get(whl_name, [])
                     for extra_dir in extra_dirs:
                         search_path.append(os.path.join(whl, extra_dir.replace('/', os.path.sep)))
+
             return search_path
 
         def create_runtime(appname, mainscript, use_console):
@@ -1015,7 +1022,10 @@ class build_apps(setuptools.Command):
         source_dir = os.path.dirname(source_path)
         target_dir = os.path.dirname(target_path)
         base = os.path.basename(target_path)
-        self.copy_dependencies(target_path, target_dir, search_path + [source_dir], base)
+
+        if source_dir not in search_path:
+            search_path = search_path + [source_dir]
+        self.copy_dependencies(target_path, target_dir, search_path, base)
 
     def copy_dependencies(self, target_path, target_dir, search_path, referenced_by):
         """ Copies the dependencies of target_path into target_dir. """
@@ -1030,8 +1040,7 @@ class build_apps(setuptools.Command):
             pe = pefile.PEFile()
             pe.read(fp)
             for lib in pe.imports:
-                if not lib.lower().startswith('api-ms-win-'):
-                    deps.append(lib)
+                deps.append(lib)
 
         elif magic == b'\x7FELF':
             # Elf magic.  Used on (among others) Linux and FreeBSD.
@@ -1350,17 +1359,22 @@ class bdist_apps(setuptools.Command):
         nsi.write('Section "" SecCore\n')
         nsi.write('  SetOutPath "$INSTDIR"\n')
         curdir = ""
+        nsi_dir = p3d.Filename.fromOsSpecific(build_cmd.build_base)
+        build_root_dir = p3d.Filename.fromOsSpecific(build_dir)
         for root, dirs, files in os.walk(build_dir):
             for name in files:
                 basefile = p3d.Filename.fromOsSpecific(os.path.join(root, name))
                 file = p3d.Filename(basefile)
                 file.makeAbsolute()
-                file.makeRelativeTo(build_dir)
-                outdir = file.getDirname().replace('/', '\\')
+                file.makeRelativeTo(nsi_dir)
+                outdir = p3d.Filename(basefile)
+                outdir.makeAbsolute()
+                outdir.makeRelativeTo(build_root_dir)
+                outdir = outdir.getDirname().replace('/', '\\')
                 if curdir != outdir:
                     nsi.write('  SetOutPath "$INSTDIR\\%s"\n' % outdir)
                     curdir = outdir
-                nsi.write('  File "%s"\n' % (basefile.toOsSpecific()))
+                nsi.write('  File "%s"\n' % (file.toOsSpecific()))
         nsi.write('  SetOutPath "$INSTDIR"\n')
         nsi.write('  WriteUninstaller "$INSTDIR\\Uninstall.exe"\n')
         nsi.write('  ; Start menu items\n')

+ 1 - 0
direct/src/distributed/ConnectionRepository.py

@@ -260,6 +260,7 @@ class ConnectionRepository(
             searchPath = getModelPath().getValue()
             for dcFileName in dcFileNames:
                 pathname = Filename(dcFileName)
+                vfs = VirtualFileSystem.getGlobalPtr()
                 vfs.resolveFilename(pathname, searchPath)
                 readResult = dcFile.read(pathname)
                 if not readResult:

+ 3 - 2
direct/src/distributed/ServerRepository.py

@@ -225,6 +225,7 @@ class ServerRepository:
             searchPath = getModelPath().getValue()
             for dcFileName in dcFileNames:
                 pathname = Filename(dcFileName)
+                vfs = VirtualFileSystem.getGlobalPtr()
                 vfs.resolveFilename(pathname, searchPath)
                 readResult = dcFile.read(pathname)
                 if not readResult:
@@ -628,7 +629,7 @@ class ServerRepository:
         del self.clientsByConnection[client.connection]
         del self.clientsByDoIdBase[client.doIdBase]
 
-        id = client.doIdBase / self.doIdRange
+        id = client.doIdBase // self.doIdRange
         self.idAllocator.free(id)
 
         self.qcr.removeConnection(client.connection)
@@ -689,7 +690,7 @@ class ServerRepository:
     def clientHardDisconnectTask(self, task):
         """ client did not tell us he was leaving but we lost connection to
         him, so we need to update our data and tell others """
-        for client in self.clientsByConnection.values():
+        for client in list(self.clientsByConnection.values()):
             if not self.qcr.isConnectionOk(client.connection):
                 self.handleClientDisconnect(client)
         return Task.cont

+ 3 - 0
direct/src/distributed/__init__.py

@@ -2,4 +2,7 @@
 This package contains an implementation of the Distributed Networking
 API, a high-level networking system that automatically propagates
 changes made on distributed objects to interested clients.
+
+See the :ref:`distributed-networking` section of the Programming Guide to
+learn more about the distributed networking system.
 """

+ 2 - 5
direct/src/extensions_native/CInterval_extensions.py

@@ -63,12 +63,9 @@ def popupControls(self, tl = None):
         import math
         # Don't use a regular import, to prevent ModuleFinder from picking
         # it up as a dependency when building a .p3d package.
-        import importlib, sys
+        import importlib
         EntryScale = importlib.import_module('direct.tkwidgets.EntryScale')
-        if sys.version_info >= (3, 0):
-            tkinter = importlib.import_module('tkinter')
-        else:
-            tkinter = importlib.import_module('Tkinter')
+        tkinter = importlib.import_module('tkinter')
 
         if tl == None:
             tl = tkinter.Toplevel()

+ 119 - 3
direct/src/filter/CommonFilters.py

@@ -1,7 +1,8 @@
 """
 
 Class CommonFilters implements certain common image
-postprocessing filters.
+postprocessing filters.  See the :ref:`common-image-filters` page for
+more information about how to use these filters.
 
 It is not ideal that these filters are all included in a single
 monolithic module.  Unfortunately, when you want to apply two filters
@@ -27,6 +28,7 @@ from panda3d.core import LVecBase4, LPoint2
 from panda3d.core import Filename
 from panda3d.core import AuxBitplaneAttrib
 from panda3d.core import Texture, Shader, ATSNone
+from panda3d.core import FrameBufferProperties
 import os
 
 CARTOON_BODY="""
@@ -177,7 +179,15 @@ class CommonFilters:
                 self.textures[tex].setWrapU(Texture.WMClamp)
                 self.textures[tex].setWrapV(Texture.WMClamp)
 
-            self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits)
+            fbprops = None
+            clamping = None
+            if "HighDynamicRange" in configuration:
+                fbprops = FrameBufferProperties()
+                fbprops.setFloatColor(True)
+                fbprops.setSrgbColor(False)
+                clamping = False
+
+            self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits, fbprops=fbprops, clamping=clamping)
             if (self.finalQuad == None):
                 self.cleanup()
                 return False
@@ -255,6 +265,17 @@ class CommonFilters:
             texcoordSets = list(enumerate(texcoordPadding.keys()))
 
             text = "//Cg\n"
+            if "HighDynamicRange" in configuration:
+                text += "static const float3x3 aces_input_mat = {\n"
+                text += "  {0.59719, 0.35458, 0.04823},\n"
+                text += "  {0.07600, 0.90834, 0.01566},\n"
+                text += "  {0.02840, 0.13383, 0.83777},\n"
+                text += "};\n"
+                text += "static const float3x3 aces_output_mat = {\n"
+                text += "  { 1.60475, -0.53108, -0.07367},\n"
+                text += "  {-0.10208,  1.10813, -0.00605},\n"
+                text += "  {-0.00327, -0.07276,  1.07602},\n"
+                text += "};\n"
             text += "void vshader(float4 vtx_position : POSITION,\n"
             text += "  out float4 l_position : POSITION,\n"
 
@@ -301,6 +322,10 @@ class CommonFilters:
             if ("VolumetricLighting" in configuration):
                 text += "  uniform float4 k_casterpos,\n"
                 text += "  uniform float4 k_vlparams,\n"
+
+            if ("ExposureAdjust" in configuration):
+                text += "  uniform float k_exposure,\n"
+
             text += "  out float4 o_color : COLOR)\n"
             text += "{\n"
             text += "  o_color = tex2D(k_txcolor, %s);\n" % (texcoords["color"])
@@ -332,6 +357,14 @@ class CommonFilters:
                 text += "  }\n"
                 text += "  o_color += float4(vlcolor * k_vlparams.z, 1);\n"
 
+            if ("ExposureAdjust" in configuration):
+                text += "  o_color.rgb *= k_exposure;\n"
+
+            # With thanks to Stephen Hill!
+            if ("HighDynamicRange" in configuration):
+                text += "  float3 aces_color = mul(aces_input_mat, o_color.rgb);\n"
+                text += "  o_color.rgb = saturate(mul(aces_output_mat, (aces_color * (aces_color + 0.0245786f) - 0.000090537f) / (aces_color * (0.983729f * aces_color + 0.4329510f) + 0.238081f)));\n"
+
             if ("GammaAdjust" in configuration):
                 gamma = configuration["GammaAdjust"]
                 if gamma == 0.5:
@@ -341,6 +374,11 @@ class CommonFilters:
                 elif gamma != 1.0:
                     text += "  o_color.rgb = pow(o_color.rgb, %ff);\n" % (gamma)
 
+            if ("SrgbEncode" in configuration):
+                text += "  o_color.r = (o_color.r < 0.0031308) ? (o_color.r * 12.92) : (1.055 * pow(o_color.r, 0.41666) - 0.055);\n"
+                text += "  o_color.g = (o_color.g < 0.0031308) ? (o_color.g * 12.92) : (1.055 * pow(o_color.g, 0.41666) - 0.055);\n"
+                text += "  o_color.b = (o_color.b < 0.0031308) ? (o_color.b * 12.92) : (1.055 * pow(o_color.b, 0.41666) - 0.055);\n"
+
             if ("Inverted" in configuration):
                 text += "  o_color = float4(1, 1, 1, 1) - o_color;\n"
             text += "}\n"
@@ -386,6 +424,11 @@ class CommonFilters:
                 self.ssao[0].setShaderInput("params1", config.numsamples, -float(config.amount) / config.numsamples, config.radius, 0)
                 self.ssao[0].setShaderInput("params2", config.strength, config.falloff, 0, 0)
 
+        if (changed == "ExposureAdjust") or fullrebuild:
+            if ("ExposureAdjust" in configuration):
+                stops = configuration["ExposureAdjust"]
+                self.finalQuad.setShaderInput("exposure", 2 ** stops)
+
         self.update()
         return True
 
@@ -547,6 +590,73 @@ class CommonFilters:
             return self.reconfigure((old_gamma != 1.0), "GammaAdjust")
         return True
 
+    def setSrgbEncode(self, force=False):
+        """ Applies the inverse sRGB EOTF to the output, unless the window
+        already has an sRGB framebuffer, in which case this filter refuses to
+        apply, to prevent accidental double-application.
+
+        Set the force argument to True to force it to be applied in all cases.
+
+        .. versionadded:: 1.10.7
+        """
+        new_enable = force or not self.manager.win.getFbProperties().getSrgbColor()
+        old_enable = self.configuration.get("SrgbEncode", False)
+        if new_enable and not old_enable:
+            self.configuration["SrgbEncode"] = True
+            return self.reconfigure(True, "SrgbEncode")
+        elif not new_enable and old_enable:
+            del self.configuration["SrgbEncode"]
+        return new_enable
+
+    def delSrgbEncode(self):
+        """ Reverses the effects of setSrgbEncode. """
+        if ("SrgbEncode" in self.configuration):
+            old_enable = self.configuration["SrgbEncode"]
+            del self.configuration["SrgbEncode"]
+            return self.reconfigure(old_enable, "SrgbEncode")
+        return True
+
+    def setHighDynamicRange(self):
+        """ Enables HDR rendering by using a floating-point framebuffer,
+        disabling color clamping on the main scene, and applying a tone map
+        operator (ACES).
+
+        It may also be necessary to use setExposureAdjust to perform exposure
+        compensation on the scene, depending on the lighting intensity.
+
+        .. versionadded:: 1.10.7
+        """
+
+        fullrebuild = (("HighDynamicRange" in self.configuration) is False)
+        self.configuration["HighDynamicRange"] = 1
+        return self.reconfigure(fullrebuild, "HighDynamicRange")
+
+    def delHighDynamicRange(self):
+        if ("HighDynamicRange" in self.configuration):
+            del self.configuration["HighDynamicRange"]
+            return self.reconfigure(True, "HighDynamicRange")
+        return True
+
+    def setExposureAdjust(self, stops):
+        """ Sets a relative exposure adjustment to multiply with the result of
+        rendering the scene, in stops.  A value of 0 means no adjustment, a
+        positive value will result in a brighter image.  Useful in conjunction
+        with HDR, see setHighDynamicRange.
+
+        .. versionadded:: 1.10.7
+        """
+        old_stops = self.configuration.get("ExposureAdjust")
+        if old_stops != stops:
+            self.configuration["ExposureAdjust"] = stops
+            return self.reconfigure(old_stops is None, "ExposureAdjust")
+        return True
+
+    def delExposureAdjust(self):
+        if ("ExposureAdjust" in self.configuration):
+            del self.configuration["ExposureAdjust"]
+            return self.reconfigure(True, "ExposureAdjust")
+        return True
+
     #snake_case alias:
     del_cartoon_ink = delCartoonInk
     set_half_pixel_shift = setHalfPixelShift
@@ -555,7 +665,6 @@ class CommonFilters:
     del_inverted = delInverted
     del_view_glow = delViewGlow
     set_volumetric_lighting = setVolumetricLighting
-    del_gamma_adjust = delGammaAdjust
     set_bloom = setBloom
     set_view_glow = setViewGlow
     set_ambient_occlusion = setAmbientOcclusion
@@ -566,3 +675,10 @@ class CommonFilters:
     del_blur_sharpen = delBlurSharpen
     del_volumetric_lighting = delVolumetricLighting
     set_gamma_adjust = setGammaAdjust
+    del_gamma_adjust = delGammaAdjust
+    set_srgb_encode = setSrgbEncode
+    del_srgb_encode = delSrgbEncode
+    set_exposure_adjust = setExposureAdjust
+    del_exposure_adjust = delExposureAdjust
+    set_high_dynamic_range = setHighDynamicRange
+    del_high_dynamic_range = delHighDynamicRange

+ 7 - 1
direct/src/filter/FilterManager.py

@@ -3,6 +3,8 @@
 The FilterManager is a convenience class that helps with the creation
 of render-to-texture buffers for image postprocessing applications.
 
+See :ref:`generalized-image-filters` for information on how to use this class.
+
 Still need to implement:
 
 * Make sure sort-order of buffers is correct.
@@ -22,6 +24,7 @@ from panda3d.core import WindowProperties, FrameBufferProperties
 from panda3d.core import Camera
 from panda3d.core import OrthographicLens
 from panda3d.core import AuxBitplaneAttrib
+from panda3d.core import LightRampAttrib
 from direct.directnotify.DirectNotifyGlobal import *
 from direct.showbase.DirectObject import DirectObject
 
@@ -124,7 +127,7 @@ class FilterManager(DirectObject):
 
         return winx,winy
 
-    def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None):
+    def renderSceneInto(self, depthtex=None, colortex=None, auxtex=None, auxbits=0, textures=None, fbprops=None, clamping=None):
 
         """ Causes the scene to be rendered into the supplied textures
         instead of into the original window.  Puts a fullscreen quad
@@ -207,6 +210,9 @@ class FilterManager(DirectObject):
         #cs.setShaderAuto()
         if (auxbits):
             cs.setAttrib(AuxBitplaneAttrib.make(auxbits))
+        if clamping is False:
+            # Disables clamping in the shader generator.
+            cs.setAttrib(LightRampAttrib.make_identity())
         self.camera.node().setInitialState(cs.getState())
 
         quadcamnode = Camera("filter-quad-cam")

+ 3 - 0
direct/src/filter/__init__.py

@@ -8,4 +8,7 @@ texture values as desired.
 The :class:`.CommonFilters` class contains various filters that are
 provided out of the box, whereas the :class:`.FilterManager` class
 is a lower-level class that allows you to set up your own filters.
+
+See the :ref:`render-to-texture-and-image-postprocessing` section of the
+Programming Guide to learn more about image postprocessing in Panda3D.
 """

+ 2 - 19
direct/src/fsm/State.py

@@ -33,15 +33,13 @@ class State(DirectObject):
                     if enterFunc.__func__ == oldFunction:
                         # print 'found: ', enterFunc, oldFunction
                         state.setEnterFunc(types.MethodType(newFunction,
-                                                            enterFunc.__self__,
-                                                            enterFunc.__self__.__class__))
+                                                            enterFunc.__self__))
                         count += 1
                 if type(exitFunc) == types.MethodType:
                     if exitFunc.__func__ == oldFunction:
                         # print 'found: ', exitFunc, oldFunction
                         state.setExitFunc(types.MethodType(newFunction,
-                                                           exitFunc.__self__,
-                                                           exitFunc.__self__.__class__))
+                                                           exitFunc.__self__))
                         count += 1
             return count
 
@@ -215,18 +213,3 @@ class State(DirectObject):
     def __str__(self):
         return "State: name = %s, enter = %s, exit = %s, trans = %s, children = %s" %\
                (self.__name, self.__enterFunc, self.__exitFunc, self.__transitions, self.__FSMList)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-

+ 16 - 0
direct/src/gui/DirectGuiGlobals.py

@@ -128,6 +128,8 @@ def getDefaultFont():
     return defaultFont
 
 def setDefaultFont(newFont):
+    """Changes the default font for DirectGUI items.  To change the default
+    font across the board, see :meth:`.TextNode.setDefaultFont`. """
     global defaultFont
     defaultFont = newFont
 
@@ -161,3 +163,17 @@ def getDefaultPanel():
 def setDefaultPanel(newPanel):
     global panel
     panel = newPanel
+
+get_default_rollover_sound = getDefaultRolloverSound
+set_default_rollover_sound = setDefaultRolloverSound
+get_default_click_sound = getDefaultClickSound
+set_default_click_sound = setDefaultClickSound
+get_default_font = getDefaultFont
+set_default_font = setDefaultFont
+get_default_dialog_geom = getDefaultDialogGeom
+get_default_dialog_relief = getDefaultDialogRelief
+set_default_dialog_geom = setDefaultDialogGeom
+get_default_draw_order = getDefaultDrawOrder
+set_default_draw_order = setDefaultDrawOrder
+get_default_panel = getDefaultPanel
+set_default_panel = setDefaultPanel

+ 1 - 2
direct/src/interval/FunctionInterval.py

@@ -37,8 +37,7 @@ class FunctionInterval(Interval.Interval):
                     if ival.function.__func__ == oldFunction:
                         # print 'found: ', ival.function, oldFunction
                         ival.function = types.MethodType(newFunction,
-                                                         ival.function.__self__,
-                                                         ival.function.__self__.__class__)
+                                                         ival.function.__self__)
                         count += 1
             return count
 

+ 5 - 5
direct/src/showbase/DirectObject.py

@@ -94,12 +94,12 @@ class DirectObject:
         if hasattr(self, '_taskList'):
             tasks = [task.name for task in self._taskList.values()]
         if len(events) or len(tasks):
-            estr = choice(len(events), 'listening to events: %s' % events, '')
-            andStr = choice(len(events) and len(tasks), ' and ', '')
-            tstr = choice(len(tasks), '%srunning tasks: %s' % (andStr, tasks), '')
+            estr = ('listening to events: %s' % events if len(events) else '')
+            andStr = (' and ' if len(events) and len(tasks) else '')
+            tstr = ('%srunning tasks: %s' % (andStr, tasks) if len(tasks) else '')
             notify = directNotify.newCategory('LeakDetect')
-            func = choice(getRepository()._crashOnProactiveLeakDetect,
-                          self.notify.error, self.notify.warning)
+            crash = getattr(getRepository(), '_crashOnProactiveLeakDetect', False)
+            func = (self.notify.error if crash else self.notify.warning)
             func('destroyed %s instance is still %s%s' % (self.__class__.__name__, estr, tstr))
 
     #snake_case alias:

+ 9 - 9
direct/src/showbase/Loader.py

@@ -24,14 +24,14 @@ class Loader(DirectObject):
 
     _loadedPythonFileTypes = False
 
-    class Callback:
+    class _Callback:
         """Returned by loadModel when used asynchronously.  This class is
         modelled after Future, and can be awaited."""
 
         # This indicates that this class behaves like a Future.
         _asyncio_future_blocking = False
 
-        class ResultAwaiter(object):
+        class _ResultAwaiter(object):
             """Reinvents generators because of PEP 479, sigh.  See #513."""
 
             __slots__ = 'requestList', 'index'
@@ -126,9 +126,9 @@ class Loader(DirectObject):
                 self._asyncio_future_blocking = True
 
             if self.gotList:
-                return self.ResultAwaiter([self])
+                return self._ResultAwaiter([self])
             else:
-                return self.ResultAwaiter(self.requestList)
+                return self._ResultAwaiter(self.requestList)
 
         def __aiter__(self):
             """ This allows using `async for` to iterate asynchronously over
@@ -138,7 +138,7 @@ class Loader(DirectObject):
             requestList = self.requestList
             assert requestList is not None, "Request was cancelled."
 
-            return self.ResultAwaiter(requestList)
+            return self._ResultAwaiter(requestList)
 
     # special methods
     def __init__(self, base):
@@ -308,7 +308,7 @@ class Loader(DirectObject):
             # requested models have been loaded, we'll invoke the
             # callback (passing it the models on the parameter list).
 
-            cb = Loader.Callback(self, len(modelList), gotList, callback, extraArgs)
+            cb = Loader._Callback(self, len(modelList), gotList, callback, extraArgs)
             i = 0
             for modelPath in modelList:
                 request = self.loader.makeAsyncRequest(Filename(modelPath), loaderOptions)
@@ -476,7 +476,7 @@ class Loader(DirectObject):
             # requested models have been saved, we'll invoke the
             # callback (passing it the models on the parameter list).
 
-            cb = Loader.Callback(self, len(modelList), gotList, callback, extraArgs)
+            cb = Loader._Callback(self, len(modelList), gotList, callback, extraArgs)
             i = 0
             for modelPath, node in modelList:
                 request = self.loader.makeAsyncSaveRequest(Filename(modelPath), loaderOptions, node)
@@ -1013,7 +1013,7 @@ class Loader(DirectObject):
             # requested sounds have been loaded, we'll invoke the
             # callback (passing it the sounds on the parameter list).
 
-            cb = Loader.Callback(self, len(soundList), gotList, callback, extraArgs)
+            cb = Loader._Callback(self, len(soundList), gotList, callback, extraArgs)
             for i, soundPath in enumerate(soundList):
                 request = AudioLoadRequest(manager, soundPath, positional)
                 request.setDoneEvent(self.hook)
@@ -1078,7 +1078,7 @@ class Loader(DirectObject):
             callback = self.__asyncFlattenDone
             gotList = True
 
-        cb = Loader.Callback(self, len(modelList), gotList, callback, extraArgs)
+        cb = Loader._Callback(self, len(modelList), gotList, callback, extraArgs)
         i = 0
         for model in modelList:
             request = ModelFlattenRequest(model.node())

+ 2 - 3
direct/src/showbase/Messenger.py

@@ -1,5 +1,5 @@
 """This defines the Messenger class, which is responsible for most of the
-event handling that happens on the Python side.
+:ref:`event handling <event-handlers>` that happens on the Python side.
 """
 
 __all__ = ['Messenger']
@@ -464,8 +464,7 @@ class Messenger:
                 #       'oldMethod: ' + repr(oldMethod) + '\n' +
                 #       'newFunction: ' + repr(newFunction) + '\n')
                 if (function == oldMethod):
-                    newMethod = types.MethodType(
-                        newFunction, method.__self__, method.__self__.__class__)
+                    newMethod = types.MethodType(newFunction, method.__self__)
                     params[0] = newMethod
                     # Found it retrun true
                     retFlag += 1

+ 3 - 3
direct/src/showbase/OnScreenDebug.py

@@ -38,9 +38,9 @@ class OnScreenDebug:
             print("failed to load OnScreenDebug font %s" % fontPath)
             font = TextNode.getDefaultFont()
         self.onScreenText = OnscreenText.OnscreenText(
-                pos = (-1.0, 0.9), fg=fgColor, bg=bgColor,
-                scale = (fontScale, fontScale, 0.0), align = TextNode.ALeft,
-                mayChange = 1, font = font)
+                parent = base.a2dTopLeft, pos = (0.0, -0.1),
+                fg=fgColor, bg=bgColor, scale = (fontScale, fontScale, 0.0),
+                align = TextNode.ALeft, mayChange = 1, font = font)
         # Make sure readout is never lit or drawn in wireframe
         DirectUtil.useDirectRenderStyle(self.onScreenText)
 

+ 0 - 1
direct/src/showbase/ProfileSession.py

@@ -1,4 +1,3 @@
-from __future__ import print_function
 from panda3d.core import TrueClock
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.showbase.PythonUtil import (

+ 4 - 3
direct/src/showbase/PythonUtil.py

@@ -39,6 +39,7 @@ import random
 import time
 import builtins
 import importlib
+import functools
 
 __report_indent = 3
 
@@ -1560,7 +1561,7 @@ def appendStr(obj, st):
             return s
         oldStr = Functor(stringer, str(obj))
         stringer = None
-    obj.__str__ = types.MethodType(Functor(appendedStr, oldStr, st), obj, obj.__class__)
+    obj.__str__ = types.MethodType(Functor(appendedStr, oldStr, st), obj)
     appendedStr = None
     return obj
 
@@ -2062,7 +2063,7 @@ def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigPara
             if not rArgs:
                 rArgs = '()'
             else:
-                rArgs = '(' + reduce(str.__add__,rArgs)[:-2] + ')'
+                rArgs = '(' + functools.reduce(str.__add__,rArgs)[:-2] + ')'
 
 
             outStr = '%s%s' % (f.__name__, rArgs)
@@ -2345,7 +2346,7 @@ class MiniLog:
         if not rArgs:
             rArgs = '()'
         else:
-            rArgs = '(' + reduce(str.__add__,rArgs)[:-2] + ')'
+            rArgs = '(' + functools.reduce(str.__add__,rArgs)[:-2] + ')'
 
         line = '%s%s' % (funcName, rArgs)
         self.appendFunctionCall(line)

File diff suppressed because it is too large
+ 277 - 141
direct/src/showbase/ShowBase.py


+ 10 - 5
direct/src/showbase/ShowBaseGlobal.py

@@ -2,9 +2,14 @@
 :class:`~.ShowBase.ShowBase` instance, as an alternative to using the builtin
 scope.
 
-Note that you cannot directly import `base` from this module since ShowBase
-may not have been created yet; instead, ShowBase dynamically adds itself to
-this module's scope when instantiated."""
+Many of the variables contained in this module are also automatically written
+to the :mod:`builtins` module when ShowBase is instantiated, making them
+available to any Python code.  Importing them from this module instead can make
+it easier to see where these variables are coming from.
+
+Note that you cannot directly import :data:`~builtins.base` from this module
+since ShowBase may not have been created yet; instead, ShowBase dynamically
+adds itself to this module's scope when instantiated."""
 
 __all__ = []
 
@@ -17,8 +22,8 @@ from . import DConfig as config
 
 __dev__ = config.GetBool('want-dev', __debug__)
 
-#: The global instance of the :class:`~panda3d.core.VirtualFileSystem`, as
-#: obtained using :meth:`panda3d.core.VirtualFileSystem.getGlobalPtr()`.
+#: The global instance of the :ref:`virtual-file-system`, as obtained using
+#: :meth:`panda3d.core.VirtualFileSystem.getGlobalPtr()`.
 vfs = VirtualFileSystem.getGlobalPtr()
 
 #: The default Panda3D output stream for notifications and logging, as

+ 3 - 0
direct/src/showbase/__init__.py

@@ -0,0 +1,3 @@
+""" This package contains `.ShowBase`, an application framework responsible
+for opening a graphical display, setting up input devices and creating
+the scene graph. """

+ 6 - 3
direct/src/showutil/TexMemWatcher.py

@@ -327,7 +327,10 @@ class TexMemWatcher(DirectObject):
 
         if self.dynamicLimit:
             # Choose a suitable limit by rounding to the next power of two.
-            self.limit = Texture.upToPower2(self.totalSize)
+            limit = 1
+            while limit < self.totalSize:
+                limit *= 2
+            self.limit = limit
 
         # Set our GSG to limit itself to no more textures than we
         # expect to display onscreen, so we don't go crazy with
@@ -883,7 +886,7 @@ class TexMemWatcher(DirectObject):
             matches.append((match, tp))
 
         if matches:
-            return max(matches)[1]
+            return max(matches, key=lambda match: match[0])[1]
         return None
 
     def findHolePieces(self, area):
@@ -937,7 +940,7 @@ class TexMemWatcher(DirectObject):
     def findLargestHole(self):
         holes = self.findAvailableHoles(0)
         if holes:
-            return max(holes)[1]
+            return max(holes, key=lambda hole: hole[0])[1]
         return None
 
     def findAvailableHoles(self, area, w = None, h = None):

+ 2 - 1
direct/src/stdpy/__init__.py

@@ -1,5 +1,6 @@
 """
 This package contains various modules that provide a drop-in substitute
 for some of the built-in Python modules.  These substitutes make better
-use of Panda3D's virtual file system and threading system.
+use of Panda3D's :ref:`Virtual File System <virtual-file-system>` and
+:ref:`threading` system.
 """

+ 1 - 3
direct/src/task/Task.py

@@ -593,9 +593,7 @@ class TaskManager:
         else:
             function = method
         if (function == oldMethod):
-            newMethod = types.MethodType(newFunction,
-                                         method.__self__,
-                                         method.__self__.__class__)
+            newMethod = types.MethodType(newFunction, method.__self__)
             task.setFunction(newMethod)
             # Found a match
             return 1

+ 14 - 8
direct/src/tkpanels/Inspector.py

@@ -1,8 +1,15 @@
 """Inspectors allow you to visually browse through the members of
-various python objects.  To open an inspector, import this module, and
-execute inspector.inspect(anObject) I start IDLE with this command
-line: idle.py -c "from inspector import inspect"
-so that I can just type: inspect(anObject) any time."""
+various Python objects.  To open an inspector, import this module, and
+execute ``inspector.inspect(anObject)``.
+
+I start IDLE with this command line::
+
+   idle.py -c "from inspector import inspect"
+
+so that I can just type: ``inspect(anObject)`` any time.
+
+See :ref:`inspection-utilities` for more information.
+"""
 
 
 __all__ = ['inspect', 'inspectorFor', 'Inspector', 'ModuleInspector', 'ClassInspector', 'InstanceInspector', 'FunctionInspector', 'InstanceMethodInspector', 'CodeInspector', 'ComplexInspector', 'DictionaryInspector', 'SequenceInspector', 'SliceInspector', 'InspectorWindow']
@@ -13,6 +20,9 @@ import Pmw
 ### public API
 
 def inspect(anObject):
+    """Opens up a window for visually inspecting the details of a given Python
+    object.  See :ref:`inspection-utilities`.
+    """
     inspector = inspectorFor(anObject)
     inspectorWindow = InspectorWindow(inspector)
     inspectorWindow.open()
@@ -437,7 +447,3 @@ class InspectorWindow:
                 label = item,
                 command = lambda p = part, f = func: f(p))
         return popupMenu
-
-
-
-

+ 71 - 0
doc/ReleaseNotes

@@ -1,3 +1,74 @@
+------------------------  RELEASE 1.10.7  -----------------------
+
+This is primarily a bugfix release, but includes a few new features as well.
+
+Rendering
+* Add High Dynamic Range filter with ACES tone mapping to CommonFilters
+* Add sRGB filter to CommonFilters (to be used as fallback to framebuffer-srgb)
+* Fix (shadow) buffer no longer working after host buffer is destroyed (#890)
+* Fix rare bug with shader parameters not being set right across render passes
+* Fog density passed to shader now defaults to 0 when no fog is applied
+* Don't check sampler/light type mismatch for non-shadow-casting lights (#942)
+* Shader generator now makes use of Material alpha values if present (#912)
+* Support sRGB textures and framebuffers in OpenGL ES 2 renderer
+
+Asset Loading
+* Egg files can now be loaded with sRGB texture formats automatically
+* Fix maya2egg regression not creating animations properly (#1004)
+* Fix FMOD issue reading sounds from read-write-opened multifiles (#1002)
+
+Stability
+* Fix faulty collision detection when sphere is under polygon (#907)
+* Fix PStats misreporting an exploding number of RenderState/TransformState
+* Fix memory leak when removing a task that is awaiting a non-Panda future
+* Optimize RenderState cache for case where texture is replaced repeatedly
+* PNMImage add_sub_image() / mult_sub_image() now properly adds offset (#903)
+* Fix some ServerRepository issues in Python 3
+* Fix has_tags() still returning true after clearing all Python tags (#936)
+* Fix crash in BitArray.has_any_of()
+* Fix errors in PythonUtil.detectLeaks() and PythonUtil.report()
+* Fix runtime error during ControlManager deletion (#884)
+* Some error messages in nativenet are changed to debug messages
+* Fix TexMemWatcher crash when graphics memory reaches 1 GB (#975)
+* Fix a Triangulator crash dealing with certain invalid polygons (#985)
+* Fix in MultiplexStreamBuf::Output::write_string() (#902)
+* Fix a buffer overrun on FreeBSD when extracting very long command-line args
+
+Input and Windowing
+* M_confined mouse mode on Windows now confines mouse to client rectangle
+* Fix incorrect handling of shift modifier on macOS (#959)
+* Fix erroneous dpad_*-up events when emulating a dpad on Linux (#973)
+* Fix tab handling in DirectEntry with certain versions of Windows CRT (#994)
+* Fix parented window receiving WS_POPUP style on Windows (#915)
+
+Deployment
+* macOS app bundle now performs chdir into Resources folder upon launch
+* No longer defaults to FMOD audio on macOS unless FMOD is explicitly bundled
+* Improvements to Config.prc handling (strip comments, sort files, etc.)
+* Line buffering is now used on Windows when writing to log files (#947)
+* stdout/stderr output streams are now flushed on exit (#946)
+* Build paths are now properly stripped from compiled Python code (#991)
+* Update to support a change in location of numpy/Pillow libraries (#914)
+* Fix libffi-7.dll not being included in official wheels
+* PYTHONINSPECT mechanism is no longer enabled when building with optimizations
+* A few unnecessary warning messages are squelched
+* Windows builds now include previously missing CRT dlls
+
+API
+* Add pickle support to Datagram class
+* Unexpose a crashing CollisionPolygon constructor and method (#908)
+* FilterManager has new parameter to control framebuffer clamping
+* Add snake_case aliases for functions in DirectGuiGlobals
+* Global delete operator is now safe to call with a null pointer
+* Improvements to API reference documentation
+
+Build
+* Fix issues building with development versions Python 3.9 and 3.10
+* Fix an ABI incompatibility issue with MouseWatcher in NDEBUG builds
+* Fix incorrect NaN/inf detection in double-precision release builds (#987)
+* interrogate C++ parser supports arbitrary constant expressions in bitfields
+* interrogate C++ parser supports sizeof with constant expression
+
 ------------------------  RELEASE 1.10.6  -----------------------
 
 This is a recommended bugfix release that adds additional stability fixes.

+ 57 - 63
dtool/Config.cmake

@@ -33,8 +33,6 @@ if(IS_MULTICONFIG)
   set(CMAKE_CONFIGURATION_TYPES ${_configs})
 endif()
 
-set(PER_CONFIG_OPTIONS)
-
 # Are we building with static or dynamic linking?
 option(BUILD_SHARED_LIBS
   "Causes subpackages to be built separately -- setup for dynamic linking.
@@ -145,7 +143,7 @@ identified by PRC_ENCRYPTED_PATTERNS.")
 # that case, config will execute the file if it appears to be
 # executable; otherwise, it will simply read it.
 
-set(PRC_EXECUTABLE_PATTERNS "" CACHE STRING 
+set(PRC_EXECUTABLE_PATTERNS "" CACHE STRING
   "The filename(s) to search for, and execute, in the above paths.
 Normally this is empty.")
 
@@ -204,10 +202,9 @@ set(PRC_INC_TRUST_LEVEL "0" CACHE STRING
 # Similarly, the descriptions are normally saved only in a
 # development build, not in a release build.  Set this value true to
 # explicitly save them anyway.
-#XXX only for release-release builds
-option(PRC_SAVE_DESCRIPTIONS
+per_config_option(PRC_SAVE_DESCRIPTIONS
   "Define if you want to save the descriptions for ConfigVariables."
-  ON)
+  Debug Standard)
 
 mark_as_advanced(DEFAULT_PRC_DIR PRC_DIR_ENVVARS PRC_PATH_ENVVARS
   PRC_PATTERNS PRC_ENCRYPTED_PATTERNS PRC_ENCRYPTION_KEY
@@ -254,49 +251,46 @@ debugging information." OFF)
 mark_as_advanced(INTERROGATE_OPTIONS)
 
 #
-# The following options have to do with the memory allocation system
-# that will be used by Panda3D.
+# The following options have to do with optional debugging features.
 #
 
-option(DO_MEMORY_USAGE
+per_config_option(DO_MEMORY_USAGE
   "Do you want to compile in support for tracking memory usage?  This
 enables you to define the variable 'track-memory-usage' at runtime
 to help track memory leaks, and also report total memory usage on
 PStats.  There is some small overhead for having this ability
-available, even if it is unused." OFF)
-list(APPEND PER_CONFIG_OPTIONS DO_MEMORY_USAGE)
-set(DO_MEMORY_USAGE_Debug ON CACHE BOOL "")
+available, even if it is unused." Debug Standard)
+
+per_config_option(DO_COLLISION_RECORDING
+  "Do you want to enable debugging features for the collision system?"
+  Debug Standard)
+
+per_config_option(DO_PSTATS
+  "Enable support for performance profiling using PStats?"
+  Debug Standard)
 
-option(SIMULATE_NETWORK_DELAY
+per_config_option(DO_DCAST
+  "Add safe typecast checking?  This adds significant overhead."
+  Debug Standard)
+
+per_config_option(SIMULATE_NETWORK_DELAY
   "This option compiles in support for simulating network delay via
 the min-lag and max-lag prc variables.  It adds a tiny bit of
 overhead even when it is not activated, so it is typically enabled
-only in a development build." OFF)
-list(APPEND PER_CONFIG_OPTIONS SIMULATE_NETWORK_DELAY)
-set(SIMULATE_NETWORK_DELAY_Debug ON CACHE BOOL "")
+only in a development build."
+  Debug)
 
-option(SUPPORT_IMMEDIATE_MODE
-  "This option compiles in support for immediate-mode OpenGL
-rendering.  Since this is normally useful only for researching
-buggy drivers, and since there is a tiny bit of per-primitive
-overhead to have this option available even if it is unused, it is
-by default enabled only in a development build.  This has no effect
-on DirectX rendering." OFF)
-list(APPEND PER_CONFIG_OPTIONS SUPPORT_IMMEDIATE_MODE)
-set(SUPPORT_IMMEDIATE_MODE_Debug ON CACHE BOOL "")
-
-option(NOTIFY_DEBUG
+per_config_option(NOTIFY_DEBUG
   "Do you want to include the 'debug' and 'spam' Notify messages?
 Normally, these are stripped out when we build for release, but sometimes it's
-useful to keep them around. Turn this setting on to achieve that." OFF)
-list(APPEND PER_CONFIG_OPTIONS NOTIFY_DEBUG)
-set(NOTIFY_DEBUG_Debug ON CACHE BOOL "")
-set(NOTIFY_DEBUG_Standard ON CACHE BOOL "")
+useful to keep them around. Turn this setting on to achieve that."
+  Debug Standard)
 
-option(SUPPORT_FIXED_FUNCTION
-  "This option compiles in support for the fixed-function OpenGL
-pipeline.  It is only really useful to turn this off if you are targeting
-an OpenGL ES 2 system." ON)
+mark_as_advanced(SIMULATE_NETWORK_DELAY DO_MEMORY_USAGE DO_DCAST)
+
+#
+# The following options have to do with the memory allocation system.
+#
 
 option(USE_MEMORY_DLMALLOC
   "This is an optional alternative memory-allocation scheme
@@ -324,8 +318,7 @@ calls to malloc() and free() for frequently-created and -deleted
 objects.  There's usually no reason to set this false, unless you
 suspect a bug in Panda's memory management code." ON)
 
-mark_as_advanced(DO_MEMORY_USAGE SIMULATE_NETWORK_DELAY
-  SUPPORT_IMMEDIATE_MODE USE_MEMORY_DLMALLOC USE_MEMORY_PTMALLOC2
+mark_as_advanced(USE_MEMORY_DLMALLOC USE_MEMORY_PTMALLOC2
   MEMORY_HOOK_DO_ALIGN USE_DELETED_CHAIN)
 
 
@@ -379,11 +372,11 @@ mark_as_advanced(ANDROID_NDK_HOME ANDROID_ABI ANDROID_STL
 
 # By default, we'll assume the user only wants to run with Debug
 # python if he has to--that is, on Windows when building a debug build.
-set(USE_DEBUG_PYTHON OFF)
 if(WIN32)
-  set(USE_DEBUG_PYTHON_Debug ON)
+  per_config_option(USE_DEBUG_PYTHON "" Debug)
+else()
+  option(USE_DEBUG_PYTHON "" OFF)
 endif()
-list(APPEND PER_CONFIG_OPTIONS USE_DEBUG_PYTHON)
 
 cmake_dependent_option(HAVE_VIDEO4LINUX
   "Set this to enable webcam support on Linux." ON
@@ -405,15 +398,27 @@ version and below, which may reduce runtime portability to other
 systems, but it will avoid issues with getting extension function
 pointers.")
 
+option(SUPPORT_FIXED_FUNCTION
+  "This option compiles in support for the fixed-function OpenGL pipeline.
+It is only really useful to turn this off to save space if you are building
+an application that only needs to use an OpenGL 3.2+ context and only uses
+custom GLSL shaders." ON)
+
+option(SUPPORT_IMMEDIATE_MODE
+  "This option compiles in support for immediate-mode OpenGL
+rendering.  Since this is normally useful only for researching
+buggy drivers, and since there is a tiny bit of per-primitive
+overhead to have this option available even if it is unused, it is
+by default enabled only in a development build.  This has no effect
+on DirectX rendering." OFF)
+
+mark_as_advanced(SUPPORT_FIXED_FUNCTION)
 
 # Should build tinydisplay?
 #option(HAVE_TINYDISPLAY
 #  "Builds TinyDisplay, a light software renderer based on TinyGL,
 #that is built into Panda. TinyDisplay is not as full-featured as Mesa
 #but is many times faster." ON)
-#option(HAVE_TINYDISPLAY_MinSizeRel "" OFF)
-#list(APPEND PER_CONFIG_OPTIONS HAVE_TINYDISPLAY)
-
 
 # Is SDL installed, and where?
 set(Threads_FIND_QUIETLY TRUE) # Fix for builtin FindSDL
@@ -477,9 +482,6 @@ build (such as, for instance, for the iPhone)." ON)
 option(HAVE_AUDIO
   "Do you want to build the audio interface?" ON)
 
-option(DO_PSTATS
-  "Enable the pstats client?" ON)
-
 option(USE_PANDAFILESTREAM
   "Enable the PandaFileStream implementation of pfstream etc.?" ON)
 
@@ -492,16 +494,12 @@ option(HAVE_IMG "Enable support for loading IMG images." ON)
 option(HAVE_SOFTIMAGE_PIC "Enable support for loading SOFTIMAGE PIC images." ON)
 option(HAVE_BMP "Enable support for loading BMP images." ON)
 option(HAVE_PNM "Enable support for loading PNM images." ON)
-
-foreach(adv_image_format
-  HAVE_SGI_RGB HAVE_TGA HAVE_IMG HAVE_SOFTIMAGE_PIC HAVE_BMP HAVE_PNM)
-
-  option(${adv_image_format}_MinSizeRel "" OFF)
-  list(APPEND PER_CONFIG_OPTIONS ${adv_image_format})
-
-  mark_as_advanced(${adv_image_format} ${adv_image_format}_MinSizeRel)
-
-endforeach(adv_image_format)
+option(HAVE_SGI_RGB "" ON)
+option(HAVE_TGA "" ON)
+option(HAVE_IMG "" ON)
+option(HAVE_SOFTIMAGE_PIC "" ON)
+option(HAVE_BMP "" ON)
+option(HAVE_PNM "" ON)
 
 # How to invoke bison and flex.  Panda takes advantage of some
 # bison/flex features, and therefore specifically requires bison and
@@ -539,9 +537,9 @@ slightly slow down Panda for the single CPU case."
   IMPORTED_AS Threads::Threads)
 
 # Configure debug threads
-option(DEBUG_THREADS "If on, enables debugging of thread and sync operations (i.e. mutexes, deadlocks)" OFF)
-list(APPEND PER_CONFIG_OPTIONS DEBUG_THREADS)
-set(DEBUG_THREADS_Debug ON CACHE BOOL "")
+option(DEBUG_THREADS
+  "If on, enables debugging of thread and sync operations (i.e. mutexes,
+deadlocks).  Very slow, disabled by default." OFF)
 
 option(SIMPLE_THREADS
   "If on, compile with simulated threads.  Threads, by default, use
@@ -551,7 +549,6 @@ On the other hand, compiling in this full OS-provided support can
 impose some substantial runtime overhead, making the application
 run slower on a single-CPU machine. This settings avoid the overhead,
 but still gain some of the basic functionality of threads." OFF)
-list(APPEND PER_CONFIG_OPTIONS SIMPLE_THREADS)
 
 option(OS_SIMPLE_THREADS
   "If on, OS threading constructs will be used to perform context switches.
@@ -560,7 +557,6 @@ normal SIMPLE_THREADS optimizations still apply, and the normal
 SIMPLE_THREADS scheduler is used to switch between threads (instead
 of the OS scheduler).  This may be more portable and more reliable,
 but it is a hybrid between user-space threads and os-provided threads." ON)
-list(APPEND PER_CONFIG_OPTIONS OS_SIMPLE_THREADS)
 
 ### Configure pipelining ###
 option(DO_PIPELINING "If on, compile with pipelined rendering." ON)
@@ -570,8 +566,6 @@ option(COMPILE_IN_DEFAULT_FONT
   "If on, compiles in a default font, so that every TextNode will always
 have a font available without requiring the user to specify one.
 When turned off, the generated library will save a few kilobytes." ON)
-list(APPEND PER_CONFIG_OPTIONS COMPILE_IN_DEFAULT_FONT)
-set(COMPILE_IN_DEFAULT_FONT_MinSizeRel OFF CACHE BOOL "")
 
 option(STDFLOAT_DOUBLE
   "Define this true to compile a special version of Panda to use a

+ 7 - 4
dtool/LocalSetup.cmake

@@ -186,11 +186,14 @@ message("")
 # Generate dtool_config.h
 if(IS_MULTICONFIG)
   foreach(config ${CMAKE_CONFIGURATION_TYPES})
-    foreach(option ${PER_CONFIG_OPTIONS})
+    string(TOUPPER "${config}" config_upper)
+    foreach(option ${_PER_CONFIG_OPTIONS})
       # Check for the presence of a config-specific option, and override what's
       # in the cache if there is.
-      if(DEFINED ${option}_${config})
-        set(${option} ${${option}_${config}})
+      if(DEFINED "${option}_${config_upper}")
+        set(${option} ${${option}_${config_upper}})
+      else()
+        message(FATAL_ERROR "${option}_${config_upper} is not defined")
       endif()
     endforeach(option)
 
@@ -199,7 +202,7 @@ if(IS_MULTICONFIG)
 
     # unset() does not unset CACHE variables by default, just normal variables.
     # By doing this we're reverting back to what was in the cache.
-    foreach(option ${PER_CONFIG_OPTIONS})
+    foreach(option ${_PER_CONFIG_OPTIONS})
       unset(${option})
     endforeach(option)
   endforeach(config)

+ 2 - 2
dtool/Package.cmake

@@ -369,7 +369,7 @@ package_option(TIFF "Enable support for loading .tif images.")
 package_status(TIFF "libtiff")
 
 # OpenEXR
-find_package(OpenEXR QUIET)
+find_package(OpenEXR QUIET MODULE)
 
 package_option(OpenEXR "Enable support for loading .exr images.")
 
@@ -390,7 +390,7 @@ package_status(SQUISH "libsquish")
 #
 
 # Assimp
-find_package(Assimp QUIET)
+find_package(Assimp QUIET MODULE)
 
 package_option(Assimp
   "Build pandatool with support for loading 3D assets supported by Assimp.")

+ 1 - 50
dtool/PandaVersion.cmake

@@ -24,37 +24,7 @@ particular license. Some packages don't have a listed license because
 they are almost always required/used, or because they are only used in
 plugins that can be easily removed (eg. directx, ffmpeg, fmod, ...).")
 
-set(PANDA_PACKAGE_VERSION CACHE STRING
-  "This string is used to describe the Panda3D \"package\" associated
-with this current build of Panda. It should increment with major
-and minor version changes, but not sequence (or \"bugfix\") changes.
-It should be unique for each unique distributor. The default is
-the empty string, which means this build does not precisely match
-any distributable Panda3D packages. If you are making a Panda3D
-build which you will be using to produce a distributable Panda3D
-package, you should set this string appropriately.")
-
-set(P3D_PLUGIN_VERSION "1.0.4" CACHE STRING
-  "We also define a version for the Panda3D plugin/runtime,
-i.e. nppanda3d.dll, p3dactivex.ocx, and panda3d.exe. This is an
-independent version number from PANDA_VERSION or
-PANDA_PACKAGE_VERSION, because it is anticipated that this plugin
-code, once settled, will need to be updated much less frequently
-than Panda itself.")
-
-set(P3D_COREAPI_VERSION "${P3D_PLUGIN_VERSION}.1" CACHE STRING
-  "Finally, there's a separate version number for the Core API. At
-first, we didn't believe we needed a Core API version number, but
-in this belief we were naive.  This version number is a little less
-strict in its format requirements than P3D_PLUGIN_VERSION, above,
-and it doesn't necessarily consist of a specific number of
-integers, but by convention it will consist of four integers, with
-the first three matching the plugin version, and the fourth integer
-being incremented with each new Core API revision.")
-
-mark_as_advanced(PANDA_VERSION PANDA_OFFICIAL_VERSION
-  PANDA_PACKAGE_VERSION P3D_PLUGIN_VERSION P3D_COREAPI_VERSION
-  PANDA_DIST_USE_LICENSES)
+mark_as_advanced(PANDA_VERSION PANDA_OFFICIAL_VERSION PANDA_DIST_USE_LICENSES)
 
 # The version gets a "c" at the end if it's not an official one.
 if(PANDA_OFFICIAL_VERSION)
@@ -82,22 +52,3 @@ if(GIT_EXECUTABLE)
     OUTPUT_VARIABLE PANDA_GIT_COMMIT_STR
     ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
 endif()
-
-# Separate the plugin version into its three components.
-string(REPLACE "." ";" P3D_PLUGIN_VERSION_LIST "${P3D_PLUGIN_VERSION}")
-list(GET P3D_PLUGIN_VERSION_LIST 0 P3D_PLUGIN_MAJOR_VERSION)
-list(GET P3D_PLUGIN_VERSION_LIST 1 P3D_PLUGIN_MINOR_VERSION)
-list(GET P3D_PLUGIN_VERSION_LIST 2 P3D_PLUGIN_SEQUENCE_VERSION)
-
-set(P3D_PLUGIN_VERSION_STR "${P3D_PLUGIN_VERSION}${VERSION_SUFFIX}")
-
-# The plugin version as dot-delimited integer quad, according to MS
-# conventions for DLL version numbers.
-if(PANDA_OFFICIAL_VERSION)
-  set(P3D_PLUGIN_DLL_DOT_VERSION "${P3D_PLUGIN_VERSION}.1000")
-else()
-  set(P3D_PLUGIN_DLL_DOT_VERSION "${P3D_PLUGIN_VERSION}.0")
-endif()
-
-# The same thing as a comma-delimited quad.
-string(REPLACE "." "," P3D_PLUGIN_DLL_COMMA_VERSION "${P3D_PLUGIN_DLL_DOT_VERSION}")

File diff suppressed because it is too large
+ 432 - 353
dtool/src/cppparser/cppBison.cxx.prebuilt


+ 6 - 2
dtool/src/cppparser/cppBison.h.prebuilt

@@ -1,8 +1,9 @@
-/* A Bison parser, made by GNU Bison 3.0.5.  */
+/* A Bison parser, made by GNU Bison 3.5.3.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018 Free Software Foundation, Inc.
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+   Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -30,6 +31,9 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+/* Undocumented macros, especially those whose name start with YY_,
+   are private implementation details.  Do not rely on them.  */
+
 #ifndef YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
 # define YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED
 /* Debug traces.  */

+ 13 - 37
dtool/src/cppparser/cppBison.yxx

@@ -1891,7 +1891,7 @@ instance_identifier_and_maybe_trailing_return_type:
   }
   $$ = $1;
 }
-        | instance_identifier ':' INTEGER
+        | instance_identifier ':' const_expr
 {
   // Bitfield definition.
   $1->_bit_width = $3;
@@ -3278,17 +3278,9 @@ no_angle_bracket_const_expr:
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
 }
-        | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY
+        | KW_SIZEOF no_angle_bracket_const_expr %prec UNARY
 {
-  CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer);
-  if (arg == nullptr) {
-    yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3);
-  } else if (arg->get_subtype() == CPPDeclaration::ST_instance) {
-    CPPInstance *inst = arg->as_instance();
-    $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type));
-  } else {
-    $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type()));
-  }
+  $$ = new CPPExpression(CPPExpression::sizeof_func($2));
 }
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
 {
@@ -3402,9 +3394,9 @@ no_angle_bracket_const_expr:
 {
   $$ = new CPPExpression('f', $1);
 }
-        | no_angle_bracket_const_expr '.' no_angle_bracket_const_expr
+        | no_angle_bracket_const_expr '.' name
 {
-  $$ = new CPPExpression('.', $1, $3);
+  $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer));
 }
         | no_angle_bracket_const_expr POINTSAT no_angle_bracket_const_expr
 {
@@ -3542,17 +3534,9 @@ const_expr:
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
 }
-        | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY
+        | KW_SIZEOF const_expr %prec UNARY
 {
-  CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer);
-  if (arg == nullptr) {
-    yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3);
-  } else if (arg->get_subtype() == CPPDeclaration::ST_instance) {
-    CPPInstance *inst = arg->as_instance();
-    $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type));
-  } else {
-    $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type()));
-  }
+  $$ = new CPPExpression(CPPExpression::sizeof_func($2));
 }
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
 {
@@ -3704,9 +3688,9 @@ const_expr:
 {
   $$ = new CPPExpression('f', $1);
 }
-        | const_expr '.' const_expr
+        | const_expr '.' name
 {
-  $$ = new CPPExpression('.', $1, $3);
+  $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer));
 }
         | const_expr POINTSAT const_expr
 {
@@ -3886,17 +3870,9 @@ formal_const_expr:
 {
   $$ = new CPPExpression(CPPExpression::sizeof_func($3));
 }
-        | KW_SIZEOF '(' IDENTIFIER ')' %prec UNARY
+        | KW_SIZEOF formal_const_expr %prec UNARY
 {
-  CPPDeclaration *arg = $3->find_symbol(current_scope, global_scope, current_lexer);
-  if (arg == nullptr) {
-    yyerror("undefined sizeof argument: " + $3->get_fully_scoped_name(), @3);
-  } else if (arg->get_subtype() == CPPDeclaration::ST_instance) {
-    CPPInstance *inst = arg->as_instance();
-    $$ = new CPPExpression(CPPExpression::sizeof_func(inst->_type));
-  } else {
-    $$ = new CPPExpression(CPPExpression::sizeof_func(arg->as_type()));
-  }
+  $$ = new CPPExpression(CPPExpression::sizeof_func($2));
 }
         | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY
 {
@@ -4044,9 +4020,9 @@ formal_const_expr:
 {
   $$ = new CPPExpression('f', $1);
 }
-        | formal_const_expr '.' const_expr
+        | formal_const_expr '.' name
 {
-  $$ = new CPPExpression('.', $1, $3);
+  $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer));
 }
         | formal_const_expr POINTSAT const_expr
 {

+ 47 - 9
dtool/src/cppparser/cppExpression.cxx

@@ -429,12 +429,24 @@ type_trait(int trait, CPPType *type, CPPType *arg) {
 CPPExpression CPPExpression::
 sizeof_func(CPPType *type) {
   CPPExpression expr(0);
-  expr._type = T_sizeof;
+  expr._type = T_sizeof_type;
   expr._u._typecast._to = type;
   expr._u._typecast._op1 = nullptr;
   return expr;
 }
 
+/**
+ *
+ */
+CPPExpression CPPExpression::
+sizeof_func(CPPExpression *op1) {
+  CPPExpression expr(0);
+  expr._type = T_sizeof_expr;
+  expr._u._typecast._to = nullptr;
+  expr._u._typecast._op1 = op1;
+  return expr;
+}
+
 /**
  *
  */
@@ -629,7 +641,8 @@ evaluate() const {
   case T_empty_aggregate_init:
   case T_new:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
+  case T_sizeof_expr:
   case T_sizeof_ellipsis:
     return Result();
 
@@ -1058,7 +1071,8 @@ determine_type() const {
   case T_default_new:
     return CPPType::new_type(new CPPPointerType(_u._typecast._to));
 
-  case T_sizeof:
+  case T_sizeof_type:
+  case T_sizeof_expr:
   case T_sizeof_ellipsis:
   case T_alignof:
     // Note: this should actually be size_t, but that is defined as a typedef
@@ -1334,10 +1348,13 @@ is_fully_specified() const {
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
     return _u._typecast._to->is_fully_specified();
 
+  case T_sizeof_expr:
+    return _u._typecast._op1->is_fully_specified();
+
   case T_sizeof_ellipsis:
     return _u._ident->is_fully_specified();
 
@@ -1469,7 +1486,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
     rep->_u._typecast._to =
       _u._typecast._to->substitute_decl(subst, current_scope, global_scope)
@@ -1477,6 +1494,13 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     any_changed = any_changed || (rep->_u._typecast._to != _u._typecast._to);
     break;
 
+  case T_sizeof_expr:
+    rep->_u._typecast._op1 =
+      _u._typecast._op1->substitute_decl(subst, current_scope, global_scope)
+      ->as_expression();
+    any_changed = any_changed || (rep->_u._typecast._op1 != _u._typecast._op1);
+    break;
+
   case T_trinary_operation:
     rep->_u._op._op3 =
       _u._op._op3->substitute_decl(subst, current_scope, global_scope)
@@ -1567,10 +1591,13 @@ is_tbd() const {
   case T_new:
   case T_default_construct:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
     return _u._typecast._to->is_tbd();
 
+  case T_sizeof_expr:
+    return _u._typecast._op1->is_tbd();
+
   case T_trinary_operation:
     if (_u._op._op3->is_tbd()) {
       return true;
@@ -1807,12 +1834,17 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool) const {
     out << "())";
     break;
 
-  case T_sizeof:
+  case T_sizeof_type:
     out << "sizeof(";
     _u._typecast._to->output(out, indent_level, scope, false);
     out << ")";
     break;
 
+  case T_sizeof_expr:
+    out << "sizeof ";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    break;
+
   case T_sizeof_ellipsis:
     out << "sizeof...(";
     _u._ident->output(out, scope);
@@ -2222,10 +2254,13 @@ is_equal(const CPPDeclaration *other) const {
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
     return _u._typecast._to == ot->_u._typecast._to;
 
+  case T_sizeof_expr:
+    return _u._typecast._op1 == ot->_u._typecast._op1;
+
   case T_unary_operation:
     return *_u._op._op1 == *ot->_u._op._op1;
 
@@ -2324,10 +2359,13 @@ is_less(const CPPDeclaration *other) const {
   case T_default_construct:
   case T_empty_aggregate_init:
   case T_default_new:
-  case T_sizeof:
+  case T_sizeof_type:
   case T_alignof:
     return _u._typecast._to < ot->_u._typecast._to;
 
+  case T_sizeof_expr:
+    return _u._typecast._op1 < ot->_u._typecast._op1;
+
   case T_trinary_operation:
     if (*_u._op._op3 != *ot->_u._op._op3) {
       return *_u._op._op3 < *ot->_u._op._op3;

+ 3 - 1
dtool/src/cppparser/cppExpression.h

@@ -52,7 +52,8 @@ public:
     T_empty_aggregate_init,
     T_new,
     T_default_new,
-    T_sizeof,
+    T_sizeof_type,
+    T_sizeof_expr,
     T_sizeof_ellipsis,
     T_alignof,
     T_unary_operation,
@@ -89,6 +90,7 @@ public:
   static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info);
   static CPPExpression type_trait(int trait, CPPType *type, CPPType *arg = nullptr);
   static CPPExpression sizeof_func(CPPType *type);
+  static CPPExpression sizeof_func(CPPExpression *op1);
   static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident);
   static CPPExpression alignof_func(CPPType *type);
   static CPPExpression lambda(CPPClosureType *type);

+ 11 - 1
dtool/src/cppparser/cppInstance.cxx

@@ -74,7 +74,17 @@ CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
   ii->_ident = nullptr;
   _storage_class = storage_class;
   _initializer = nullptr;
-  _bit_width = ii->_bit_width;
+
+  if (ii->_bit_width != nullptr) {
+    CPPExpression::Result result = ii->_bit_width->evaluate();
+    if (result._type != CPPExpression::RT_error) {
+      _bit_width = ii->_bit_width->evaluate().as_integer();
+    } else {
+      _bit_width = -1;
+    }
+  } else {
+    _bit_width = -1;
+  }
 
   CPPParameterList *params = ii->get_initializer();
   if (params != nullptr) {

+ 1 - 1
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -82,7 +82,7 @@ initializer_type(CPPParameterList *params) {
 CPPInstanceIdentifier::
 CPPInstanceIdentifier(CPPIdentifier *ident) :
   _ident(ident),
-  _bit_width(-1),
+  _bit_width(nullptr),
   _packed(false) {
 }
 

+ 2 - 2
dtool/src/cppparser/cppInstanceIdentifier.h

@@ -86,8 +86,8 @@ public:
   typedef std::vector<Modifier> Modifiers;
   Modifiers _modifiers;
 
-  // If not -1, indicates a bitfield
-  int _bit_width;
+  // If not null, indicates a bitfield
+  CPPExpression *_bit_width;
 
   // Indicates a parameter pack
   bool _packed;

+ 1 - 3
dtool/src/cppparser/cppManifest.cxx

@@ -127,9 +127,7 @@ CPPManifest(const string &macro, const string &definition) :
  */
 CPPManifest::
 ~CPPManifest() {
-  if (_expr != nullptr) {
-    delete _expr;
-  }
+  delete _expr;
 }
 
 /**

+ 2 - 2
dtool/src/dtoolbase/cmath.I

@@ -351,7 +351,7 @@ cnan(double v) {
 #if __FINITE_MATH_ONLY__
   // GCC's isnan breaks when using -ffast-math.
   union { double d; uint64_t x; } u = { v };
-  return ((u.x << 1) > 0xff70000000000000ull);
+  return ((u.x << 1) > 0xffe0000000000000ull);
 #elif !defined(_WIN32)
   return std::isnan(v);
 #else
@@ -383,7 +383,7 @@ cinf(double v) {
 #if __FINITE_MATH_ONLY__
   // GCC's isinf breaks when using -ffast-math.
   union { double d; uint64_t x; } u = { v };
-  return ((u.x << 1) == 0xff70000000000000ull);
+  return ((u.x << 1) == 0xffe0000000000000ull);
 #elif !defined(_WIN32)
   return std::isinf(v);
 #else

+ 6 - 2
dtool/src/dtoolbase/deletedChain.h

@@ -85,7 +85,9 @@ public:
     return ptr;                                              \
   }                                                          \
   inline void operator delete(void *ptr) {                   \
-    StaticDeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \
+    if (ptr != nullptr) {                                    \
+      StaticDeletedChain< Type >::deallocate((Type *)ptr, get_type_handle(Type)); \
+    }                                                        \
   }                                                          \
   inline void operator delete(void *, void *) {              \
   }                                                          \
@@ -104,7 +106,9 @@ public:
     return ptr;                                              \
   }                                                          \
   inline void operator delete(void *ptr) {                   \
-    _deleted_chain.deallocate((Type *)ptr, get_type_handle(Type)); \
+    if (ptr != nullptr) {                                    \
+      _deleted_chain.deallocate((Type *)ptr, get_type_handle(Type)); \
+    }                                                        \
   }                                                          \
   inline void operator delete(void *, void *) {              \
   }                                                          \

+ 6 - 2
dtool/src/dtoolbase/memoryBase.h

@@ -32,7 +32,9 @@
     return ptr;                                              \
   }                                                          \
   inline void operator delete(void *ptr) {                   \
-    PANDA_FREE_SINGLE(ptr);                                  \
+    if (ptr != nullptr) {                                    \
+      PANDA_FREE_SINGLE(ptr);                                \
+    }                                                        \
   }                                                          \
   inline void operator delete(void *, void *) {              \
   }                                                          \
@@ -44,7 +46,9 @@
     return ptr;                                              \
   }                                                          \
   inline void operator delete[](void *ptr) {                 \
-    PANDA_FREE_ARRAY(ptr);                                   \
+    if (ptr != nullptr) {                                    \
+      PANDA_FREE_ARRAY(ptr);                                 \
+    }                                                        \
   }                                                          \
   inline void operator delete[](void *, void *) {            \
   }

+ 0 - 10
dtool/src/dtoolbase/pandaVersion.h.in

@@ -61,13 +61,3 @@
 
 /* This is a string indicating who has provided this distribution. */
 #define PANDA_DISTRIBUTOR "@PANDA_DISTRIBUTOR@"
-
-/* The string indicating the version number of the associated Panda3D
-   distributable package, or empty string if there is no associated
-   package. */
-#define PANDA_PACKAGE_VERSION_STR "@PANDA_PACKAGE_VERSION@"
-
-/* The string indicating the URL from which the associated Panda3D
-   distributable package may be downloaded, or empty string if there
-   is no associated package. */
-#define PANDA_PACKAGE_HOST_URL "@PANDA_PACKAGE_HOST_URL@"

Some files were not shown because too many files changed in this diff