Browse Source

Merge branch 'shaderpipeline' into vulkan

rdb 3 năm trước cách đây
mục cha
commit
609f3bc696
100 tập tin đã thay đổi với 3468 bổ sung2287 xóa
  1. 112 48
      .github/workflows/ci.yml
  2. 3 11
      BACKERS.md
  3. 6 6
      README.md
  4. 1 1
      contrib/src/rplight/gpuCommandList.cxx
  5. 1 1
      contrib/src/rplight/gpuCommandList.h
  6. 5 5
      contrib/src/rplight/pssmCameraRig.I
  7. 10 8
      contrib/src/rplight/pssmCameraRig.cxx
  8. 5 5
      contrib/src/rplight/pssmCameraRig.h
  9. 2 2
      contrib/src/rplight/tagStateManager.I
  10. 1 1
      contrib/src/rplight/tagStateManager.h
  11. 8 8
      direct/src/actor/Actor.py
  12. 2 2
      direct/src/dcparser/dcClass.cxx
  13. 1 1
      direct/src/dcparser/dcPacker_ext.cxx
  14. 16 7
      direct/src/deadrec/smoothMover.I
  15. 38 14
      direct/src/dist/FreezeTool.py
  16. 66 19
      direct/src/dist/commands.py
  17. 30 0
      direct/src/dist/pefile.py
  18. 1 1
      direct/src/distributed/ConnectionRepository.py
  19. 3 2
      direct/src/distributed/cConnectionRepository.cxx
  20. 34 1
      direct/src/filter/CommonFilters.py
  21. 1 1
      direct/src/interval/Interval.py
  22. 1 1
      direct/src/interval/MetaInterval.py
  23. 1 1
      direct/src/interval/cInterval.cxx
  24. 170 72
      direct/src/motiontrail/MotionTrail.py
  25. 285 434
      direct/src/motiontrail/cMotionTrail.cxx
  26. 37 39
      direct/src/motiontrail/cMotionTrail.h
  27. 4 4
      direct/src/showbase/BufferViewer.py
  28. 26 6
      direct/src/showbase/ContainerLeakDetector.py
  29. 28 14
      direct/src/showbase/ContainerReport.py
  30. 5 2
      direct/src/showbase/EventManager.py
  31. 6 7
      direct/src/showbase/GarbageReport.py
  32. 1 1
      direct/src/showbase/Job.py
  33. 46 35
      direct/src/showbase/ShowBase.py
  34. 0 1
      direct/src/showutil/Effects.py
  35. 152 0
      doc/ReleaseNotes
  36. 301 1
      dtool/metalibs/dtoolconfig/pydtool.cxx
  37. 2 0
      dtool/src/cppparser/CMakeLists.txt
  38. 5 0
      dtool/src/cppparser/cppArrayType.cxx
  39. 196 0
      dtool/src/cppparser/cppAttributeList.cxx
  40. 65 0
      dtool/src/cppparser/cppAttributeList.h
  41. 916 952
      dtool/src/cppparser/cppBison.cxx.prebuilt
  42. 6 3
      dtool/src/cppparser/cppBison.h.prebuilt
  43. 256 203
      dtool/src/cppparser/cppBison.yxx
  44. 2 0
      dtool/src/cppparser/cppBisonDefs.h
  45. 4 0
      dtool/src/cppparser/cppClosureType.cxx
  46. 22 3
      dtool/src/cppparser/cppDeclaration.cxx
  47. 8 3
      dtool/src/cppparser/cppDeclaration.h
  48. 23 12
      dtool/src/cppparser/cppEnumType.cxx
  49. 6 3
      dtool/src/cppparser/cppEnumType.h
  50. 5 1
      dtool/src/cppparser/cppExtensionType.cxx
  51. 1 1
      dtool/src/cppparser/cppExtensionType.h
  52. 20 9
      dtool/src/cppparser/cppFunctionType.cxx
  53. 8 0
      dtool/src/cppparser/cppIdentifier.cxx
  54. 2 0
      dtool/src/cppparser/cppIdentifier.h
  55. 11 15
      dtool/src/cppparser/cppInstance.cxx
  56. 1 1
      dtool/src/cppparser/cppInstance.h
  57. 40 16
      dtool/src/cppparser/cppInstanceIdentifier.cxx
  58. 22 8
      dtool/src/cppparser/cppInstanceIdentifier.h
  59. 12 6
      dtool/src/cppparser/cppNamespace.cxx
  60. 1 1
      dtool/src/cppparser/cppNamespace.h
  61. 6 0
      dtool/src/cppparser/cppPointerType.cxx
  62. 2 2
      dtool/src/cppparser/cppPreprocessor.h
  63. 9 6
      dtool/src/cppparser/cppReferenceType.cxx
  64. 9 5
      dtool/src/cppparser/cppStructType.cxx
  65. 2 1
      dtool/src/cppparser/cppStructType.h
  66. 13 2
      dtool/src/cppparser/cppTypedefType.cxx
  67. 2 1
      dtool/src/cppparser/cppTypedefType.h
  68. 1 1
      dtool/src/cppparser/p3cppParser_composite1.cxx
  69. 9 5
      dtool/src/dtoolbase/CMakeLists.txt
  70. 52 0
      dtool/src/dtoolbase/deletedBufferChain.I
  71. 42 12
      dtool/src/dtoolbase/deletedBufferChain.cxx
  72. 17 3
      dtool/src/dtoolbase/deletedBufferChain.h
  73. 4 5
      dtool/src/dtoolbase/deletedChain.I
  74. 1 1
      dtool/src/dtoolbase/deletedChain.h
  75. 3 0
      dtool/src/dtoolbase/dtool_platform.h
  76. 5 21
      dtool/src/dtoolbase/dtoolbase.cxx
  77. 8 2
      dtool/src/dtoolbase/memoryHook.I
  78. 43 80
      dtool/src/dtoolbase/memoryHook.cxx
  79. 11 16
      dtool/src/dtoolbase/memoryHook.h
  80. 2 0
      dtool/src/dtoolbase/mutexSpinlockImpl.cxx
  81. 1 0
      dtool/src/dtoolbase/patomic.I
  82. 0 19
      dtool/src/dtoolbase/typeHandle.cxx
  83. 5 3
      dtool/src/dtoolbase/typeHandle.h
  84. 0 19
      dtool/src/dtoolbase/typeRegistry.cxx
  85. 0 3
      dtool/src/dtoolbase/typeRegistry.h
  86. 0 8
      dtool/src/dtoolbase/typedObject.I
  87. 0 2
      dtool/src/dtoolbase/typedObject.h
  88. 2 2
      dtool/src/dtoolutil/dSearchPath.h
  89. 4 0
      dtool/src/dtoolutil/executionEnvironment.cxx
  90. 32 21
      dtool/src/dtoolutil/filename.cxx
  91. 12 9
      dtool/src/dtoolutil/filename.h
  92. 10 10
      dtool/src/dtoolutil/textEncoder.h
  93. 23 2
      dtool/src/interrogate/functionRemap.cxx
  94. 26 11
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  95. 10 11
      dtool/src/interrogate/interrogate.cxx
  96. 5 1
      dtool/src/interrogate/interrogateBuilder.cxx
  97. 3 3
      dtool/src/interrogatedb/dtool_super_base.cxx
  98. 32 0
      dtool/src/interrogatedb/interrogateFunctionWrapper.I
  99. 9 1
      dtool/src/interrogatedb/interrogateFunctionWrapper.h
  100. 10 0
      dtool/src/interrogatedb/interrogateType.I

+ 112 - 48
.github/workflows/ci.yml

@@ -92,10 +92,10 @@ jobs:
     - name: Install dependencies (macOS)
       if: runner.os == 'macOS'
       run: |
-        curl -O https://www.panda3d.org/download/panda3d-1.10.10/panda3d-1.10.10-tools-mac.tar.gz
-        tar -xf panda3d-1.10.10-tools-mac.tar.gz
-        mv panda3d-1.10.10/thirdparty thirdparty
-        rmdir panda3d-1.10.10
+        curl -O https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-mac.tar.gz
+        tar -xf panda3d-1.10.13-tools-mac.tar.gz
+        mv panda3d-1.10.13/thirdparty thirdparty
+        rmdir panda3d-1.10.13
 
         # Temporary hack so that pzip can run, since we are about to remove Cg anyway.
         install_name_tool -id "$(pwd)/thirdparty/darwin-libs-a/nvidiacg/lib/libCg.dylib" thirdparty/darwin-libs-a/nvidiacg/lib/libCg.dylib
@@ -124,16 +124,16 @@ jobs:
       uses: actions/cache@v1
       with:
         path: thirdparty
-        key: ci-cmake-${{ runner.OS }}-thirdparty-v1.10.10-r1
+        key: ci-cmake-${{ runner.OS }}-thirdparty-v1.10.13-r1
     - name: Install dependencies (Windows)
       if: runner.os == 'Windows'
       shell: powershell
       run: |
         if (!(Test-Path thirdparty/win-libs-vc14-x64)) {
           $wc = New-Object System.Net.WebClient
-          $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.10/panda3d-1.10.10-tools-win64.zip", "thirdparty-tools.zip")
+          $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-win64.zip", "thirdparty-tools.zip")
           Expand-Archive -Path thirdparty-tools.zip
-          Move-Item -Path thirdparty-tools/panda3d-1.10.10/thirdparty -Destination .
+          Move-Item -Path thirdparty-tools/panda3d-1.10.13/thirdparty -Destination .
         }
 
     - name: ccache (non-Windows)
@@ -173,7 +173,7 @@ jobs:
         -D CMAKE_UNITY_BUILD=${{ matrix.unity }}
         -D CMAKE_BUILD_TYPE="${{ matrix.config }}"
         -D BUILD_METALIBS=${{ matrix.metalibs }}
-        -D HAVE_PYTHON=${{ matrix.python }}
+        -D HAVE_PYTHON=${{ runner.os != 'Windows' && matrix.python || 'NO' }}
         -D HAVE_EIGEN=${{ matrix.eigen }}
         ..
 
@@ -184,25 +184,25 @@ jobs:
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
 
-    - name: Setup Python (Python 3.6)
+    - name: Setup Python (Python 3.7)
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
-        python-version: 3.6
-    - name: Configure (Python 3.6)
+        python-version: '3.7'
+    - name: Configure (Python 3.7)
       if: contains(matrix.python, 'YES')
       working-directory: build
       shell: bash
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.6
+        cmake -DWANT_PYTHON_VERSION=3.7 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.6)
+    - name: Build (Python 3.7)
       if: contains(matrix.python, 'YES')
       # BEGIN A
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
-    - name: Test (Python 3.6)
+    - name: Test (Python 3.7)
       # BEGIN B
       if: contains(matrix.python, 'YES')
       working-directory: build
@@ -216,25 +216,25 @@ jobs:
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
       # END B
 
-    - name: Setup Python (Python 3.7)
+    - name: Setup Python (Python 3.8)
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
-        python-version: 3.7
-    - name: Configure (Python 3.7)
+        python-version: '3.8'
+    - name: Configure (Python 3.8)
       if: contains(matrix.python, 'YES')
       working-directory: build
       shell: bash
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.7
+        cmake -DWANT_PYTHON_VERSION=3.8 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.7)
+    - name: Build (Python 3.8)
       if: contains(matrix.python, 'YES')
       # BEGIN A
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
-    - name: Test (Python 3.7)
+    - name: Test (Python 3.8)
       # BEGIN B
       if: contains(matrix.python, 'YES')
       working-directory: build
@@ -248,25 +248,25 @@ jobs:
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
       # END B
 
-    - name: Setup Python (Python 3.8)
+    - name: Setup Python (Python 3.9)
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
-        python-version: 3.8
-    - name: Configure (Python 3.8)
+        python-version: '3.9'
+    - name: Configure (Python 3.9)
       if: contains(matrix.python, 'YES')
       working-directory: build
       shell: bash
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.8
+        cmake -DWANT_PYTHON_VERSION=3.9 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.8)
+    - name: Build (Python 3.9)
       if: contains(matrix.python, 'YES')
       # BEGIN A
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
-    - name: Test (Python 3.8)
+    - name: Test (Python 3.9)
       # BEGIN B
       if: contains(matrix.python, 'YES')
       working-directory: build
@@ -280,25 +280,57 @@ jobs:
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
       # END B
 
-    - name: Setup Python (Python 3.9)
+    - name: Setup Python (Python 3.10)
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
-        python-version: 3.9
-    - name: Configure (Python 3.9)
+        python-version: '3.10'
+    - name: Configure (Python 3.10)
       if: contains(matrix.python, 'YES')
       working-directory: build
       shell: bash
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.9
+        cmake -DWANT_PYTHON_VERSION=3.10 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.9)
+    - name: Build (Python 3.10)
       if: contains(matrix.python, 'YES')
       # BEGIN A
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
-    - name: Test (Python 3.9)
+    - name: Test (Python 3.10)
+      # 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 pytest-cov
+        export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
+        $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
+      # END B
+
+    - name: Setup Python (Python 3.11)
+      if: contains(matrix.python, 'YES')
+      uses: actions/setup-python@v4
+      with:
+        python-version: '3.11'
+    - name: Configure (Python 3.11)
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: >
+        cmake -DWANT_PYTHON_VERSION=3.11 -DHAVE_PYTHON=YES
+        -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
+    - name: Build (Python 3.11)
+      if: contains(matrix.python, 'YES')
+      # BEGIN A
+      working-directory: build
+      run: cmake --build . --config ${{ matrix.config }} --parallel 4
+      # END A
+    - name: Test (Python 3.11)
       # BEGIN B
       if: contains(matrix.python, 'YES')
       working-directory: build
@@ -347,21 +379,50 @@ jobs:
       shell: powershell
       run: |
         $wc = New-Object System.Net.WebClient
-        $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.11/panda3d-1.10.11-tools-win64.zip", "thirdparty-tools.zip")
+        $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-win64.zip", "thirdparty-tools.zip")
         Expand-Archive -Path thirdparty-tools.zip
-        Move-Item -Path thirdparty-tools/panda3d-1.10.11/thirdparty -Destination .
+        Move-Item -Path thirdparty-tools/panda3d-1.10.13/thirdparty -Destination .
     - name: Get thirdparty packages (macOS)
       if: runner.os == 'macOS'
       run: |
-        curl -O https://www.panda3d.org/download/panda3d-1.10.11/panda3d-1.10.11-tools-mac.tar.gz
-        tar -xf panda3d-1.10.11-tools-mac.tar.gz
-        mv panda3d-1.10.11/thirdparty thirdparty
-        rmdir panda3d-1.10.11
+        curl -O https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-mac.tar.gz
+        tar -xf panda3d-1.10.13-tools-mac.tar.gz
+        mv panda3d-1.10.13/thirdparty thirdparty
+        rmdir panda3d-1.10.13
         (cd thirdparty/darwin-libs-a && rm -rf rocket)
+
+    - name: Set up Python 3.11
+      uses: actions/setup-python@v4
+      with:
+        python-version: '3.11'
+    - name: Build Python 3.11
+      shell: bash
+      run: |
+        python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10
+    - name: Test Python 3.11
+      shell: bash
+      run: |
+        python -m pip install pytest
+        PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
+    - name: Set up Python 3.10
+      uses: actions/setup-python@v4
+      with:
+        python-version: '3.10'
+    - name: Build Python 3.10
+      shell: bash
+      run: |
+        python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10
+    - name: Test Python 3.10
+      shell: bash
+      run: |
+        python -m pip install pytest
+        PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
     - name: Set up Python 3.9
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
-        python-version: 3.9
+        python-version: '3.9'
     - name: Build Python 3.9
       shell: bash
       run: |
@@ -371,10 +432,11 @@ jobs:
       run: |
         python -m pip install pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
     - name: Set up Python 3.8
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
-        python-version: 3.8
+        python-version: '3.8'
     - name: Build Python 3.8
       shell: bash
       run: |
@@ -384,10 +446,11 @@ jobs:
       run: |
         python -m pip install pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
     - name: Set up Python 3.7
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
-        python-version: 3.7
+        python-version: '3.7'
     - name: Build Python 3.7
       shell: bash
       run: |
@@ -397,6 +460,7 @@ jobs:
       run: |
         python -m pip install pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
     - name: Make installer
       run: |
         python makepanda/makepackage.py --verbose --lzma

+ 3 - 11
BACKERS.md

@@ -2,20 +2,12 @@
 
 This is a list of all the people who are contributing financially to Panda3D.  If you'd like to join them, visit [our campaign on OpenCollective](https://opencollective.com/panda3d)!
 
-## Gold Sponsors
-
-![Gold Sponsors](https://opencollective.com/panda3d/tiers/gold-sponsor.svg?avatarHeight=48&width=600)
-
-* [tcdude](https://opencollective.com/tizilogic)
-
 ## Bronze Sponsors
 
 [<img src="https://www.panda3d.org/wp-content/uploads/2021/02/changecrab_logo.png" alt="ChangeCrab" height="48">](https://changecrab.com/) ![Bronze Sponsors](https://opencollective.com/panda3d/tiers/bronze-sponsor.svg?avatarHeight=48&width=600)
 
-* [Mitchell Stokes](https://opencollective.com/mitchell-stokes)
 * [Daniel Stokes](https://opencollective.com/daniel-stokes)
 * [David Rose](https://opencollective.com/david-rose)
-* [ChangeCrab](https://changecrab.com)
 
 ## Benefactors
 
@@ -24,17 +16,17 @@ This is a list of all the people who are contributing financially to Panda3D.  I
 * Sam Edwards
 * Max Voss
 * Hawkheart
-* Dan Mlodecki
+* Veronica
 
 ## Enthusiasts
 
 ![Enthusiasts](https://opencollective.com/panda3d/tiers/enthusiast.svg?avatarHeight=48&width=600)
 
 * Eric Thomson
-* Kyle Roach
 * Brian Lach
-* C0MPU73R
 * Maxwell Dreytser
+* SureBet
+* Gyedo Jeon
 
 ## Backers
 

+ 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-11/).
+[this page](https://www.panda3d.org/download/sdk-1-10-12/).
 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.11/panda3d-1.10.11-tools-win64.zip
-- https://www.panda3d.org/download/panda3d-1.10.11/panda3d-1.10.11-tools-win32.zip
+- https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-win64.zip
+- https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-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
@@ -80,10 +80,10 @@ makepanda\makepanda.bat --everything --installer --msvc-version=14.3 --windows-s
 When the build succeeds, it will produce an .exe file that you can use to
 install Panda3D on your system.
 
-Note: you may choose to remove --no-eigen and build with Eigen support in
+**Note:** you may choose to remove `--no-eigen` and build with Eigen support in
 order to improve runtime performance.  However, this will cause the build to
 take hours to complete, as Eigen is a heavily template-based library, and the
-the MSVC compiler does not perform well under these circumstances.
+MSVC compiler does not perform well under those circumstances.
 
 Linux
 -----
@@ -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.11/panda3d-1.10.11-tools-mac.tar.gz).
+compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.13/panda3d-1.10.13-tools-mac.tar.gz).
 
 After placing the thirdparty directory inside the panda3d source directory,
 you may build Panda3D using a command like the following:

+ 1 - 1
contrib/src/rplight/gpuCommandList.cxx

@@ -51,7 +51,7 @@ void GPUCommandList::add_command(const GPUCommand& cmd) {
  *   list, and are waiting to get processed.
  * @return Amount of commands
  */
-size_t GPUCommandList::get_num_commands() {
+size_t GPUCommandList::get_num_commands() const {
   return _commands.size();
 }
 

+ 1 - 1
contrib/src/rplight/gpuCommandList.h

@@ -42,7 +42,7 @@ PUBLISHED:
   GPUCommandList();
 
   void add_command(const GPUCommand& cmd);
-  size_t get_num_commands();
+  size_t get_num_commands() const;
   size_t write_commands_to(const PTA_uchar &dest, size_t limit = 32);
 
   MAKE_PROPERTY(num_commands, get_num_commands);

+ 5 - 5
contrib/src/rplight/pssmCameraRig.I

@@ -175,7 +175,7 @@ inline void PSSMCameraRig::reset_film_size_cache() {
  * @param index Index of the camera.
  * @return [description]
  */
-inline NodePath PSSMCameraRig::get_camera(size_t index) {
+inline NodePath PSSMCameraRig::get_camera(size_t index) const {
   nassertr(index >= 0 && index < _cam_nodes.size(), NodePath());
   return _cam_nodes[index];
 }
@@ -193,7 +193,7 @@ inline NodePath PSSMCameraRig::get_camera(size_t index) {
  * @param split_index The index of the split
  * @return Distance of the split, ranging from 0 .. 1
  */
-inline float PSSMCameraRig::get_split_start(size_t split_index) {
+inline float PSSMCameraRig::get_split_start(size_t split_index) const {
   float x = (float)split_index / (float)_cam_nodes.size();
   return (exp(_logarithmic_factor*x)-1) / (exp(_logarithmic_factor)-1);
 }
@@ -209,7 +209,7 @@ inline float PSSMCameraRig::get_split_start(size_t split_index) {
  *
  * @return interpolated point in world space
  */
-inline LPoint3 PSSMCameraRig::get_interpolated_point(CoordinateOrigin origin, float depth) {
+inline LPoint3 PSSMCameraRig::get_interpolated_point(CoordinateOrigin origin, float depth) const {
   nassertr(depth >= 0.0 && depth <= 1.0, LPoint3());
   return _curr_near_points[origin] * (1.0 - depth) + _curr_far_points[origin] * depth;
 }
@@ -222,7 +222,7 @@ inline LPoint3 PSSMCameraRig::get_interpolated_point(CoordinateOrigin origin, fl
  *
  * @return view-projection matrix array
  */
-inline const PTA_LMatrix4 &PSSMCameraRig::get_mvp_array() {
+inline const PTA_LMatrix4 &PSSMCameraRig::get_mvp_array() const {
   return _camera_mvps;
 }
 
@@ -238,6 +238,6 @@ inline const PTA_LMatrix4 &PSSMCameraRig::get_mvp_array() {
  *
  * @return Array of near and far planes
  */
-inline const PTA_LVecBase2 &PSSMCameraRig::get_nearfar_array() {
+inline const PTA_LVecBase2 &PSSMCameraRig::get_nearfar_array() const {
   return _camera_nearfar;
 }

+ 10 - 8
contrib/src/rplight/pssmCameraRig.cxx

@@ -296,9 +296,10 @@ void PSSMCameraRig::compute_pssm_splits(const LMatrix4& transform, float max_dis
 
     // Reset the film size, offset and far-plane
     Camera* cam = DCAST(Camera, _cam_nodes[i].node());
-    cam->get_lens()->set_film_size(1, 1);
-    cam->get_lens()->set_film_offset(0, 0);
-    cam->get_lens()->set_near_far(1, 100);
+    Lens *lens = cam->get_lens();
+    lens->set_film_size(1, 1);
+    lens->set_film_offset(0, 0);
+    lens->set_near_far(1, 100);
 
     // Find a good initial position
     _cam_nodes[i].set_pos(cam_start);
@@ -320,16 +321,16 @@ void PSSMCameraRig::compute_pssm_splits(const LMatrix4& transform, float max_dis
       if (_max_film_sizes[i].get_x() < film_size.get_x()) _max_film_sizes[i].set_x(film_size.get_x());
       if (_max_film_sizes[i].get_y() < film_size.get_y()) _max_film_sizes[i].set_y(film_size.get_y());
 
-      cam->get_lens()->set_film_size(_max_film_sizes[i] * filmsize_bias);
+      lens->set_film_size(_max_film_sizes[i] * filmsize_bias);
     } else {
       // If we don't use a fixed film size, we can just set the film size
       // on the lens.
-      cam->get_lens()->set_film_size(film_size * filmsize_bias);
+      lens->set_film_size(film_size * filmsize_bias);
     }
 
     // Compute new film offset
-    cam->get_lens()->set_film_offset(film_offset);
-    cam->get_lens()->set_near_far(10, best_max_extent.get_z());
+    lens->set_film_offset(film_offset);
+    lens->set_near_far(10, best_max_extent.get_z());
     _camera_nearfar[i] = LVecBase2(10, best_max_extent.get_z());
 
     // Compute the camera MVP
@@ -399,7 +400,8 @@ void PSSMCameraRig::update(NodePath cam_node, const LVecBase3 &light_vector) {
   }
 
   // Do the actual PSSM
-  compute_pssm_splits( transform, _pssm_distance / lens->get_far(), light_vector );
+  double far_recip = std::max(1.0 / (double)lens->get_far(), (double)lens_far_limit);
+  compute_pssm_splits( transform, _pssm_distance * far_recip, light_vector );
 
   _update_collector.stop();
 }

+ 5 - 5
contrib/src/rplight/pssmCameraRig.h

@@ -72,11 +72,11 @@ PUBLISHED:
   void update(NodePath cam_node, const LVecBase3 &light_vector);
   inline void reset_film_size_cache();
 
-  inline NodePath get_camera(size_t index);
+  inline NodePath get_camera(size_t index) const;
 
   void reparent_to(NodePath parent);
-  inline const PTA_LMatrix4 &get_mvp_array();
-  inline const PTA_LVecBase2 &get_nearfar_array();
+  inline const PTA_LMatrix4 &get_mvp_array() const;
+  inline const PTA_LVecBase2 &get_nearfar_array() const;
 
 public:
   // Used to access the near and far points in the array
@@ -91,9 +91,9 @@ protected:
   void init_cam_nodes();
   void compute_pssm_splits(const LMatrix4& transform, float max_distance,
                const LVecBase3 &light_vector);
-  inline float get_split_start(size_t split_index);
+  inline float get_split_start(size_t split_index) const;
   LMatrix4 compute_mvp(size_t cam_index);
-  inline LPoint3 get_interpolated_point(CoordinateOrigin origin, float depth);
+  inline LPoint3 get_interpolated_point(CoordinateOrigin origin, float depth) const;
   LVecBase3 get_snap_offset(const LMatrix4& mat, size_t resolution);
 
   std::vector<NodePath> _cam_nodes;

+ 2 - 2
contrib/src/rplight/tagStateManager.I

@@ -83,11 +83,11 @@ apply_state(const std::string& state, NodePath np, Shader* shader,
  * @return Bit mask of the render pass
  */
 inline BitMask32 TagStateManager::
-get_mask(const std::string &container_name) {
+get_mask(const std::string &container_name) const {
   if (container_name == "gbuffer") {
     return BitMask32::bit(1);
   }
-  ContainerList::iterator entry = _containers.find(container_name);
+  ContainerList::const_iterator entry = _containers.find(container_name);
   nassertr(entry != _containers.end(), BitMask32());
   return entry->second.mask;
 }

+ 1 - 1
contrib/src/rplight/tagStateManager.h

@@ -57,7 +57,7 @@ PUBLISHED:
 
   inline void register_camera(const std::string& state, Camera* source);
   inline void unregister_camera(const std::string& state, Camera* source);
-  inline BitMask32 get_mask(const std::string &container_name);
+  inline BitMask32 get_mask(const std::string &container_name) const;
 
 private:
   typedef std::vector<Camera*> CameraList;

+ 8 - 8
direct/src/actor/Actor.py

@@ -424,7 +424,7 @@ class Actor(DirectObject, NodePath):
                             subpartDef.subset.isIncludeEmpty(), subpartDef.subset)
 
     def __doListJoints(self, indentLevel, part, isIncluded, subset):
-        name = part.getName()
+        name = part.name
         if subset.matchesInclude(name):
             isIncluded = True
         elif subset.matchesExclude(name):
@@ -437,9 +437,9 @@ class Actor(DirectObject, NodePath):
                 part.outputValue(lineStream)
                 value = lineStream.getLine()
 
-            print(' '.join((' ' * indentLevel, part.getName(), value)))
+            print(' '.join((' ' * indentLevel, name, value)))
 
-        for child in part.getChildren():
+        for child in part.children:
             self.__doListJoints(indentLevel + 2, child, isIncluded, subset)
 
 
@@ -1206,11 +1206,11 @@ class Actor(DirectObject, NodePath):
 
         return jointsA & jointsB
 
-    def __getPartJoints(self, joints, pattern, partNode, subset, isIncluded):
+    def __getPartJoints(self, joints, pattern, part, subset, isIncluded):
         """ Recursively walks the joint hierarchy to look for matching
         joint names, implementing getJoints(). """
 
-        name = partNode.getName()
+        name = part.name
         if subset:
             # Constrain the traversal just to the named subset.
             if subset.matchesInclude(name):
@@ -1218,10 +1218,10 @@ class Actor(DirectObject, NodePath):
             elif subset.matchesExclude(name):
                 isIncluded = False
 
-        if isIncluded and pattern.matches(name) and isinstance(partNode, MovingPartBase):
-            joints.append(partNode)
+        if isIncluded and pattern.matches(name) and isinstance(part, MovingPartBase):
+            joints.append(part)
 
-        for child in partNode.getChildren():
+        for child in part.children:
             self.__getPartJoints(joints, pattern, child, subset, isIncluded)
 
     def getJointTransform(self, partName, jointName, lodName='lodRoot'):

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

@@ -24,8 +24,8 @@ using std::string;
 
 #ifdef WITHIN_PANDA
 #ifndef CPPPARSER
-PStatCollector DCClass::_update_pcollector("App:Show code:readerPollTask:Update");
-PStatCollector DCClass::_generate_pcollector("App:Show code:readerPollTask:Generate");
+PStatCollector DCClass::_update_pcollector("App:Tasks:readerPollTask:Update");
+PStatCollector DCClass::_generate_pcollector("App:Tasks:readerPollTask:Generate");
 #endif  // CPPPARSER
 
 ConfigVariableBool dc_multiple_inheritance

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

@@ -195,7 +195,7 @@ unpack_object() {
   case PT_uint:
     {
       unsigned int value = _this->unpack_uint();
-      object = PyLong_FromLong(value);
+      object = PyLong_FromUnsignedLong(value);
     }
     break;
 

+ 16 - 7
direct/src/deadrec/smoothMover.I

@@ -23,7 +23,7 @@
  */
 INLINE bool SmoothMover::
 set_pos(const LVecBase3 &pos) {
-  return set_x(pos[0]) | set_y(pos[1]) | set_z(pos[2]);
+  return set_pos(pos[0], pos[1], pos[2]);
 }
 
 /**
@@ -38,7 +38,10 @@ set_pos(const LVecBase3 &pos) {
  */
 INLINE bool SmoothMover::
 set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) {
-  return set_x(x) | set_y(y) | set_z(z);
+  bool x_changed = set_x(x);
+  bool y_changed = set_y(y);
+  bool z_changed = set_z(z);
+  return x_changed || y_changed || z_changed;
 }
 
 /**
@@ -98,7 +101,7 @@ set_z(PN_stdfloat z) {
  */
 INLINE bool SmoothMover::
 set_hpr(const LVecBase3 &hpr) {
-  return set_h(hpr[0]) | set_p(hpr[1]) | set_r(hpr[2]);
+  return set_hpr(hpr[0], hpr[1], hpr[2]);
 }
 
 /**
@@ -113,7 +116,10 @@ set_hpr(const LVecBase3 &hpr) {
  */
 INLINE bool SmoothMover::
 set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) {
-  return set_h(h) | set_p(p) | set_r(r);
+  bool h_changed = set_h(h);
+  bool p_changed = set_p(p);
+  bool r_changed = set_r(r);
+  return h_changed || p_changed || r_changed;
 }
 
 /**
@@ -173,8 +179,9 @@ set_r(PN_stdfloat r) {
  */
 INLINE bool SmoothMover::
 set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr) {
-  return (set_x(pos[0]) | set_y(pos[1]) | set_z(pos[2]) |
-          set_h(hpr[0]) | set_p(hpr[1]) | set_r(hpr[2]));
+  bool pos_changed = set_pos(pos);
+  bool hpr_changed = set_hpr(hpr);
+  return pos_changed || hpr_changed;
 }
 
 /**
@@ -189,7 +196,9 @@ set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr) {
  */
 INLINE bool SmoothMover::
 set_pos_hpr(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) {
-  return set_x(x) | set_y(y) | set_z(z) | set_h(h) | set_p(p) | set_r(r);
+  bool pos_changed = set_pos(x, y, z);
+  bool hpr_changed = set_hpr(h, p, r);
+  return pos_changed || hpr_changed;
 }
 
 /**

+ 38 - 14
direct/src/dist/FreezeTool.py

@@ -81,6 +81,12 @@ defaultHiddenImports = {
     'pandas.compat': ['lzma', 'cmath'],
     'pandas._libs.tslibs.conversion': ['pandas._libs.tslibs.base'],
     'plyer': ['plyer.platforms'],
+    'scipy.linalg': ['scipy.linalg.cython_blas', 'scipy.linalg.cython_lapack'],
+    'scipy.sparse.csgraph': ['scipy.sparse.csgraph._validation'],
+    'scipy.spatial._qhull': ['scipy._lib.messagestream'],
+    'scipy.spatial.transform._rotation': ['scipy.spatial.transform._rotation_groups'],
+    'scipy.special._ufuncs': ['scipy.special._ufuncs_cxx'],
+    'scipy.stats._stats': ['scipy.special.cython_special'],
 }
 
 
@@ -781,7 +787,7 @@ class Freezer:
             return 'ModuleDef(%s)' % (', '.join(args))
 
     def __init__(self, previous = None, debugLevel = 0,
-                 platform = None, path=None, hiddenImports=None):
+                 platform = None, path=None, hiddenImports=None, optimize=None):
         # Normally, we are freezing for our own platform.  Change this
         # if untrue.
         self.platform = platform or PandaSystem.getPlatform()
@@ -911,7 +917,13 @@ class Freezer:
                     ('.so', 'rb', 3),
                 ]
 
-        self.mf = PandaModuleFinder(excludes=['doctest'], suffixes=suffixes, path=path)
+        if optimize is None or optimize < 0:
+            self.optimize = sys.flags.optimize
+        else:
+            self.optimize = optimize
+
+        self.mf = PandaModuleFinder(excludes=['doctest'], suffixes=suffixes,
+                                    path=path, optimize=self.optimize)
 
     def excludeFrom(self, freezer):
         """ Excludes all modules that have already been processed by
@@ -1189,22 +1201,31 @@ class Freezer:
 
         # Special case for sysconfig, which depends on a platform-specific
         # sysconfigdata module on POSIX systems.
-        if 'sysconfig' in self.mf.modules:
+        missing = []
+        if 'sysconfig' in self.mf.modules and \
+           ('linux' in self.platform or 'mac' in self.platform):
+            modname = '_sysconfigdata'
             if sys.version_info >= (3, 6):
+                modname += '_'
+                if sys.version_info < (3, 8):
+                    modname += 'm'
+
                 if 'linux' in self.platform:
                     arch = self.platform.split('_', 1)[1]
-                    self.__loadModule(self.ModuleDef('_sysconfigdata__linux_' + arch + '-linux-gnu', implicit=True))
+                    modname += '_linux_' + arch + '-linux-gnu'
                 elif 'mac' in self.platform:
-                    self.__loadModule(self.ModuleDef('_sysconfigdata__darwin_darwin', implicit=True))
-            elif 'linux' in self.platform or 'mac' in self.platform:
-                self.__loadModule(self.ModuleDef('_sysconfigdata', implicit=True))
+                    modname += '_darwin_darwin'
+
+            try:
+                self.__loadModule(self.ModuleDef(modname, implicit=True))
+            except:
+                missing.append(modname)
 
         # Now, any new modules we found get added to the export list.
         for origName in list(self.mf.modules.keys()):
             if origName not in origToNewName:
                 self.modules[origName] = self.ModuleDef(origName, implicit = True)
 
-        missing = []
         for origName in self.mf.any_missing_maybe()[0]:
             if origName in startupModules:
                 continue
@@ -1398,7 +1419,7 @@ class Freezer:
                 else:
                     filename += '.pyo'
                 if multifile.findSubfile(filename) < 0:
-                    code = compile('', moduleName, 'exec', optimize=2)
+                    code = compile('', moduleName, 'exec', optimize=self.optimize)
                     self.__addPyc(multifile, filename, code, compressionLevel)
 
             moduleDirs[str] = True
@@ -1478,7 +1499,7 @@ class Freezer:
                 source = open(sourceFilename.toOsSpecific(), 'r').read()
                 if source and source[-1] != '\n':
                     source = source + '\n'
-                code = compile(source, str(sourceFilename), 'exec', optimize=2)
+                code = compile(source, str(sourceFilename), 'exec', optimize=self.optimize)
 
         self.__addPyc(multifile, filename, code, compressionLevel)
 
@@ -1557,7 +1578,7 @@ class Freezer:
             # trouble importing it as a builtin module.  Synthesize a frozen
             # module that loads it as builtin.
             if '.' in moduleName and self.linkExtensionModules:
-                code = compile('import sys;del sys.modules["%s"];import imp;imp.init_builtin("%s")' % (moduleName, moduleName), moduleName, 'exec', optimize=2)
+                code = compile('import sys;del sys.modules["%s"];import imp;imp.init_builtin("%s")' % (moduleName, moduleName), moduleName, 'exec', optimize=self.optimize)
                 code = marshal.dumps(code)
                 mangledName = self.mangleName(moduleName)
                 moduleDefs.append(self.makeModuleDef(mangledName, code))
@@ -1830,7 +1851,7 @@ class Freezer:
                     code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(sys.path[0], "%s%s"))' % (moduleName, moduleName, moduleName, modext)
                 else:
                     code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(os.path.dirname(sys.executable), "%s%s"))' % (moduleName, moduleName, moduleName, modext)
-                code = compile(code, moduleName, 'exec', optimize=2)
+                code = compile(code, moduleName, 'exec', optimize=self.optimize)
                 code = marshal.dumps(code)
                 moduleList.append((moduleName, len(pool), len(code)))
                 pool += code
@@ -1931,6 +1952,8 @@ class Freezer:
                 flags |= 1
             if log_filename_strftime:
                 flags |= 2
+            if self.optimize < 2:
+                flags |= 4 # keep_docstrings
 
             # Compose the header we will be writing to the stub, to tell it
             # where to find the module data blob, as well as other variables.
@@ -2362,6 +2385,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
         """
 
         self.suffixes = kw.pop('suffixes', imp.get_suffixes())
+        self.optimize = kw.pop('optimize', -1)
 
         modulefinder.ModuleFinder.__init__(self, *args, **kw)
 
@@ -2515,7 +2539,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
 
         if type is _PKG_NAMESPACE_DIRECTORY:
             m = self.add_module(fqname)
-            m.__code__ = compile('', '', 'exec', optimize=2)
+            m.__code__ = compile('', '', 'exec', optimize=self.optimize)
             m.__path__ = pathname
             return m
 
@@ -2527,7 +2551,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
                 code = fp.read()
 
             code += b'\n' if isinstance(code, bytes) else '\n'
-            co = compile(code, pathname, 'exec', optimize=2)
+            co = compile(code, pathname, 'exec', optimize=self.optimize)
         elif type == imp.PY_COMPILED:
             if sys.version_info >= (3, 7):
                 try:

+ 66 - 19
direct/src/dist/commands.py

@@ -49,24 +49,39 @@ def _parse_dict(input):
     return d
 
 
+def _register_python_loaders():
+    # We need this method so that we don't depend on direct.showbase.Loader.
+    if getattr(_register_python_loaders, 'done', None):
+        return
 
-def egg2bam(_build_cmd, srcpath, dstpath):
+    _register_python_loaders.done = True
+
+    registry = p3d.LoaderFileTypeRegistry.getGlobalPtr()
+
+    for entry_point in pkg_resources.iter_entry_points('panda3d.loaders'):
+        registry.register_deferred_type(entry_point)
+
+
+def _model_to_bam(_build_cmd, srcpath, dstpath):
     if dstpath.endswith('.gz') or dstpath.endswith('.pz'):
         dstpath = dstpath[:-3]
     dstpath = dstpath + '.bam'
-    try:
-        subprocess.check_call([
-            'egg2bam',
-            '-o', dstpath,
-            '-pd', os.path.dirname(os.path.abspath(srcpath)),
-            '-ps', 'rel',
-            srcpath
-        ])
-    except FileNotFoundError:
-        raise RuntimeError('egg2bam failed: egg2bam was not found in the PATH')
-    except (subprocess.CalledProcessError, OSError) as err:
-        raise RuntimeError('egg2bam failed: {}'.format(err))
-    return dstpath
+
+    src_fn = p3d.Filename.from_os_specific(srcpath)
+    dst_fn = p3d.Filename.from_os_specific(dstpath)
+
+    _register_python_loaders()
+
+    loader = p3d.Loader.get_global_ptr()
+    options = p3d.LoaderOptions(p3d.LoaderOptions.LF_report_errors |
+                                p3d.LoaderOptions.LF_no_ram_cache)
+    node = loader.load_sync(src_fn, options)
+    if not node:
+        raise IOError('Failed to load model: %s' % (srcpath))
+
+    if not p3d.NodePath(node).write_bam_file(dst_fn):
+        raise IOError('Failed to write .bam file: %s' % (dstpath))
+
 
 macosx_binary_magics = (
     b'\xFE\xED\xFA\xCE', b'\xCE\xFA\xED\xFE',
@@ -243,7 +258,6 @@ class build_apps(setuptools.Command):
         ('platforms=', 'p', 'a list of platforms to build for'),
     ]
     default_file_handlers = {
-        '.egg': egg2bam,
     }
 
     def initialize_options(self):
@@ -277,13 +291,16 @@ class build_apps(setuptools.Command):
         self.log_filename = None
         self.log_filename_strftime = True
         self.log_append = False
+        self.prefer_discrete_gpu = False
         self.requirements_path = os.path.join(os.getcwd(), 'requirements.txt')
+        self.strip_docstrings = True
         self.use_optimized_wheels = True
         self.optimized_wheel_index = ''
         self.pypi_extra_indexes = [
             'https://archive.panda3d.org/thirdparty',
         ]
         self.file_handlers = {}
+        self.bam_model_extensions = ['.egg', '.gltf', '.glb']
         self.exclude_dependencies = [
             # Windows
             'kernel32.dll', 'user32.dll', 'wsock32.dll', 'ws2_32.dll',
@@ -444,6 +461,15 @@ class build_apps(setuptools.Command):
         for glob in self.exclude_dependencies:
             glob.case_sensitive = False
 
+        # bam_model_extensions registers a 2bam handler for each given extension.
+        # They can override a default handler, but not a custom handler.
+        if self.bam_model_extensions:
+            for ext in self.bam_model_extensions:
+                ext = '.' + ext.lstrip('.')
+                assert ext not in self.file_handlers, \
+                    'Extension {} occurs in both file_handlers and bam_model_extensions!'.format(ext)
+                self.file_handlers[ext] = _model_to_bam
+
         tmp = self.default_file_handlers.copy()
         tmp.update(self.file_handlers)
         self.file_handlers = tmp
@@ -625,11 +651,16 @@ class build_apps(setuptools.Command):
             self.icon_objects.get('*', None),
         )
 
-        if icon is not None:
+        if icon is not None or self.prefer_discrete_gpu:
             pef = pefile.PEFile()
             pef.open(runtime, 'r+')
-            pef.add_icon(icon)
-            pef.add_resource_section()
+            if icon is not None:
+                pef.add_icon(icon)
+                pef.add_resource_section()
+            if self.prefer_discrete_gpu:
+                if not pef.rename_export("SymbolPlaceholder___________________", "AmdPowerXpressRequestHighPerformance") or \
+                   not pef.rename_export("SymbolPlaceholder__", "NvOptimusEnablement"):
+                    self.warn("Failed to apply prefer_discrete_gpu, newer target Panda3D version may be required")
             pef.write_changes()
             pef.close()
 
@@ -944,7 +975,8 @@ class build_apps(setuptools.Command):
             freezer = FreezeTool.Freezer(
                 platform=platform,
                 path=path,
-                hiddenImports=self.hidden_imports
+                hiddenImports=self.hidden_imports,
+                optimize=2 if self.strip_docstrings else 1
             )
             freezer.addModule('__main__', filename=mainscript)
             if platform.startswith('android'):
@@ -1617,6 +1649,10 @@ class bdist_apps(setuptools.Command):
         'manylinux_2_24_ppc64': ['gztar'],
         'manylinux_2_24_ppc64le': ['gztar'],
         'manylinux_2_24_s390x': ['gztar'],
+        'manylinux_2_28_x86_64': ['gztar'],
+        'manylinux_2_28_aarch64': ['gztar'],
+        'manylinux_2_28_ppc64le': ['gztar'],
+        'manylinux_2_28_s390x': ['gztar'],
         'android': ['aab'],
         # Everything else defaults to ['zip']
     }
@@ -1710,3 +1746,14 @@ class bdist_apps(setuptools.Command):
                     continue
 
                 self.installer_functions[installer](self, basename, build_dir)
+
+
+def finalize_distribution_options(dist):
+    """Entry point for compatibility with setuptools>=61, see #1394."""
+
+    options = dist.get_option_dict('build_apps')
+    if options.get('gui_apps') or options.get('console_apps'):
+        # Make sure this is set to avoid auto-discovery taking place.
+        if getattr(dist.metadata, 'py_modules', None) is None and \
+           getattr(dist.metadata, 'packages', None) is None:
+            dist.py_modules = []

+ 30 - 0
direct/src/dist/pefile.py

@@ -600,6 +600,36 @@ class PEFile(object):
         if self.res_rva.addr and self.res_rva.size:
             self.resources.unpack_from(self.vmem, self.res_rva.addr)
 
+    def _mark_address_modified(self, rva):
+        for section in self.sections:
+            if rva >= section.vaddr and rva - section.vaddr <= section.size:
+                section.modified = True
+
+    def rename_export(self, old_name, new_name):
+        """ Renames a symbol in the export table. """
+
+        assert len(new_name) <= len(old_name)
+
+        new_name = new_name.ljust(len(old_name) + 1, '\0').encode('ascii')
+
+        start = self.exp_rva.addr
+        expdir = expdirtab(*unpack('<IIHHIIIIIII', self.vmem[start:start+40]))
+        if expdir.nnames == 0 or expdir.ordinals == 0 or expdir.names == 0:
+            return False
+
+        nptr = expdir.names
+        for i in range(expdir.nnames):
+            name_rva, = unpack('<I', self.vmem[nptr:nptr+4])
+            if name_rva != 0:
+                name = _unpack_zstring(self.vmem, name_rva)
+                if name == old_name:
+                    self.vmem[name_rva:name_rva+len(new_name)] = new_name
+                    self._mark_address_modified(name_rva)
+                    return True
+            nptr += 4
+
+        return False
+
     def get_export_address(self, symbol_name):
         """ Finds the virtual address for a named export symbol. """
 

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

@@ -120,7 +120,7 @@ class ConnectionRepository(
 
         self._serverAddress = ''
 
-        if self.config.GetBool('gc-save-all', 1):
+        if self.config.GetBool('gc-save-all', 0):
             # set gc to preserve every object involved in a cycle, even ones that
             # would normally be freed automatically during garbage collect
             # allows us to find and fix these cycles, reducing or eliminating the

+ 3 - 2
direct/src/distributed/cConnectionRepository.cxx

@@ -35,7 +35,7 @@ using std::string;
 const string CConnectionRepository::_overflow_event_name = "CRDatagramOverflow";
 
 #ifndef CPPPARSER
-PStatCollector CConnectionRepository::_update_pcollector("App:Show code:readerPollTask:Update");
+PStatCollector CConnectionRepository::_update_pcollector("App:Tasks:readerPollTask:Update");
 #endif  // CPPPARSER
 
 /**
@@ -580,7 +580,8 @@ flush() {
 
   #ifdef HAVE_OPENSSL
   if (_http_conn) {
-    return _http_conn->flush();
+    _http_conn->flush();
+    return !_http_conn->is_closed();
   }
   #endif  // HAVE_OPENSSL
 

+ 34 - 1
direct/src/filter/CommonFilters.py

@@ -17,7 +17,7 @@ These filters are written in the Cg shading language.
 # clunky approach.  - Josh
 
 from panda3d.core import LVecBase4, LPoint2
-from panda3d.core import AuxBitplaneAttrib
+from panda3d.core import AuxBitplaneAttrib, AntialiasAttrib
 from panda3d.core import Texture, Shader, ATSNone
 from panda3d.core import FrameBufferProperties
 from panda3d.core import getDefaultCoordinateSystem, CS_zup_right, CS_zup_left
@@ -189,11 +189,22 @@ class CommonFilters:
                 fbprops.setSrgbColor(False)
                 clamping = False
 
+            if "MSAA" in configuration:
+                if fbprops is None:
+                    fbprops = FrameBufferProperties()
+                fbprops.setMultisamples(configuration["MSAA"].samples)
+
             self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits, fbprops=fbprops, clamping=clamping)
             if self.finalQuad is None:
                 self.cleanup()
                 return False
 
+            if "MSAA" in configuration:
+                camNode = self.manager.camera.node()
+                state = camNode.getInitialState()
+                state.setAttrib(AntialiasAttrib.make(AntialiasAttrib.M_multisample))
+                camNode.setInitialState(state)
+
             if "BlurSharpen" in configuration:
                 blur0 = self.textures["blur0"]
                 blur1 = self.textures["blur1"]
@@ -454,6 +465,26 @@ class CommonFilters:
         if task is not None:
             return task.cont
 
+    def setMSAA(self, samples):
+        """Enables multisample anti-aliasing on the render-to-texture buffer.
+        If you enable this, it is recommended to leave any multisample request
+        on the main framebuffer OFF (ie. don't set framebuffer-multisample true
+        in Config.prc), since it would be a waste of resources otherwise.
+
+        .. versionadded:: 1.10.13
+        """
+        fullrebuild = "MSAA" not in self.configuration or self.configuration["MSAA"].samples != samples
+        newconfig = FilterConfig()
+        newconfig.samples = samples
+        self.configuration["MSAA"] = newconfig
+        return self.reconfigure(fullrebuild, "MSAA")
+
+    def delMSAA(self):
+        if "MSAA" in self.configuration:
+            del self.configuration["MSAA"]
+            return self.reconfigure(True, "MSAA")
+        return True
+
     def setCartoonInk(self, separation=1, color=(0, 0, 0, 1)):
         fullrebuild = ("CartoonInk" not in self.configuration)
         newconfig = FilterConfig()
@@ -679,6 +710,8 @@ class CommonFilters:
         return True
 
     #snake_case alias:
+    set_msaa = setMSAA
+    del_msaa = delMSAA
     del_cartoon_ink = delCartoonInk
     set_half_pixel_shift = setHalfPixelShift
     del_half_pixel_shift = delHalfPixelShift

+ 1 - 1
direct/src/interval/Interval.py

@@ -41,7 +41,7 @@ class Interval(DirectObject):
         self.pstats = None
         if __debug__ and TaskManager.taskTimerVerbose:
             self.pname = name.split('-', 1)[0]
-            self.pstats = PStatCollector("App:Show code:ivalLoop:%s" % (self.pname))
+            self.pstats = PStatCollector("App:Tasks:ivalLoop:%s" % (self.pname))
 
         # Set true if the interval should be invoked if it was
         # completely skipped over during initialize or finalize, false

+ 1 - 1
direct/src/interval/MetaInterval.py

@@ -106,7 +106,7 @@ class MetaInterval(CMetaInterval):
         self.pstats = None
         if __debug__ and TaskManager.taskTimerVerbose:
             self.pname = name.split('-', 1)[0]
-            self.pstats = PStatCollector("App:Show code:ivalLoop:%s" % (self.pname))
+            self.pstats = PStatCollector("App:Tasks:ivalLoop:%s" % (self.pname))
 
         self.pythonIvals = []
 

+ 1 - 1
direct/src/interval/cInterval.cxx

@@ -22,7 +22,7 @@
 using std::ostream;
 using std::string;
 
-PStatCollector CInterval::_root_pcollector("App:Show code:ivalLoop");
+PStatCollector CInterval::_root_pcollector("App:Tasks:ivalLoop");
 TypeHandle CInterval::_type_handle;
 
 static inline string

+ 170 - 72
direct/src/motiontrail/MotionTrail.py

@@ -47,6 +47,30 @@ class MotionTrailFrame:
 
 
 class MotionTrail(NodePath, DirectObject):
+    """Generates smooth geometry-based motion trails behind a moving object.
+
+    To use this class, first define the shape of the cross-section polygon that
+    is to be extruded along the motion trail by calling `add_vertex()` and
+    `set_vertex_color()`.  When this is done, call `update_vertices()`.
+
+    To generate the motion trail, either call `register_motion_trail()`
+    to have Panda update it automatically, or periodically call the method
+    `update_motion_trail()` with the current time and the new transform.
+
+    The duration of the sample history is specified by `time_window`.  A larger
+    time window creates longer motion trails (given constant speed).  Samples
+    that are no longer within the time window are automatically discarded.
+
+    The `use_nurbs` option can be used to create smooth interpolated curves
+    from the samples.  This option is useful for animations that lack sampling
+    to begin with, animations that move very quickly, or low frame rates, or if
+    `sampling_time` is used to artificially slow down the update frequency.
+
+    By default, the optimized C++ implementation (provided by `.CMotionTrail`)
+    is used to generate the motion trails.  If for some reason you want to use
+    the pure-Python implementation instead, set `want-python-motion-trails` to
+    true in Config.prc.
+    """
 
     notify = directNotify.newCategory("MotionTrail")
 
@@ -58,9 +82,16 @@ class MotionTrail(NodePath, DirectObject):
 
     @classmethod
     def setGlobalEnable(cls, enable):
+        """Set this to False to have the task stop updating all motion trails.
+        This does not prevent updating them manually using the
+        `update_motion_trail()` method.
+        """
         cls.global_enable = enable
 
     def __init__(self, name, parent_node_path):
+        """Creates the motion trail with the given name and parents it to the
+        given root node.
+        """
         NodePath.__init__(self, name)
 
         # required initialization
@@ -91,8 +122,17 @@ class MotionTrail(NodePath, DirectObject):
         # default options
         self.continuous_motion_trail = True
         self.color_scale = 1.0
+
+        #: How long the time window is for which the trail is computed.  Can be
+        #: increased to obtain a longer trail, decreased for a shorter trail.
         self.time_window = 1.0
+
+        #: How often the trail updates, in seconds.  The default is 0.0, which
+        #: has the trail updated every frame for the smoothest result.  Higher
+        #: values will generate a choppier trail.  The `use_nurbs` option can
+        #: compensate partially for this choppiness, however.
         self.sampling_time = 0.0
+
         self.square_t = True
 
 #        self.task_transform = False
@@ -100,7 +140,12 @@ class MotionTrail(NodePath, DirectObject):
 
         # node path states
         self.reparentTo(parent_node_path)
+
+        #: A `.GeomNode` object containing the generated geometry.  By default
+        #: parented to the MotionTrail itself, but can be reparented elsewhere
+        #: if necessary.
         self.geom_node = GeomNode("motion_trail")
+        self.geom_node.setBoundsType(BoundingVolume.BT_box)
         self.geom_node_path = self.attachNewNode(self.geom_node)
         node_path = self.geom_node_path
 
@@ -127,10 +172,13 @@ class MotionTrail(NodePath, DirectObject):
 
             MotionTrail.task_added = True
 
-
         self.relative_to_render = False
 
+        #: Set this to True to use a NURBS curve to generate a smooth trail,
+        #: even if the underlying animation or movement is janky.
         self.use_nurbs = False
+
+        #: This can be changed to fine-tune the resolution of the NURBS curve.
         self.resolution_distance = 0.5
 
         self.cmotion_trail = CMotionTrail()
@@ -142,14 +190,13 @@ class MotionTrail(NodePath, DirectObject):
         else:
             self.use_python_version = False
 
-        return
-
     def delete(self):
+        """Completely cleans up the motion trail object.
+        """
         self.reset_motion_trail()
         self.reset_motion_trail_geometry()
         self.cmotion_trail.resetVertexList()
         self.removeNode()
-        return
 
     def print_matrix(self, matrix):
         separator = ' '
@@ -206,11 +253,32 @@ class MotionTrail(NodePath, DirectObject):
 
         return Task.cont
 
-    def add_vertex(self, vertex_id, vertex_function, context):
-        motion_trail_vertex = MotionTrailVertex(vertex_id, vertex_function, context)
+    def add_vertex(self, vertex_id, vertex_function=None, context=None, *,
+                   start_color=(1.0, 1.0, 1.0, 1.0), end_color=(0.0, 0.0, 0.0, 1.0)):
+        """This must be called initially to define the polygon that forms the
+        cross-section of the generated motion trail geometry.  The first
+        argument is a user-defined vertex identifier, the second is a function
+        that will be called with three parameters that should return the
+        position of the vertex as a `.Vec4` object, and the third is an
+        arbitrary context object that is passed as last argument to the
+        provided function.
+
+        After calling this, you must call `update_vertices()` before the
+        changes will fully take effect.
+
+        As of Panda3D 1.10.13, you may alternatively simply pass in a single
+        argument containing the vertex position as a `.Vec4` or `.Point3`.
+        """
+        if vertex_function is None:
+            motion_trail_vertex = MotionTrailVertex(None, None, context)
+            motion_trail_vertex.vertex = Vec4(vertex_id)
+        else:
+            motion_trail_vertex = MotionTrailVertex(vertex_id, vertex_function, context)
+        motion_trail_vertex.start_color = Vec4(start_color)
+        motion_trail_vertex.end_color = Vec4(end_color)
         total_vertices = len(self.vertex_list)
 
-        self.vertex_list [total_vertices : total_vertices] = [motion_trail_vertex]
+        self.vertex_list[total_vertices : total_vertices] = [motion_trail_vertex]
 
         self.total_vertices = len(self.vertex_list)
 
@@ -219,15 +287,24 @@ class MotionTrail(NodePath, DirectObject):
         return motion_trail_vertex
 
     def set_vertex_color(self, vertex_id, start_color, end_color):
+        """Sets the start and end color of the vertex with the given index,
+        which must have been previously added by `add_vertex()`.  The motion
+        trail will contain a smooth gradient between these colors.  By default,
+        the motion trail fades from white to black (which, with the default
+        additive blending mode, makes it show up as a purely white motion trail
+        that fades out towards the end).
+        """
         if vertex_id >= 0 and vertex_id < self.total_vertices:
-            motion_trail_vertex = self.vertex_list [vertex_id]
+            motion_trail_vertex = self.vertex_list[vertex_id]
             motion_trail_vertex.start_color = start_color
             motion_trail_vertex.end_color = end_color
 
         self.modified_vertices = True
-        return
 
     def set_texture(self, texture):
+        """Defines the texture that should be applied to the trail geometry.
+        This also enables generation of UV coordinates.
+        """
         self.texture = texture
         if texture:
             self.geom_node_path.setTexture(texture)
@@ -237,17 +314,21 @@ class MotionTrail(NodePath, DirectObject):
             self.geom_node_path.clearTexture()
 
         self.modified_vertices = True
-        return
 
     def update_vertices(self):
+        """This must be called after the list of vertices defining the
+        cross-section shape of the motion trail has been defined by
+        `add_vertex()` and `set_vertex_color()`.
+        """
         total_vertices = len(self.vertex_list)
 
         self.total_vertices = total_vertices
         if total_vertices >= 2:
             vertex_index = 0
             while vertex_index < total_vertices:
-                motion_trail_vertex = self.vertex_list [vertex_index]
-                motion_trail_vertex.vertex = motion_trail_vertex.vertex_function(motion_trail_vertex, motion_trail_vertex.vertex_id, motion_trail_vertex.context)
+                motion_trail_vertex = self.vertex_list[vertex_index]
+                if motion_trail_vertex.vertex_function is not None:
+                    motion_trail_vertex.vertex = motion_trail_vertex.vertex_function(motion_trail_vertex, motion_trail_vertex.vertex_id, motion_trail_vertex.context)
                 vertex_index += 1
 
             # calculate v coordinate
@@ -257,7 +338,7 @@ class MotionTrail(NodePath, DirectObject):
             float_total_vertices = 0.0
             float_total_vertices = total_vertices - 1.0
             while vertex_index < total_vertices:
-                motion_trail_vertex = self.vertex_list [vertex_index]
+                motion_trail_vertex = self.vertex_list[vertex_index]
                 motion_trail_vertex.v = float_vertex_index / float_total_vertices
                 vertex_index += 1
                 float_vertex_index += 1.0
@@ -265,7 +346,6 @@ class MotionTrail(NodePath, DirectObject):
 #                print "motion_trail_vertex.v", motion_trail_vertex.v
 
         self.modified_vertices = True
-        return
 
     def transferVertices(self):
 
@@ -278,22 +358,24 @@ class MotionTrail(NodePath, DirectObject):
             vertex_index = 0
             total_vertices = len(self.vertex_list)
             while vertex_index < total_vertices:
-                motion_trail_vertex = self.vertex_list [vertex_index]
+                motion_trail_vertex = self.vertex_list[vertex_index]
                 self.cmotion_trail.addVertex(motion_trail_vertex.vertex, motion_trail_vertex.start_color, motion_trail_vertex.end_color, motion_trail_vertex.v)
                 vertex_index += 1
 
             self.modified_vertices = False
 
-        return
-
     def register_motion_trail(self):
+        """Adds this motion trail to the list of trails that are updated
+        automatically every frame.  Be careful not to call this twice.
+        """
         MotionTrail.motion_trail_list = MotionTrail.motion_trail_list + [self]
-        return
 
     def unregister_motion_trail(self):
+        """Removes this motion trail from the list of trails that are updated
+        automatically every frame.  If it is not on that list, does nothing.
+        """
         if self in MotionTrail.motion_trail_list:
             MotionTrail.motion_trail_list.remove(self)
-        return
 
     def begin_geometry(self):
         self.vertex_index = 0
@@ -314,21 +396,21 @@ class MotionTrail(NodePath, DirectObject):
 
     def add_geometry_quad(self, v0, v1, v2, v3, c0, c1, c2, c3, t0, t1, t2, t3):
 
-        self.vertex_writer.addData3f(v0 [0], v0 [1], v0 [2])
-        self.vertex_writer.addData3f(v1 [0], v1 [1], v1 [2])
-        self.vertex_writer.addData3f(v2 [0], v2 [1], v2 [2])
-        self.vertex_writer.addData3f(v3 [0], v3 [1], v3 [2])
+        self.vertex_writer.addData3(v0[0], v0[1], v0[2])
+        self.vertex_writer.addData3(v1[0], v1[1], v1[2])
+        self.vertex_writer.addData3(v2[0], v2[1], v2[2])
+        self.vertex_writer.addData3(v3[0], v3[1], v3[2])
 
-        self.color_writer.addData4f(c0)
-        self.color_writer.addData4f(c1)
-        self.color_writer.addData4f(c2)
-        self.color_writer.addData4f(c3)
+        self.color_writer.addData4(c0)
+        self.color_writer.addData4(c1)
+        self.color_writer.addData4(c2)
+        self.color_writer.addData4(c3)
 
         if self.texture is not None:
-            self.texture_writer.addData2f(t0)
-            self.texture_writer.addData2f(t1)
-            self.texture_writer.addData2f(t2)
-            self.texture_writer.addData2f(t3)
+            self.texture_writer.addData2(t0)
+            self.texture_writer.addData2(t1)
+            self.texture_writer.addData2(t2)
+            self.texture_writer.addData2(t3)
 
         vertex_index = self.vertex_index
 
@@ -352,7 +434,10 @@ class MotionTrail(NodePath, DirectObject):
         self.geom_node.addGeom(self.geometry)
 
     def check_for_update(self, current_time):
-
+        """Returns true if the motion trail is overdue for an update based on
+        the configured `sampling_time` (by default 0.0 to update continuously),
+        and is not currently paused.
+        """
         state = False
         if (current_time - self.last_update_time) >= self.sampling_time:
             state = True
@@ -365,9 +450,12 @@ class MotionTrail(NodePath, DirectObject):
         return state
 
     def update_motion_trail(self, current_time, transform):
-
+        """If the trail is overdue for an update based on the given time in
+        seconds, updates it, extracting the new object position from the given
+        transform matrix.
+        """
         if len(self.frame_list) >= 1:
-            if transform == self.frame_list [0].transform:
+            if transform == self.frame_list[0].transform:
                 # ignore duplicate transform updates
                 return
 
@@ -378,7 +466,7 @@ class MotionTrail(NodePath, DirectObject):
                 elapsed_time = current_time - self.fade_start_time
 
                 if elapsed_time < 0.0:
-                    print("elapsed_time < 0: %f" %(elapsed_time))
+                    print("elapsed_time < 0: %f" % (elapsed_time))
                     elapsed_time = 0.0
 
                 if elapsed_time < self.fade_time:
@@ -397,13 +485,13 @@ class MotionTrail(NodePath, DirectObject):
             last_frame_index = len(self.frame_list) - 1
 
             while index <= last_frame_index:
-                motion_trail_frame = self.frame_list [last_frame_index - index]
+                motion_trail_frame = self.frame_list[last_frame_index - index]
                 if motion_trail_frame.time >= minimum_time:
                     break
                 index += 1
 
             if index > 0:
-                self.frame_list [last_frame_index - index: last_frame_index + 1] = []
+                self.frame_list[last_frame_index - index: last_frame_index + 1] = []
 
             # add new frame to beginning of list
             motion_trail_frame = MotionTrailFrame(current_time, transform)
@@ -416,15 +504,14 @@ class MotionTrail(NodePath, DirectObject):
             #
             #index = 0
             #while index < total_frames:
-            #    motion_trail_frame = self.frame_list [index]
+            #    motion_trail_frame = self.frame_list[index]
             #    print("frame time", index, motion_trail_frame.time)
             #    index += 1
 
-            if (total_frames >= 2) and(self.total_vertices >= 2):
-
+            if total_frames >= 2 and self.total_vertices >= 2:
                 self.begin_geometry()
                 total_segments = total_frames - 1
-                last_motion_trail_frame = self.frame_list [total_segments]
+                last_motion_trail_frame = self.frame_list[total_segments]
                 minimum_time = last_motion_trail_frame.time
                 delta_time = current_time - minimum_time
 
@@ -432,7 +519,7 @@ class MotionTrail(NodePath, DirectObject):
                     inverse_matrix = Mat4(transform)
                     inverse_matrix.invertInPlace()
 
-                if self.use_nurbs and(total_frames >= 5):
+                if self.use_nurbs and total_frames >= 5:
 
                     total_distance = 0.0
                     vector = Vec3()
@@ -452,10 +539,10 @@ class MotionTrail(NodePath, DirectObject):
                     # add vertices to each NurbsCurveEvaluator
                     segment_index = 0
                     while segment_index < total_segments:
-                        motion_trail_frame_start = self.frame_list [segment_index]
-                        motion_trail_frame_end = self.frame_list [segment_index + 1]
+                        motion_trail_frame_start = self.frame_list[segment_index]
+                        motion_trail_frame_end = self.frame_list[segment_index + 1]
 
-                        vertex_segement_index = 0
+                        vertex_segment_index = 0
 
                         if self.calculate_relative_matrix:
                             start_transform = Mat4()
@@ -468,34 +555,34 @@ class MotionTrail(NodePath, DirectObject):
                             start_transform = motion_trail_frame_start.transform
                             end_transform = motion_trail_frame_end.transform
 
-                        motion_trail_vertex_start = self.vertex_list [0]
+                        motion_trail_vertex_start = self.vertex_list[0]
 
                         v0 = start_transform.xform(motion_trail_vertex_start.vertex)
                         v2 = end_transform.xform(motion_trail_vertex_start.vertex)
 
-                        nurbs_curve_evaluator = nurbs_curve_evaluator_list [vertex_segement_index]
+                        nurbs_curve_evaluator = nurbs_curve_evaluator_list [vertex_segment_index]
 
                         nurbs_curve_evaluator.setVertex(segment_index, v0)
 
-                        while vertex_segement_index < total_vertex_segments:
+                        while vertex_segment_index < total_vertex_segments:
 
-                            motion_trail_vertex_start = self.vertex_list [vertex_segement_index]
-                            motion_trail_vertex_end = self.vertex_list [vertex_segement_index + 1]
+                            motion_trail_vertex_start = self.vertex_list[vertex_segment_index]
+                            motion_trail_vertex_end = self.vertex_list[vertex_segment_index + 1]
 
                             v1 = start_transform.xform(motion_trail_vertex_end.vertex)
                             v3 = end_transform.xform(motion_trail_vertex_end.vertex)
 
-                            nurbs_curve_evaluator = nurbs_curve_evaluator_list [vertex_segement_index + 1]
+                            nurbs_curve_evaluator = nurbs_curve_evaluator_list [vertex_segment_index + 1]
 
                             nurbs_curve_evaluator.setVertex(segment_index, v1)
 
-                            if vertex_segement_index == (total_vertex_segments - 1):
+                            if vertex_segment_index == (total_vertex_segments - 1):
                                 v = v1 - v3
                                 vector.set(v[0], v[1], v[2])
                                 distance = vector.length()
                                 total_distance += distance
 
-                            vertex_segement_index += 1
+                            vertex_segment_index += 1
 
                         segment_index += 1
 
@@ -531,7 +618,7 @@ class MotionTrail(NodePath, DirectObject):
                     curve_segment_index = 0.0
                     while curve_segment_index < total_curve_segments:
 
-                        vertex_segement_index = 0
+                        vertex_segment_index = 0
 
                         st = curve_segment_index / total_curve_segments
                         et = (curve_segment_index + 1.0) / total_curve_segments
@@ -545,7 +632,7 @@ class MotionTrail(NodePath, DirectObject):
                             start_t *= start_t
                             end_t *= end_t
 
-                        motion_trail_vertex_start = self.vertex_list [0]
+                        motion_trail_vertex_start = self.vertex_list[0]
 
                         vertex_start_color = motion_trail_vertex_start.end_color + (motion_trail_vertex_start.start_color - motion_trail_vertex_start.end_color)
                         color_start_t = color_scale * start_t
@@ -556,13 +643,13 @@ class MotionTrail(NodePath, DirectObject):
                         t0 = Vec2(one_minus_x(st), motion_trail_vertex_start.v)
                         t2 = Vec2(one_minus_x(et), motion_trail_vertex_start.v)
 
-                        while vertex_segement_index < total_vertex_segments:
+                        while vertex_segment_index < total_vertex_segments:
 
-                            motion_trail_vertex_start = self.vertex_list [vertex_segement_index]
-                            motion_trail_vertex_end = self.vertex_list [vertex_segement_index + 1]
+                            motion_trail_vertex_start = self.vertex_list[vertex_segment_index]
+                            motion_trail_vertex_end = self.vertex_list[vertex_segment_index + 1]
 
-                            start_nurbs_curve_result = nurbs_curve_result_list [vertex_segement_index]
-                            end_nurbs_curve_result = nurbs_curve_result_list [vertex_segement_index + 1]
+                            start_nurbs_curve_result = nurbs_curve_result_list [vertex_segment_index]
+                            end_nurbs_curve_result = nurbs_curve_result_list [vertex_segment_index + 1]
 
                             start_nurbs_start_t = start_nurbs_curve_result.getStartT()
                             start_nurbs_end_t = start_nurbs_curve_result.getEndT()
@@ -597,17 +684,15 @@ class MotionTrail(NodePath, DirectObject):
                             t0 = t1
                             t2 = t3
 
-                            vertex_segement_index += 1
+                            vertex_segment_index += 1
 
                         curve_segment_index += 1.0
 
-
                 else:
-
                     segment_index = 0
                     while segment_index < total_segments:
-                        motion_trail_frame_start = self.frame_list [segment_index]
-                        motion_trail_frame_end = self.frame_list [segment_index + 1]
+                        motion_trail_frame_start = self.frame_list[segment_index]
+                        motion_trail_frame_end = self.frame_list[segment_index + 1]
 
                         start_t = (motion_trail_frame_start.time - minimum_time) / delta_time
                         end_t = (motion_trail_frame_end.time - minimum_time) / delta_time
@@ -619,7 +704,7 @@ class MotionTrail(NodePath, DirectObject):
                             start_t *= start_t
                             end_t *= end_t
 
-                        vertex_segement_index = 0
+                        vertex_segment_index = 0
                         total_vertex_segments = self.total_vertices - 1
 
                         if self.calculate_relative_matrix:
@@ -631,7 +716,7 @@ class MotionTrail(NodePath, DirectObject):
                             start_transform = motion_trail_frame_start.transform
                             end_transform = motion_trail_frame_end.transform
 
-                        motion_trail_vertex_start = self.vertex_list [0]
+                        motion_trail_vertex_start = self.vertex_list[0]
 
                         v0 = start_transform.xform(motion_trail_vertex_start.vertex)
                         v2 = end_transform.xform(motion_trail_vertex_start.vertex)
@@ -645,10 +730,10 @@ class MotionTrail(NodePath, DirectObject):
                         t0 = Vec2(st, motion_trail_vertex_start.v)
                         t2 = Vec2(et, motion_trail_vertex_start.v)
 
-                        while vertex_segement_index < total_vertex_segments:
+                        while vertex_segment_index < total_vertex_segments:
 
-                            motion_trail_vertex_start = self.vertex_list [vertex_segement_index]
-                            motion_trail_vertex_end = self.vertex_list [vertex_segement_index + 1]
+                            motion_trail_vertex_start = self.vertex_list[vertex_segment_index]
+                            motion_trail_vertex_end = self.vertex_list[vertex_segment_index + 1]
 
                             v1 = start_transform.xform(motion_trail_vertex_end.vertex)
                             v3 = end_transform.xform(motion_trail_vertex_end.vertex)
@@ -675,24 +760,37 @@ class MotionTrail(NodePath, DirectObject):
                             t0 = t1
                             t2 = t3
 
-                            vertex_segement_index += 1
+                            vertex_segment_index += 1
 
                         segment_index += 1
 
                 self.end_geometry()
 
     def enable_motion_trail(self, enable):
+        """Sets whether the motion trail is currently enabled.  Every motion
+        trail starts off as being enabled, passing False to this method prevents
+        it from being updated.
+        """
         self.enable = enable
 
     def reset_motion_trail(self):
+        """Call this to have the motion trail restart from nothing on the next
+        update.
+        """
         self.frame_list = []
         self.cmotion_trail.reset()
 
     def reset_motion_trail_geometry(self):
+        """Destroys the currently generated motion trail geometry immediately.
+        However, it will be fully regenerated on the next call to update, see
+        `reset_motion_trail()` to prevent this.
+        """
         if self.geom_node is not None:
             self.geom_node.removeAllGeoms()
 
     def attach_motion_trail(self):
+        """Alias of `reset_motion_trail()`.
+        """
         self.reset_motion_trail()
 
     def begin_motion_trail(self):
@@ -733,7 +831,7 @@ class MotionTrail(NodePath, DirectObject):
             frame_index = 0
             total_frames = len(self.frame_list)
             while frame_index < total_frames:
-                motion_trail_frame = self.frame_list [frame_index]
+                motion_trail_frame = self.frame_list[frame_index]
                 motion_trail_frame.time += delta_time
                 frame_index += 1
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 285 - 434
direct/src/motiontrail/cMotionTrail.cxx


+ 37 - 39
direct/src/motiontrail/cMotionTrail.h

@@ -21,13 +21,11 @@
 #include "geomVertexWriter.h"
 #include "geomTriangles.h"
 #include "luse.h"
-#include "memoryBase.h"
 #include "nurbsCurveEvaluator.h"
 #include "plist.h"
 #include "epvector.h"
 
-class CMotionTrailVertex : public MemoryBase {
-public:
+struct CMotionTrailVertex : public MemoryBase {
   LPoint4 _vertex;
   LVecBase4 _start_color;
   LVecBase4 _end_color;
@@ -36,9 +34,8 @@ public:
   PT(NurbsCurveEvaluator) _nurbs_curve_evaluator;
 };
 
-class CMotionTrailFrame {
-public:
-  UnalignedLMatrix4 _transform;
+struct CMotionTrailFrame : public MemoryBase {
+  LMatrix4 _transform;
   PN_stdfloat _time;
 };
 
@@ -72,8 +69,8 @@ public:
  */
 class EXPCL_DIRECT_MOTIONTRAIL CMotionTrail : public TypedReferenceCount {
 PUBLISHED:
-  CMotionTrail();
-  ~CMotionTrail();
+  CMotionTrail() = default;
+  ~CMotionTrail() = default;
 
   void reset();
   void reset_vertex_list();
@@ -81,64 +78,66 @@ PUBLISHED:
   void enable(bool enable);
 
   void set_geom_node(GeomNode *geom_node);
-  void add_vertex(LVector4 *vertex, LVector4 *start_color, LVector4 *end_color, PN_stdfloat v);
+  void add_vertex(const LVector4 &vertex, const LVector4 &start_color,
+                  const LVector4 &end_color, PN_stdfloat v);
 
-  void set_parameters(PN_stdfloat sampling_time, PN_stdfloat time_window, bool use_texture, bool calculate_relative_matrix, bool use_nurbs, PN_stdfloat resolution_distance);
+  void set_parameters(PN_stdfloat sampling_time, PN_stdfloat time_window,
+                      bool use_texture, bool calculate_relative_matrix,
+                      bool use_nurbs, PN_stdfloat resolution_distance);
 
   int check_for_update(PN_stdfloat current_time);
-  void update_motion_trail(PN_stdfloat current_time, LMatrix4 *transform);
+  void update_motion_trail(PN_stdfloat current_time, const LMatrix4 &transform);
 
 public:
+  void begin_geometry(int num_quads);
+  void add_geometry_quad(
+    const LPoint3 &v0, const LPoint3 &v1, const LPoint3 &v2, const LPoint3 &v3,
+    const LVector4 &c0, const LVector4 &c1, const LVector4 &c2, const LVector4 &c3,
+    const LVector2 &t0, const LVector2 &t1, const LVector2 &t2, const LVector2 &t3);
+  void end_geometry(const LPoint3 &min_vertex, const LPoint3 &max_vertex);
 
-  void begin_geometry();
-  void add_geometry_quad(LVector3 &v0, LVector3 &v1, LVector3 &v2, LVector3 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
-  void add_geometry_quad(LVector4 &v0, LVector4 &v1, LVector4 &v2, LVector4 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
-  void end_geometry();
-
-  int _active;
-  int _enable;
+  bool _active = true;
+  bool _enable = true;
 
-  int _pause;
-  PN_stdfloat _pause_time;
+  bool _pause = false;
+  PN_stdfloat _pause_time = 0.0f;
 
-  int _fade;
-  int _fade_end;
-  PN_stdfloat _fade_time;
-  PN_stdfloat _fade_start_time;
-  PN_stdfloat _fade_color_scale;
+  bool _fade = false;
+  bool _fade_end = false;
+  PN_stdfloat _fade_time = 0.0f;
+  PN_stdfloat _fade_start_time = 0.0f;
+  PN_stdfloat _fade_color_scale = 1.0f;
 
-  PN_stdfloat _last_update_time;
+  PN_stdfloat _last_update_time = 0.0f;
 
   typedef epvector<CMotionTrailVertex> VertexList;
   VertexList _vertex_list;
-  typedef plist<CMotionTrailFrame> FrameList;
+  typedef pdeque<CMotionTrailFrame> FrameList;
   FrameList _frame_list;
+  PN_stdfloat _vertex_bounds_radius = 0.0f;
 
   // parameters
-  PN_stdfloat _color_scale;
-  PN_stdfloat _sampling_time;
-  PN_stdfloat _time_window;
-  bool _square_t;
-  bool _use_texture;
-  int _calculate_relative_matrix;
+  PN_stdfloat _color_scale = 1.0f;
+  PN_stdfloat _sampling_time = 0.0f;
+  PN_stdfloat _time_window = 1.0f;
+  bool _square_t = true;
+  bool _use_texture = false;
+  bool _calculate_relative_matrix = false;
 
   // nurbs parameters
-  bool _use_nurbs;
-  PN_stdfloat _resolution_distance;
+  bool _use_nurbs = false;
+  PN_stdfloat _resolution_distance = 0.5f;
 
   // geom
   PT(GeomNode) _geom_node;
 
   // real-time data
-  int _vertex_index;
   PT(GeomVertexData) _vertex_data;
   GeomVertexWriter _vertex_writer;
   GeomVertexWriter _color_writer;
   GeomVertexWriter _texture_writer;
   PT(GeomTriangles) _triangles;
 
-  CMotionTrailVertex *_vertex_array;
-
 public:
   static TypeHandle get_class_type() {
     return _type_handle;
@@ -155,7 +154,6 @@ public:
 
 private:
   static TypeHandle _type_handle;
-
 };
 
 #endif

+ 4 - 4
direct/src/showbase/BufferViewer.py

@@ -240,10 +240,10 @@ class BufferViewer(DirectObject):
             offsetx = (ringoffset[ring]*2.0) / float(sizex)
             offsety = (ringoffset[ring]*2.0) / float(sizey)
             bright = ringbright[ring]
-            vwriter.addData3f(Vec3.rfu(-1 - offsetx, 0, -1 - offsety))
-            vwriter.addData3f(Vec3.rfu( 1 + offsetx, 0, -1 - offsety))
-            vwriter.addData3f(Vec3.rfu( 1 + offsetx, 0,  1 + offsety))
-            vwriter.addData3f(Vec3.rfu(-1 - offsetx, 0,  1 + offsety))
+            vwriter.addData3f(Vec3F.rfu(-1 - offsetx, 0, -1 - offsety))
+            vwriter.addData3f(Vec3F.rfu( 1 + offsetx, 0, -1 - offsety))
+            vwriter.addData3f(Vec3F.rfu( 1 + offsetx, 0,  1 + offsety))
+            vwriter.addData3f(Vec3F.rfu(-1 - offsetx, 0,  1 + offsety))
             cwriter.addData3f(bright, bright, bright)
             cwriter.addData3f(bright, bright, bright)
             cwriter.addData3f(bright, bright, bright)

+ 26 - 6
direct/src/showbase/ContainerLeakDetector.py

@@ -11,12 +11,15 @@ import weakref
 import random
 import builtins
 
-deadEndTypes = (bool, types.BuiltinFunctionType,
-                types.BuiltinMethodType, complex,
-                float, int,
-                type(None), type(NotImplemented),
-                type, types.CodeType, types.FunctionType,
-                bytes, str, tuple)
+deadEndTypes = frozenset((
+    types.BuiltinFunctionType, types.BuiltinMethodType,
+    types.CodeType, types.FunctionType,
+    types.GeneratorType, types.CoroutineType,
+    types.AsyncGeneratorType,
+    bool, complex, float, int, type,
+    bytes, str, list, tuple,
+    type(None), type(NotImplemented)
+))
 
 
 def _createContainerLeak():
@@ -547,6 +550,23 @@ class FindContainers(Job):
                 # if we hit a dead end, start over from another container
                 curObjRef = None
 
+                # types.CellType was added in Python 3.8
+                if sys.version_info >= (3, 8) and type(curObj) is types.CellType:
+                    child = curObj.cell_contents
+                    hasLength = self._hasLength(child)
+                    notDeadEnd = not self._isDeadEnd(child)
+                    if hasLength or notDeadEnd:
+                        objRef = ObjectRef(Indirection(evalStr='.cell_contents'),
+                                           id(child), parentObjRef)
+                        yield None
+                        if hasLength:
+                            for i in self._addContainerGen(child, objRef):
+                                yield None
+                        if notDeadEnd:
+                            self._addDiscoveredStartRef(child, objRef)
+                            curObjRef = objRef
+                    continue
+
                 if hasattr(curObj, '__dict__'):
                     child = curObj.__dict__
                     hasLength = self._hasLength(child)

+ 28 - 14
direct/src/showbase/ContainerReport.py

@@ -3,7 +3,10 @@ from direct.showbase.PythonUtil import Queue, invertDictLossless
 from direct.showbase.PythonUtil import safeRepr
 from direct.showbase.Job import Job
 from direct.showbase.JobManagerGlobal import jobMgr
+from direct.showbase.ContainerLeakDetector import deadEndTypes
 import types
+import sys
+import io
 
 
 class ContainerReport(Job):
@@ -89,14 +92,6 @@ class ContainerReport(Job):
             if isinstance(parentObj, (str, bytes)):
                 continue
 
-            if type(parentObj) in (types.ModuleType, types.InstanceType):
-                child = parentObj.__dict__
-                if self._examine(child):
-                    assert self._queue.back() is child
-                    self._instanceDictIds.add(id(child))
-                    self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)])
-                continue
-
             if isinstance(parentObj, dict):
                 key = None
                 attr = None
@@ -126,7 +121,25 @@ class ContainerReport(Job):
                 del attr
                 continue
 
-            if type(parentObj) is not types.FileType:
+            # types.CellType was added in Python 3.8
+            if sys.version_info >= (3, 8) and type(parentObj) is types.CellType:
+                child = parentObj.cell_contents
+                if self._examine(child):
+                    assert (self._queue.back() is child)
+                    self._instanceDictIds.add(id(child))
+                    self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)]) + '.cell_contents'
+                continue
+
+            if hasattr(parentObj, '__dict__'):
+                # Instance of a class
+                child = parentObj.__dict__
+                if self._examine(child):
+                    assert (self._queue.back() is child)
+                    self._instanceDictIds.add(id(child))
+                    self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)])
+                continue
+
+            if not isinstance(parentObj, io.TextIOWrapper):
                 try:
                     itr = iter(parentObj)
                 except:
@@ -161,7 +174,10 @@ class ContainerReport(Job):
                 childName = None
                 child = None
                 for childName in childNames:
-                    child = getattr(parentObj, childName)
+                    try:
+                        child = getattr(parentObj, childName)
+                    except:
+                        continue
                     if id(child) not in self._visitedIds:
                         self._visitedIds.add(id(child))
                         if self._examine(child):
@@ -198,9 +214,7 @@ class ContainerReport(Job):
             self._type2id2len[type(obj)][objId] = length
     def _examine(self, obj):
         # return False if it's an object that can't contain or lead to other objects
-        if type(obj) in (bool, types.BuiltinFunctionType, types.BuiltinMethodType,
-                         complex, float, int, type(None), type(NotImplemented),
-                         type, types.CodeType, types.FunctionType):
+        if type(obj) in deadEndTypes:
             return False
         # if it's an internal object, ignore it
         if id(obj) in ContainerReport.PrivateIds:
@@ -243,7 +257,7 @@ class ContainerReport(Job):
             for i in self._outputType(type, **kArgs):
                 yield None
         otherTypes = list(set(self._type2id2len.keys()).difference(set(initialTypes)))
-        otherTypes.sort()
+        otherTypes.sort(key=lambda obj: obj.__name__)
         for type in otherTypes:
             for i in self._outputType(type, **kArgs):
                 yield None

+ 5 - 2
direct/src/showbase/EventManager.py

@@ -137,11 +137,11 @@ class EventManager:
             hyphen = name.find('-')
             if hyphen >= 0:
                 name = name[0:hyphen]
-            pstatCollector = PStatCollector('App:Show code:eventManager:' + name)
+            pstatCollector = PStatCollector('App:Tasks:eventManager:' + name)
             pstatCollector.start()
             if self.eventHandler:
                 cppPstatCollector = PStatCollector(
-                    'App:Show code:eventManager:' + name + ':C++')
+                    'App:Tasks:eventManager:' + name + ':C++')
 
             messenger.send(eventName, paramList)
 
@@ -180,3 +180,6 @@ class EventManager:
         # since the task removal itself might also fire off an event.
         if self.eventQueue is not None:
             self.eventQueue.clear()
+
+    do_events = doEvents
+    process_event = processEvent

+ 6 - 7
direct/src/showbase/GarbageReport.py

@@ -8,9 +8,8 @@ from direct.showbase.PythonUtil import itype, deeptype, fastRepr
 from direct.showbase.Job import Job
 from direct.showbase.JobManagerGlobal import jobMgr
 from direct.showbase.MessengerGlobal import messenger
-import direct.showbase.DConfig as config
+from panda3d.core import ConfigVariableBool
 import gc
-import types
 
 GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num'
 
@@ -213,7 +212,7 @@ class GarbageReport(Job):
                     startIndex = 0
                     # + 1 to include a reference back to the first object
                     endIndex = numObjs + 1
-                    if type(objs[-1]) is types.InstanceType and type(objs[0]) is dict:
+                    if type(objs[0]) is dict and hasattr(objs[-1], '__dict__'):
                         startIndex -= 1
                         endIndex -= 1
 
@@ -222,7 +221,7 @@ class GarbageReport(Job):
                             numToSkip -= 1
                             continue
                         obj = objs[index]
-                        if type(obj) is types.InstanceType:
+                        if hasattr(obj, '__dict__'):
                             if not objAlreadyRepresented:
                                 cycleBySyntax += '%s' % obj.__class__.__name__
                             cycleBySyntax += '.'
@@ -307,7 +306,7 @@ class GarbageReport(Job):
             while n > 0:
                 yield None
                 digits += 1
-                n /= 10
+                n = n // 10
             digits = digits
             format = '%0' + '%s' % digits + 'i:%s \t%s'
 
@@ -562,7 +561,7 @@ class _CFGLGlobals:
 def checkForGarbageLeaks():
     gc.collect()
     numGarbage = len(gc.garbage)
-    if numGarbage > 0 and config.GetBool('auto-garbage-logging', 0):
+    if numGarbage > 0 and ConfigVariableBool('auto-garbage-logging', False):
         if numGarbage != _CFGLGlobals.LastNumGarbage:
             print("")
             gr = GarbageReport('found garbage', threaded=False, collect=False)
@@ -572,7 +571,7 @@ def checkForGarbageLeaks():
             messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
             gr.destroy()
         notify = directNotify.newCategory("GarbageDetect")
-        if config.GetBool('allow-garbage-cycles', 1):
+        if ConfigVariableBool('allow-garbage-cycles', True):
             func = notify.warning
         else:
             func = notify.error

+ 1 - 1
direct/src/showbase/Job.py

@@ -35,7 +35,7 @@ class Job(DirectObject):
         self._priority = Job.Priorities.Normal
         self._finished = False
         if __debug__:
-            self._pstats = PStatCollector("App:Show code:jobManager:%s" % self._name)
+            self._pstats = PStatCollector("App:Tasks:jobManager:%s" % self._name)
 
     def destroy(self):
         del self._name

+ 46 - 35
direct/src/showbase/ShowBase.py

@@ -1151,7 +1151,7 @@ class ShowBase(DirectObject.DirectObject):
         Creates the render scene graph, the primary scene graph for
         rendering 3-d geometry.
         """
-        ## This is the root of the 3-D scene graph.
+        #: This is the root of the 3-D scene graph.
         self.render = NodePath('render')
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
 
@@ -1170,7 +1170,7 @@ class ShowBase(DirectObject.DirectObject):
         # for the benefit of creating DirectGui elements before ShowBase.
         from . import ShowBaseGlobal
 
-        ## This is the root of the 2-D scene graph.
+        #: This is the root of the 2-D scene graph.
         self.render2d = ShowBaseGlobal.render2d
 
         # Set up some overrides to turn off certain properties which
@@ -1191,12 +1191,12 @@ class ShowBase(DirectObject.DirectObject):
         self.render2d.setMaterialOff(1)
         self.render2d.setTwoSided(1)
 
-        ## The normal 2-d DisplayRegion has an aspect ratio that
-        ## matches the window, but its coordinate system is square.
-        ## This means anything we parent to render2d gets stretched.
-        ## For things where that makes a difference, we set up
-        ## aspect2d, which scales things back to the right aspect
-        ## ratio along the X axis (Z is still from -1 to 1)
+        #: The normal 2-d DisplayRegion has an aspect ratio that
+        #: matches the window, but its coordinate system is square.
+        #: This means anything we parent to render2d gets stretched.
+        #: For things where that makes a difference, we set up
+        #: aspect2d, which scales things back to the right aspect
+        #: ratio along the X axis (Z is still from -1 to 1)
         self.aspect2d = ShowBaseGlobal.aspect2d
 
         aspectRatio = self.getAspectRatio()
@@ -1204,13 +1204,13 @@ class ShowBase(DirectObject.DirectObject):
 
         self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
 
-        ## The Z position of the top border of the aspect2d screen.
+        #: The Z position of the top border of the aspect2d screen.
         self.a2dTop = 1.0
-        ## The Z position of the bottom border of the aspect2d screen.
+        #: The Z position of the bottom border of the aspect2d screen.
         self.a2dBottom = -1.0
-        ## The X position of the left border of the aspect2d screen.
+        #: The X position of the left border of the aspect2d screen.
         self.a2dLeft = -aspectRatio
-        ## The X position of the right border of the aspect2d screen.
+        #: The X position of the right border of the aspect2d screen.
         self.a2dRight = aspectRatio
 
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
@@ -1250,9 +1250,9 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRightNs.setPos(self.a2dRight, 0, self.a2dBottom)
 
-        ## This special root, pixel2d, uses units in pixels that are relative
-        ## to the window. The upperleft corner of the window is (0, 0),
-        ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
+        #: This special root, pixel2d, uses units in pixels that are relative
+        #: to the window. The upperleft corner of the window is (0, 0),
+        #: the lowerleft corner is (xsize, -ysize), in this coordinate system.
         self.pixel2d = self.render2d.attachNewNode(PGTop("pixel2d"))
         self.pixel2d.setPos(-1, 0, 1)
         xsize, ysize = self.getSize()
@@ -1282,25 +1282,25 @@ class ShowBase(DirectObject.DirectObject):
         self.render2dp.setMaterialOff(1)
         self.render2dp.setTwoSided(1)
 
-        ## The normal 2-d DisplayRegion has an aspect ratio that
-        ## matches the window, but its coordinate system is square.
-        ## This means anything we parent to render2dp gets stretched.
-        ## For things where that makes a difference, we set up
-        ## aspect2dp, which scales things back to the right aspect
-        ## ratio along the X axis (Z is still from -1 to 1)
+        #: The normal 2-d DisplayRegion has an aspect ratio that
+        #: matches the window, but its coordinate system is square.
+        #: This means anything we parent to render2dp gets stretched.
+        #: For things where that makes a difference, we set up
+        #: aspect2dp, which scales things back to the right aspect
+        #: ratio along the X axis (Z is still from -1 to 1)
         self.aspect2dp = self.render2dp.attachNewNode(PGTop("aspect2dp"))
         self.aspect2dp.node().setStartSort(16384)
 
         aspectRatio = self.getAspectRatio()
         self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
 
-        ## The Z position of the top border of the aspect2dp screen.
+        #: The Z position of the top border of the aspect2dp screen.
         self.a2dpTop = 1.0
-        ## The Z position of the bottom border of the aspect2dp screen.
+        #: The Z position of the bottom border of the aspect2dp screen.
         self.a2dpBottom = -1.0
-        ## The X position of the left border of the aspect2dp screen.
+        #: The X position of the left border of the aspect2dp screen.
         self.a2dpLeft = -aspectRatio
-        ## The X position of the right border of the aspect2dp screen.
+        #: The X position of the right border of the aspect2dp screen.
         self.a2dpRight = aspectRatio
 
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
@@ -1324,9 +1324,9 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
         self.a2dpBottomRight.setPos(self.a2dpRight, 0, self.a2dpBottom)
 
-        ## This special root, pixel2d, uses units in pixels that are relative
-        ## to the window. The upperleft corner of the window is (0, 0),
-        ## the lowerleft corner is (xsize, -ysize), in this coordinate system.
+        #: This special root, pixel2dp, uses units in pixels that are relative
+        #: to the window. The upperleft corner of the window is (0, 0),
+        #: the lowerleft corner is (xsize, -ysize), in this coordinate system.
         self.pixel2dp = self.render2dp.attachNewNode(PGTop("pixel2dp"))
         self.pixel2dp.node().setStartSort(16384)
         self.pixel2dp.setPos(-1, 0, 1)
@@ -1647,11 +1647,11 @@ class ShowBase(DirectObject.DirectObject):
 
         mw = self.buttonThrowers[0].getParent()
 
-        ## A special ButtonThrower to generate keyboard events and
-        ## include the time from the OS.  This is separate only to
-        ## support legacy code that did not expect a time parameter; it
-        ## will eventually be folded into the normal ButtonThrower,
-        ## above.
+        #: A special ButtonThrower to generate keyboard events and
+        #: include the time from the OS.  This is separate only to
+        #: support legacy code that did not expect a time parameter; it
+        #: will eventually be folded into the normal ButtonThrower,
+        #: above.
         self.timeButtonThrower = mw.attachNewNode(ButtonThrower('timeButtons'))
         self.timeButtonThrower.node().setPrefix('time-')
         self.timeButtonThrower.node().setTimeFlag(1)
@@ -2713,7 +2713,7 @@ class ShowBase(DirectObject.DirectObject):
 
     def screenshot(self, namePrefix = 'screenshot',
                    defaultFilename = 1, source = None,
-                   imageComment=""):
+                   imageComment="", blocking=True):
         """ Captures a screenshot from the main window or from the
         specified window or Texture and writes it to a filename in the
         current directory (or to a specified directory).
@@ -2735,6 +2735,13 @@ class ShowBase(DirectObject.DirectObject):
         generated by makeCubeMap(), namePrefix should contain the hash
         mark ('#') character.
 
+        Normally, this call will block until the screenshot is fully
+        written.  To write the screenshot in a background thread
+        instead, pass blocking = False.  In this case, the return value
+        is a future that can be awaited.
+
+        A "screenshot" event will be sent once the screenshot is saved.
+
         :returns: The filename if successful, or None if there is a problem.
         """
 
@@ -2751,8 +2758,12 @@ class ShowBase(DirectObject.DirectObject):
                 saved = source.write(filename, 0, 0, 1, 0)
             else:
                 saved = source.write(filename)
-        else:
+        elif blocking:
             saved = source.saveScreenshot(filename, imageComment)
+        else:
+            request = source.saveAsyncScreenshot(filename, imageComment)
+            request.addDoneCallback(lambda fut, filename=filename: messenger.send('screenshot', [filename]))
+            return request
 
         if saved:
             # Announce to anybody that a screenshot has been taken

+ 0 - 1
direct/src/showutil/Effects.py

@@ -105,7 +105,6 @@ def createBounce(nodeObj, numBounces, startValues, totalTime, amplitude,
 
         newVec3 = Vec3(startValues)
         newVec3.setCell(index, currBounceVal)
-        print("### newVec3 = %s" % newVec3)
 
         # create the right type of lerp
         if ((bounceType == SX_BOUNCE) or (bounceType == SY_BOUNCE) or

+ 152 - 0
doc/ReleaseNotes

@@ -1,3 +1,155 @@
+-----------------------  RELEASE 1.10.13  -----------------------
+
+This is a significant release containing many important bug fixes and a couple
+of interesting new features.
+
+Rendering
+* Fix single texture stage limit when `gl-version 3 2` or higher is set (#1404)
+* Fix some render-to-texture bugs with multithreaded pipeline (incl. #1364)
+* Fix failure to unset divisor after rendering with hardware instancing
+* Add "MSAA" filter to CommonFilters class as convenience to enable MSAA
+* Fix multisample FBOs with MRT resolving aux target into color target
+* Fix shader generator not responding to fog color changes
+* Fix OpenGL error when downloading GL_LUMINANCE8 texture
+
+Windowing
+* Fix incorrect "without" event generation when mouse leaves window (#1400)
+* Windows: Fix lost "up" events when dragging cursor outside window while
+  multiple mouse buttons are pressed down (#1396)
+* macOS: Fix crash with threading-model on newer macOS versions (#1286)
+* macOS: Fix black screen when going fullscreen on Apple M1-based macs (#1316)
+* macOS: Fix window overlapping Dock when requesting very large height
+* macOS: Improve application termination handling, now sends proper exit events
+* X11: tinydisplay handles window resizes more efficiently
+* X11: Work around window not rendering at first on swaywm (#1087)
+
+Deployment
+* Not all code was being built with optimize level 2
+* Add `keep_docstrings` option to switch to optimize level 1 (#1341)
+* Add `prefer_discrete_gpu` option to force dedicated GPU on Windows (#680)
+* Add `bam_model_extensions` for converting non-egg models to .bam (#714)
+* Work around autodiscovery error when using `setuptools>=61.0.0` (#1394)
+* Default Linux target to `manylinux2014_x86_64` on Python 3.11+
+
+PStats
+* Add support for Python profiling with `pstats-python-profiler` Config.prc var
+* Fix PStats crash at launch from pip installs in newer Linux distros (#1391)
+* Performance improvements to time-based strip chart views
+* Time-based strip charts now can show start/stop count in corner of graphs
+* Optimize client performance when sending a large number of samples
+* Fix dropped frames by changing value for `pstats-max-queue-size` from 1 to 4
+* Server accept clients using PStats protocol version 2.3
+
+Assimp
+* Fix assertion when loading meshes with multiple primitive types
+* Add `assimp-collapse-dummy-root-node` option to remove root node (see #366)
+* Import custom object properties as tags
+* Add support for additional texture maps, including PBR textures
+* Support reading tangent and binormal vectors
+* Improve performance when loading geometry
+* Fix problems reading external files (see #366)
+* Support reading alpha mode when loading .glTF models
+* Add support for texture transforms
+* Add support for texture wrapping modes
+* Fix memory corruption bugs
+
+Build
+* Fixes to `pview.desktop` file on Linux
+* makepanda: Fix problems when building on arm64 on macOS without `--arch` flag
+* makepanda: Fix detection issues with newer macOS / XCode versions
+* makepanda: Fix motiontrail header files not being copied
+* Windows: Fix HTTPClient not working when nativenet module is disabled
+* macOS: Fix OpenCV library refusing to load in arm64 build (#1393)
+* Fix compiler error when compiling for e2k (MCST Elbrus 2000) (#1367)
+
+Miscellaneous
+* Add new motion trails sample program
+* `MotionTrail.add_vertex()` method now directly accepts a vertex position
+* Significant performance optimization of C++-based motion trail implementation
+* Fix race condition when destructing/constructing NodePaths in thread (#1366)
+* Add implementation of capsule-into-polygon collision test (#1369)
+* Fix texture transforms sometimes not being flattened (#1392)
+* Fix support for `#pragma include <file.glsl>` in GLSL shaders
+* Fix `ShaderBuffer.prepare()` not doing anything
+* Implement deepcopy for PointerToArray
+* Fix Texture deepcopy keeping a reference to the original RAM image
+* Fix bf-cbc encryption no longer working when building with OpenSSL 3.0
+* PandaNode bounds_type property was erroneously marked read-only
+* Fix warnings when copying OdeTriMeshGeom objects
+* Fix a crash when using `Notify.set_ostream_ptr()` from Python (#1371)
+* Fix GarbageReport not working with Python 3 (#1304)
+* Make `mat.cols[n]` and `mat.rows[n]` assignable
+* Fix `ExecutionEnvironment.args` being empty on Linux
+* Add various useful functions to interrogatedb module
+* Fix Python 3 issues unpacking uint types in Python 3 (#1380)
+* Fix interrogate syntax error with C++11-style attributes in declarators
+* Fix double-precision color values not being clamped by GeomVertexWriter
+* Fix regression with BufferViewer in double-precision build (#1365)
+* Fix `PandaNode.nested_vertices` not updating properly
+* Prevent Panda calculating bounding volume of Geom with custom bounding volume
+* Add `do_events()` and `process_event()` snake_case aliases in eventMgr
+* Support second arg of None in `replace_texture()` / `replace_material()`
+* Support `os.fspath()` for ConfigVariableFilename objects (#1406)
+* rplight: Fix PSSM calculation failing with infinite far distance (#1397)
+* Remove spurious print in `direct.showutil.Effects.createBounce()` (#1383)
+* Fix assorted compiler warnings
+
+-----------------------  RELEASE 1.10.12  -----------------------
+
+Recommended maintenance release containing primarily bug fixes.
+
+Windowing
+* Windows: Fix origin not respected when switching to windowed mode
+* macOS: Fix origin not being updated when resizing window
+* macOS: Fix off-by-one errors with mouse cursor position
+* macOS: Fix issues with confined mouse mode
+* macOS: Fix events being suppressed when moving the mouse pointer
+* macOS: Invert horizontal scroll, set `cocoa-invert-wheel-x true` to revert
+
+Rendering
+* Add `shadow-cube-map-filter` setting to enable cube map shadow filtering
+* Support floating-point FBOs in OpenGL ES 2+
+* Fix texture format selection in OpenGL with T_half_float component type
+* Added `egl-device-index` config var to select EGL device
+* Offscreen windows in tinydisplay renderer are now resizeable
+* CommonFilters now supports alternative coordinate systems
+* Fix BufferViewer frame when using a different coordinate system
+
+Deployment
+* Fix _bootlocale error in deployed application on Windows with Python 3.10
+* Include _sysconfigdata module properly when using sysconfig module
+* Fix building deploy-stub on platforms that use DT_RUNPATH instead of DT_RPATH
+* `sys.flags.optimize` is now set to 2 in Python 3.2 and above
+* Fix import errors when using scipy
+
+Miscellaneous
+* `Texture::get_ram_image_as()` fixed for 3D textures
+* Fix PStats GPU timing not working with newer NVIDIA drivers
+* Fix false negative in collision test when sphere is fully inside box
+* Resolve segmentation fault when statically linking ffmpeg module
+* Fix issue with failed mmap when using WebcamVideo on Linux
+* macOS: Keyboard/mouse devices are no longer enumerated by default
+* Fix repr of LPlane class
+* Remove dependency on ShowBase in FilterManager
+* Many new functions added to interrogatedb module to query additional info
+* Interrogate no longer writes wrappers with rvalue references to interrogatedb
+* PStats on Linux: Fix mouse motion detected outside strip chart graph area
+* Fix assertion when reading bam file with Bullet convex hull shape
+* Fix memory leak when specifying owner of a task
+* Add additional helpful debug/spam prints to display code
+
+Build
+* Support building with Python 3.11
+* Support building with OpenSSL 1.1.1 on Windows
+* Support building with OpenEXR 3.0 or 3.1 on Windows
+* Fix errors when compiling Panda headers with MinGW
+* Allow compiling Panda headers on Windows without NOMINMAX set
+* Fix wheel platform tag on manylinux aarch64
+* Experimentally allow building with mimalloc on Windows
+* Makepanda records cache timestamps as integers instead of floats
+* Makepanda can now also build tinydisplay on Linux without X11
+* Fix naming of built wheels when building for macOS 12
+
 -----------------------  RELEASE 1.10.11  -----------------------
 
 Maintenance release containing assorted bug fixes and minor improvements.

+ 301 - 1
dtool/metalibs/dtoolconfig/pydtool.cxx

@@ -45,6 +45,17 @@ static PyObject *_inP07ytDId0(PyObject *self, PyObject *args);
 static PyObject *_inP07ytHuAm(PyObject *self, PyObject *args);
 static PyObject *_inP07yt_xr0(PyObject *self, PyObject *args);
 static PyObject *_inP07ytH5qp(PyObject *self, PyObject *args);
+static PyObject *_inP07ytLfJw(PyObject *self, PyObject *args);
+static PyObject *_inP07yt_Atg(PyObject *self, PyObject *args);
+static PyObject *_inP07ytlBqc(PyObject *self, PyObject *args);
+static PyObject *_inP07ytNdUp(PyObject *self, PyObject *args);
+static PyObject *_inP07ytlS0p(PyObject *self, PyObject *args);
+static PyObject *_inP07ytZZe7(PyObject *self, PyObject *args);
+static PyObject *_inP07ytV5S_(PyObject *self, PyObject *args);
+static PyObject *_inP07yto9vD(PyObject *self, PyObject *args);
+static PyObject *_inP07ytv7tF(PyObject *self, PyObject *args);
+static PyObject *_inP07ythOg6(PyObject *self, PyObject *args);
+static PyObject *_inP07ytoZUn(PyObject *self, PyObject *args);
 static PyObject *_inP07ytq45U(PyObject *self, PyObject *args);
 static PyObject *_inP07yt6IPa(PyObject *self, PyObject *args);
 static PyObject *_inP07ytU2_B(PyObject *self, PyObject *args);
@@ -74,7 +85,12 @@ static PyObject *_inP07yt3zru(PyObject *self, PyObject *args);
 static PyObject *_inP07ytRrg2(PyObject *self, PyObject *args);
 static PyObject *_inP07ytEJCx(PyObject *self, PyObject *args);
 static PyObject *_inP07ytWAZr(PyObject *self, PyObject *args);
+static PyObject *_inP07ytHQi6(PyObject *self, PyObject *args);
 static PyObject *_inP07ytrD_M(PyObject *self, PyObject *args);
+static PyObject *_inP07ytYaah(PyObject *self, PyObject *args);
+static PyObject *_inP07yt2otr(PyObject *self, PyObject *args);
+static PyObject *_inP07ytNP_b(PyObject *self, PyObject *args);
+static PyObject *_inP07ytrrrN(PyObject *self, PyObject *args);
 static PyObject *_inP07ytjolz(PyObject *self, PyObject *args);
 static PyObject *_inP07ytt_JD(PyObject *self, PyObject *args);
 static PyObject *_inP07ytwEts(PyObject *self, PyObject *args);
@@ -107,6 +123,7 @@ static PyObject *_inP07ytNHcs(PyObject *self, PyObject *args);
 static PyObject *_inP07ytqHrb(PyObject *self, PyObject *args);
 static PyObject *_inP07ytaOqq(PyObject *self, PyObject *args);
 static PyObject *_inP07ytpTBb(PyObject *self, PyObject *args);
+static PyObject *_inP07ytZUkn(PyObject *self, PyObject *args);
 static PyObject *_inP07ytqWOw(PyObject *self, PyObject *args);
 static PyObject *_inP07ytHu7x(PyObject *self, PyObject *args);
 static PyObject *_inP07ytwGnA(PyObject *self, PyObject *args);
@@ -583,6 +600,184 @@ _inP07ytH5qp(PyObject *, PyObject *args) {
   return nullptr;
 }
 
+/*
+ * Python simple wrapper for
+ * bool interrogate_element_has_has_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytLfJw(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_element_has_has_function)((ElementIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * FunctionIndex interrogate_element_has_function(ElementIndex element)
+ */
+static PyObject *
+_inP07yt_Atg(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    FunctionIndex return_value = (::interrogate_element_has_function)((ElementIndex)param0);
+#if PY_MAJOR_VERSION >= 3
+    return PyLong_FromLong(return_value);
+#else
+    return PyInt_FromLong(return_value);
+#endif
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * bool interrogate_element_has_clear_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytlBqc(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_element_has_clear_function)((ElementIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * FunctionIndex interrogate_element_clear_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytNdUp(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    FunctionIndex return_value = (::interrogate_element_clear_function)((ElementIndex)param0);
+#if PY_MAJOR_VERSION >= 3
+    return PyLong_FromLong(return_value);
+#else
+    return PyInt_FromLong(return_value);
+#endif
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * bool interrogate_element_has_del_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytlS0p(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_element_has_del_function)((ElementIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * FunctionIndex interrogate_element_del_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytZZe7(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    FunctionIndex return_value = (::interrogate_element_del_function)((ElementIndex)param0);
+#if PY_MAJOR_VERSION >= 3
+    return PyLong_FromLong(return_value);
+#else
+    return PyInt_FromLong(return_value);
+#endif
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * bool interrogate_element_has_insert_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytV5S_(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_element_has_insert_function)((ElementIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * FunctionIndex interrogate_element_insert_function(ElementIndex element)
+ */
+static PyObject *
+_inP07yto9vD(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    FunctionIndex return_value = (::interrogate_element_insert_function)((ElementIndex)param0);
+#if PY_MAJOR_VERSION >= 3
+    return PyLong_FromLong(return_value);
+#else
+    return PyInt_FromLong(return_value);
+#endif
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * bool interrogate_element_has_getkey_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytv7tF(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_element_has_getkey_function)((ElementIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * FunctionIndex interrogate_element_getkey_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ythOg6(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    FunctionIndex return_value = (::interrogate_element_getkey_function)((ElementIndex)param0);
+#if PY_MAJOR_VERSION >= 3
+    return PyLong_FromLong(return_value);
+#else
+    return PyInt_FromLong(return_value);
+#endif
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * FunctionIndex interrogate_element_length_function(ElementIndex element)
+ */
+static PyObject *
+_inP07ytoZUn(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    FunctionIndex return_value = (::interrogate_element_length_function)((ElementIndex)param0);
+#if PY_MAJOR_VERSION >= 3
+    return PyLong_FromLong(return_value);
+#else
+    return PyInt_FromLong(return_value);
+#endif
+  }
+  return nullptr;
+}
+
 /*
  * Python simple wrapper for
  * bool interrogate_element_is_sequence(ElementIndex element)
@@ -1060,6 +1255,24 @@ _inP07ytWAZr(PyObject *, PyObject *args) {
   return nullptr;
 }
 
+/*
+ * Python simple wrapper for
+ * FunctionIndex interrogate_wrapper_function(FunctionWrapperIndex wrapper)
+ */
+static PyObject *
+_inP07ytHQi6(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    FunctionIndex return_value = (::interrogate_wrapper_function)((FunctionWrapperIndex)param0);
+#if PY_MAJOR_VERSION >= 3
+    return PyLong_FromLong(return_value);
+#else
+    return PyInt_FromLong(return_value);
+#endif
+  }
+  return nullptr;
+}
+
 /*
  * Python simple wrapper for
  * bool interrogate_wrapper_is_callable_by_name(FunctionWrapperIndex wrapper)
@@ -1074,6 +1287,62 @@ _inP07ytrD_M(PyObject *, PyObject *args) {
   return nullptr;
 }
 
+/*
+ * Python simple wrapper for
+ * bool interrogate_wrapper_is_copy_constructor(FunctionWrapperIndex wrapper)
+ */
+static PyObject *
+_inP07ytYaah(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_wrapper_is_copy_constructor)((FunctionWrapperIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * bool interrogate_wrapper_is_coerce_constructor(FunctionWrapperIndex wrapper)
+ */
+static PyObject *
+_inP07yt2otr(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_wrapper_is_coerce_constructor)((FunctionWrapperIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * bool interrogate_wrapper_is_extension(FunctionWrapperIndex wrapper)
+ */
+static PyObject *
+_inP07ytNP_b(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_wrapper_is_extension)((FunctionWrapperIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
+/*
+ * Python simple wrapper for
+ * bool interrogate_wrapper_is_deprecated(FunctionWrapperIndex wrapper)
+ */
+static PyObject *
+_inP07ytrrrN(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_wrapper_is_deprecated)((FunctionWrapperIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
 /*
  * Python simple wrapper for
  * bool interrogate_wrapper_has_comment(FunctionWrapperIndex wrapper)
@@ -1613,6 +1882,20 @@ _inP07ytpTBb(PyObject *, PyObject *args) {
   return nullptr;
 }
 
+/*
+ * Python simple wrapper for
+ * bool interrogate_type_is_deprecated(TypeIndex type)
+ */
+static PyObject *
+_inP07ytZUkn(PyObject *, PyObject *args) {
+  int param0;
+  if (PyArg_ParseTuple(args, "i", &param0)) {
+    bool return_value = (::interrogate_type_is_deprecated)((TypeIndex)param0);
+    return PyBool_FromLong(return_value);
+  }
+  return nullptr;
+}
+
 /*
  * Python simple wrapper for
  * char const *interrogate_type_name(TypeIndex type)
@@ -2652,6 +2935,17 @@ static PyMethodDef python_simple_funcs[] = {
   { "interrogate_element_getter", &_inP07ytHuAm, METH_VARARGS, nullptr },
   { "interrogate_element_has_setter", &_inP07yt_xr0, METH_VARARGS, nullptr },
   { "interrogate_element_setter", &_inP07ytH5qp, METH_VARARGS, nullptr },
+  { "interrogate_element_has_has_function", &_inP07ytLfJw, METH_VARARGS, nullptr },
+  { "interrogate_element_has_function", &_inP07yt_Atg, METH_VARARGS, nullptr },
+  { "interrogate_element_has_clear_function", &_inP07ytlBqc, METH_VARARGS, nullptr },
+  { "interrogate_element_clear_function", &_inP07ytNdUp, METH_VARARGS, nullptr },
+  { "interrogate_element_has_del_function", &_inP07ytlS0p, METH_VARARGS, nullptr },
+  { "interrogate_element_del_function", &_inP07ytZZe7, METH_VARARGS, nullptr },
+  { "interrogate_element_has_insert_function", &_inP07ytV5S_, METH_VARARGS, nullptr },
+  { "interrogate_element_insert_function", &_inP07yto9vD, METH_VARARGS, nullptr },
+  { "interrogate_element_has_getkey_function", &_inP07ytv7tF, METH_VARARGS, nullptr },
+  { "interrogate_element_getkey_function", &_inP07ythOg6, METH_VARARGS, nullptr },
+  { "interrogate_element_length_function", &_inP07ytoZUn, METH_VARARGS, nullptr },
   { "interrogate_element_is_sequence", &_inP07ytq45U, METH_VARARGS, nullptr },
   { "interrogate_element_is_mapping", &_inP07yt6IPa, METH_VARARGS, nullptr },
   { "interrogate_number_of_globals", &_inP07ytU2_B, METH_VARARGS, nullptr },
@@ -2681,7 +2975,12 @@ static PyMethodDef python_simple_funcs[] = {
   { "interrogate_function_number_of_python_wrappers", &_inP07ytRrg2, METH_VARARGS, nullptr },
   { "interrogate_function_python_wrapper", &_inP07ytEJCx, METH_VARARGS, nullptr },
   { "interrogate_wrapper_name", &_inP07ytWAZr, METH_VARARGS, nullptr },
+  { "interrogate_wrapper_function", &_inP07ytHQi6, METH_VARARGS, nullptr },
   { "interrogate_wrapper_is_callable_by_name", &_inP07ytrD_M, METH_VARARGS, nullptr },
+  { "interrogate_wrapper_is_copy_constructor", &_inP07ytYaah, METH_VARARGS, nullptr },
+  { "interrogate_wrapper_is_coerce_constructor", &_inP07yt2otr, METH_VARARGS, nullptr },
+  { "interrogate_wrapper_is_extension", &_inP07ytNP_b, METH_VARARGS, nullptr },
+  { "interrogate_wrapper_is_deprecated", &_inP07ytrrrN, METH_VARARGS, nullptr },
   { "interrogate_wrapper_has_comment", &_inP07ytjolz, METH_VARARGS, nullptr },
   { "interrogate_wrapper_comment", &_inP07ytt_JD, METH_VARARGS, nullptr },
   { "interrogate_wrapper_has_return_value", &_inP07ytwEts, METH_VARARGS, nullptr },
@@ -2714,6 +3013,7 @@ static PyMethodDef python_simple_funcs[] = {
   { "interrogate_get_type_by_scoped_name", &_inP07ytqHrb, METH_VARARGS, nullptr },
   { "interrogate_get_type_by_true_name", &_inP07ytaOqq, METH_VARARGS, nullptr },
   { "interrogate_type_is_global", &_inP07ytpTBb, METH_VARARGS, nullptr },
+  { "interrogate_type_is_deprecated", &_inP07ytZUkn, METH_VARARGS, nullptr },
   { "interrogate_type_name", &_inP07ytqWOw, METH_VARARGS, nullptr },
   { "interrogate_type_scoped_name", &_inP07ytHu7x, METH_VARARGS, nullptr },
   { "interrogate_type_true_name", &_inP07ytwGnA, METH_VARARGS, nullptr },
@@ -2782,7 +3082,7 @@ static PyMethodDef python_simple_funcs[] = {
 #if PY_MAJOR_VERSION >= 3
 static struct PyModuleDef python_simple_module = {
   PyModuleDef_HEAD_INIT,
-  "interrogatedb",
+  "panda3d.interrogatedb",
   nullptr,
   -1,
   python_simple_funcs,

+ 2 - 0
dtool/src/cppparser/CMakeLists.txt

@@ -1,4 +1,5 @@
 set(P3CPPPARSER_HEADERS
+  cppAttributeList.h
   cppArrayType.h cppBison.yxx cppBisonDefs.h
   cppClassTemplateParameter.h cppCommentBlock.h
   cppClosureType.h cppConstType.h
@@ -17,6 +18,7 @@ set(P3CPPPARSER_HEADERS
 )
 
 set(P3CPPPARSER_SOURCES
+  cppAttributeList.cxx
   cppArrayType.cxx ${CMAKE_CURRENT_BINARY_DIR}/cppBison.cxx
   cppClassTemplateParameter.cxx
   cppCommentBlock.cxx cppClosureType.cxx cppConstType.cxx cppDeclaration.cxx

+ 5 - 0
dtool/src/cppparser/cppArrayType.cxx

@@ -189,6 +189,11 @@ output_instance(std::ostream &out, int indent_level, CPPScope *scope,
     brackets << *_bounds;
   }
   brackets << "]";
+
+  if (!_attributes.is_empty()) {
+    brackets << " " << _attributes;
+  }
+
   std::string bracketsstr = brackets.str();
 
   _element_type->output_instance(out, indent_level, scope, complete,

+ 196 - 0
dtool/src/cppparser/cppAttributeList.cxx

@@ -0,0 +1,196 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file cppAttributeList.cxx
+ * @author rdb
+ * @date 2022-10-23
+ */
+
+#include "cppAttributeList.h"
+#include "cppExpression.h"
+#include "cppIdentifier.h"
+#include "cppType.h"
+
+/**
+ * Returns true if no attributes have been defined.
+ */
+bool CPPAttributeList::
+is_empty() const {
+  return _attributes.empty() && _alignas == nullptr;
+}
+
+/**
+ * Returns true if the attribute list has an attribute with the given name.
+ */
+bool CPPAttributeList::
+has_attribute(const std::string &name) const {
+  for (const Attribute &attr : _attributes) {
+    if (attr._ident->get_fully_scoped_name() == name) {
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ *
+ */
+bool CPPAttributeList::
+operator == (const CPPAttributeList &other) const {
+  if (_attributes.size() != other._attributes.size()) {
+    return false;
+  }
+  if ((_alignas != nullptr) != (other._alignas != nullptr)) {
+    return false;
+  }
+  if (_alignas != nullptr && *_alignas != *other._alignas) {
+    return false;
+  }
+  for (size_t i = 0; i < _attributes.size(); ++i) {
+    if (_attributes[i]._ident != other._attributes[i]._ident) {
+      return false;
+    }
+    if (_attributes[i]._reason != other._attributes[i]._reason) {
+      return false;
+    }
+  }
+  return true;
+}
+
+/**
+ *
+ */
+bool CPPAttributeList::
+operator != (const CPPAttributeList &other) const {
+  return !(*this == other);
+}
+
+/**
+ *
+ */
+bool CPPAttributeList::
+operator < (const CPPAttributeList &other) const {
+  if (_attributes.size() != other._attributes.size()) {
+    return _attributes.size() < other._attributes.size();
+  }
+  if ((_alignas != nullptr) != (other._alignas != nullptr)) {
+    return _alignas == nullptr;
+  }
+  if (_alignas != nullptr && *_alignas != *other._alignas) {
+    return *_alignas < *other._alignas;
+  }
+  for (size_t i = 0; i < _attributes.size(); ++i) {
+    if (_attributes[i]._ident != other._attributes[i]._ident) {
+      return _attributes[i]._ident < other._attributes[i]._ident;
+    }
+    if (_attributes[i]._reason != other._attributes[i]._reason) {
+      return _attributes[i]._reason < other._attributes[i]._reason;
+    }
+  }
+  return false;
+}
+
+/**
+ * Adds an attribute.
+ */
+void CPPAttributeList::
+add_attribute(CPPIdentifier *ident) {
+  _attributes.push_back({ident});
+}
+
+/**
+ * Adds an attribute.
+ */
+void CPPAttributeList::
+add_attribute(CPPIdentifier *ident, std::string reason) {
+  _attributes.push_back({ident, std::move(reason)});
+}
+
+/**
+ * Adds an alignas specifier.
+ */
+void CPPAttributeList::
+add_alignas(int size) {
+  if (_alignas == nullptr || size >= _alignas->evaluate().as_integer()) {
+    _alignas = new CPPExpression(size);
+  }
+}
+
+/**
+ * Adds an alignas specifier.
+ */
+void CPPAttributeList::
+add_alignas(CPPType *type) {
+  CPPExpression expr = CPPExpression::alignof_func(type);
+  if (_alignas == nullptr || expr.evaluate().as_integer() > _alignas->evaluate().as_integer()) {
+    _alignas = new CPPExpression(expr);
+  }
+}
+
+/**
+ * Adds an alignas specifier.
+ */
+void CPPAttributeList::
+add_alignas(CPPExpression *expr) {
+  if (_alignas == nullptr || expr->evaluate().as_integer() > _alignas->evaluate().as_integer()) {
+    _alignas = expr;
+  }
+}
+
+/**
+ * Merges the other list into this one.
+ */
+void CPPAttributeList::
+add_attributes_from(const CPPAttributeList &other) {
+  for (const Attribute &attr : other._attributes) {
+    _attributes.push_back(attr);
+  }
+
+  if (other._alignas != nullptr) {
+    add_alignas(other._alignas);
+  }
+}
+
+/**
+ *
+ */
+void CPPAttributeList::
+output(std::ostream &out, CPPScope *scope) const {
+  Attributes::const_iterator it = _attributes.begin();
+  if (it != _attributes.end()) {
+    out << "[[";
+    (*it)._ident->output(out, scope);
+    if (!(*it)._reason.empty()) {
+      out << "(" << (*it)._reason << ")";
+    }
+
+    for (++it; it != _attributes.end(); ++it) {
+      out << ", ";
+      (*it)._ident->output(out, scope);
+      if (!(*it)._reason.empty()) {
+        out << "(" << (*it)._reason << ")";
+      }
+    }
+
+    out << "]]";
+
+    if (_alignas != nullptr) {
+      out << " ";
+    }
+  }
+
+  if (_alignas != nullptr) {
+    out << "alignas(";
+    if (_alignas->_type == CPPExpression::T_alignof) {
+      _alignas->_u._typecast._to->output(out, 0, scope, false);
+    } else {
+      _alignas->output(out, 0, scope, false);
+    }
+    out << ")";
+  }
+}

+ 65 - 0
dtool/src/cppparser/cppAttributeList.h

@@ -0,0 +1,65 @@
+/**
+ * PANDA 3D SOFTWARE
+ * Copyright (c) Carnegie Mellon University.  All rights reserved.
+ *
+ * All use of this software is subject to the terms of the revised BSD
+ * license.  You should have received a copy of this license along
+ * with this source code in a file named "LICENSE."
+ *
+ * @file cppAttributeList.h
+ * @author rdb
+ * @date 2022-10-23
+ */
+
+#ifndef CPPATTRIBUTELIST_H
+#define CPPATTRIBUTELIST_H
+
+#include "dtoolbase.h"
+
+#include <vector>
+
+class CPPExpression;
+class CPPIdentifier;
+class CPPScope;
+class CPPType;
+
+/**
+ * A list of square-bracket attributes and/or alignas specifiers.
+ */
+class CPPAttributeList {
+public:
+  bool is_empty() const;
+  bool has_attribute(const std::string &name) const;
+
+  bool operator == (const CPPAttributeList &other) const;
+  bool operator != (const CPPAttributeList &other) const;
+  bool operator < (const CPPAttributeList &other) const;
+
+  void add_attribute(CPPIdentifier *ident);
+  void add_attribute(CPPIdentifier *ident, std::string reason);
+
+  void add_alignas(int size);
+  void add_alignas(CPPType *type);
+  void add_alignas(CPPExpression *expr);
+
+  void add_attributes_from(const CPPAttributeList &other);
+
+  struct Attribute {
+    CPPIdentifier *_ident;
+    std::string _reason;
+  };
+
+  typedef std::vector<Attribute> Attributes;
+  Attributes _attributes;
+  CPPExpression *_alignas = nullptr;
+
+  void output(std::ostream &out, CPPScope *scope) const;
+};
+
+inline std::ostream &
+operator << (std::ostream &out, const CPPAttributeList &alist) {
+  alist.output(out, nullptr);
+  return out;
+}
+
+#endif

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 916 - 952
dtool/src/cppparser/cppBison.cxx.prebuilt


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

@@ -1,8 +1,8 @@
-/* A Bison parser, made by GNU Bison 3.7.3.  */
+/* A Bison parser, made by GNU Bison 3.8.2.  */
 
 /* Bison interface for Yacc-like parsers in C
 
-   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
+   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
    Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
@@ -208,6 +208,7 @@ extern int cppyydebug;
   typedef enum yytokentype yytoken_kind_t;
 #endif
 /* Token kinds.  */
+#define YYEMPTY -2
 #define YYEOF 0
 #define YYerror 256
 #define YYUNDEF 257
@@ -380,6 +381,8 @@ struct YYLTYPE
 
 
 
+
 int cppyyparse (void);
 
+
 #endif /* !YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED  */

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 256 - 203
dtool/src/cppparser/cppBison.yxx


+ 2 - 0
dtool/src/cppparser/cppBisonDefs.h

@@ -23,6 +23,7 @@
 
 #include <string>
 
+#include "cppAttributeList.h"
 #include "cppClosureType.h"
 #include "cppExtensionType.h"
 #include "cppFile.h"
@@ -65,6 +66,7 @@ extern CPPPreprocessor *current_lexer;
 class cppyystype {
 public:
   std::string str;
+  CPPAttributeList attr_list;
   union {
     unsigned long long integer;
     long double real;

+ 4 - 0
dtool/src/cppparser/cppClosureType.cxx

@@ -152,6 +152,10 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
     out << " noexcept";
   }
 
+  if (!_attributes.is_empty()) {
+    out << " " << _attributes;
+  }
+
   if (_return_type != nullptr) {
     out << " -> ";
     _return_type->output(out, indent_level, scope, false);

+ 22 - 3
dtool/src/cppparser/cppDeclaration.cxx

@@ -18,8 +18,9 @@
  *
  */
 CPPDeclaration::
-CPPDeclaration(const CPPFile &file) :
-  _file(file)
+CPPDeclaration(const CPPFile &file, CPPAttributeList attr) :
+  _file(file),
+  _attributes(std::move(attr))
 {
   _vis = V_unknown;
   _template_scope = nullptr;
@@ -34,7 +35,8 @@ CPPDeclaration(const CPPDeclaration &copy) :
   _vis(copy._vis),
   _template_scope(copy._template_scope),
   _file(copy._file),
-  _leading_comment(copy._leading_comment)
+  _leading_comment(copy._leading_comment),
+  _attributes(copy._attributes)
 {
 }
 
@@ -47,6 +49,7 @@ operator = (const CPPDeclaration &copy) {
   _template_scope = copy._template_scope;
   _file = copy._file;
   _leading_comment = copy._leading_comment;
+  _attributes = copy._attributes;
   return *this;
 }
 
@@ -135,6 +138,22 @@ substitute_decl(SubstDecl &subst, CPPScope *, CPPScope *) {
   return this;
 }
 
+/**
+ *
+ */
+void CPPDeclaration::
+output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const {
+  out << _attributes;
+}
+
+/**
+ *
+ */
+CPPDeclaration::SubType CPPDeclaration::
+get_subtype() const {
+  return ST_empty;
+}
+
 /**
  *
  */

+ 8 - 3
dtool/src/cppparser/cppDeclaration.h

@@ -19,6 +19,7 @@
 #include "cppVisibility.h"
 #include "cppFile.h"
 #include "cppCommentBlock.h"
+#include "cppAttributeList.h"
 
 #include <string>
 #include <vector>
@@ -59,6 +60,9 @@ class CPPPreprocessor;
 class CPPDeclaration {
 public:
   enum SubType {
+    // Empty declaration
+    ST_empty,
+
     // Subtypes of CPPDeclaration
     ST_instance,
     ST_type_declaration,
@@ -87,7 +91,7 @@ public:
     ST_closure,
   };
 
-  CPPDeclaration(const CPPFile &file);
+  CPPDeclaration(const CPPFile &file, CPPAttributeList attr = CPPAttributeList());
   CPPDeclaration(const CPPDeclaration &copy);
   virtual ~CPPDeclaration() {};
 
@@ -114,9 +118,9 @@ public:
   Instantiations _instantiations;
 
   virtual void output(std::ostream &out, int indent_level, CPPScope *scope,
-                      bool complete) const=0;
+                      bool complete) const;
 
-  virtual SubType get_subtype() const=0;
+  virtual SubType get_subtype() const;
 
   virtual CPPInstance *as_instance();
   virtual CPPClassTemplateParameter *as_class_template_parameter();
@@ -216,6 +220,7 @@ public:
   CPPTemplateScope *_template_scope;
   CPPFile _file;
   CPPCommentBlock *_leading_comment;
+  CPPAttributeList _attributes;
 
 protected:
   virtual bool is_equal(const CPPDeclaration *other) const;

+ 23 - 12
dtool/src/cppparser/cppEnumType.cxx

@@ -26,8 +26,8 @@
  */
 CPPEnumType::
 CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
-            CPPScope *scope, const CPPFile &file) :
-  CPPExtensionType(type, ident, current_scope, file),
+            CPPScope *scope, const CPPFile &file, CPPAttributeList attr) :
+  CPPExtensionType(type, ident, current_scope, file, std::move(attr)),
   _scope(scope),
   _element_type(nullptr),
   _last_value(nullptr)
@@ -44,8 +44,9 @@ CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
  */
 CPPEnumType::
 CPPEnumType(Type type, CPPIdentifier *ident, CPPType *element_type,
-            CPPScope *current_scope, CPPScope *scope, const CPPFile &file) :
-  CPPExtensionType(type, ident, current_scope, file),
+            CPPScope *current_scope, CPPScope *scope, const CPPFile &file,
+            CPPAttributeList attr) :
+  CPPExtensionType(type, ident, current_scope, file, std::move(attr)),
   _scope(scope),
   _element_type(element_type),
   _last_value(nullptr)
@@ -89,7 +90,9 @@ get_underlying_type() {
  *
  */
 CPPInstance *CPPEnumType::
-add_element(const std::string &name, CPPExpression *value, CPPPreprocessor *preprocessor, const cppyyltype &pos) {
+add_element(const std::string &name, CPPExpression *value,
+            CPPPreprocessor *preprocessor, const cppyyltype &pos,
+            CPPAttributeList attr) {
   CPPIdentifier *ident = new CPPIdentifier(name);
   ident->_native_scope = _parent_scope;
 
@@ -102,6 +105,7 @@ add_element(const std::string &name, CPPExpression *value, CPPPreprocessor *prep
     inst = new CPPInstance(this, ident);
   }
   inst->_storage_class |= CPPInstance::SC_constexpr;
+  inst->_attributes = std::move(attr);
   _elements.push_back(inst);
 
   if (value == nullptr) {
@@ -269,9 +273,12 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
       out << _type << " ";
     }
     out << _ident->get_local_name(scope);
-
-  } else {
+  }
+  else {
     out << _type;
+    if (!_attributes.is_empty()) {
+      out << " " << _attributes;
+    }
     if (_ident != nullptr) {
       out << " " << _ident->get_local_name(scope);
     }
@@ -280,11 +287,15 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
     }
 
     out << " {\n";
-    Elements::const_iterator ei;
-    for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
-      indent(out, indent_level + 2) << (*ei)->get_local_name();
-      if ((*ei)->_initializer != nullptr) {
-        out << " = " << *(*ei)->_initializer;
+    for (CPPInstance *element : _elements) {
+      indent(out, indent_level + 2) << element->get_local_name();
+
+      if (!element->_attributes.is_empty()) {
+        out << " " << element->_attributes;
+      }
+
+      if (element->_initializer != nullptr) {
+        out << " = " << *element->_initializer;
       }
       out << ",\n";
     }

+ 6 - 3
dtool/src/cppparser/cppEnumType.h

@@ -32,15 +32,18 @@ class CPPScope;
 class CPPEnumType : public CPPExtensionType {
 public:
   CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
-              CPPScope *scope, const CPPFile &file);
+              CPPScope *scope, const CPPFile &file,
+              CPPAttributeList attr = CPPAttributeList());
   CPPEnumType(Type type, CPPIdentifier *ident, CPPType *element_type,
-              CPPScope *current_scope, CPPScope *scope, const CPPFile &file);
+              CPPScope *current_scope, CPPScope *scope, const CPPFile &file,
+              CPPAttributeList attr = CPPAttributeList());
 
   bool is_scoped() const;
   CPPType *get_underlying_type();
 
   CPPInstance *add_element(const std::string &name, CPPExpression *value,
-                           CPPPreprocessor *preprocessor, const cppyyltype &pos);
+                           CPPPreprocessor *preprocessor, const cppyyltype &pos,
+                           CPPAttributeList attr = CPPAttributeList());
 
   virtual bool is_incomplete() const;
 

+ 5 - 1
dtool/src/cppparser/cppExtensionType.cxx

@@ -23,7 +23,7 @@
 CPPExtensionType::
 CPPExtensionType(CPPExtensionType::Type type,
                  CPPIdentifier *ident, CPPScope *current_scope,
-                 const CPPFile &file) :
+                 const CPPFile &file, CPPAttributeList attr) :
   CPPType(file),
   _type(type), _ident(ident),
   _alignment(nullptr)
@@ -31,6 +31,7 @@ CPPExtensionType(CPPExtensionType::Type type,
   if (_ident != nullptr) {
     _ident->_native_scope = current_scope;
   }
+  _attributes = std::move(attr);
 }
 
 /**
@@ -215,6 +216,9 @@ output(std::ostream &out, int, CPPScope *scope, bool complete) const {
     if (complete || cppparser_output_class_keyword) {
       out << _type << " ";
     }
+    if (complete && !_attributes.is_empty()) {
+      out << _attributes << " ";
+    }
     out << _ident->get_local_name(scope);
 
   } else if (!_typedefs.empty()) {

+ 1 - 1
dtool/src/cppparser/cppExtensionType.h

@@ -39,7 +39,7 @@ public:
   };
 
   CPPExtensionType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
-                   const CPPFile &file);
+                   const CPPFile &file, CPPAttributeList attr = CPPAttributeList());
 
   virtual std::string get_simple_name() const;
   virtual std::string get_local_name(CPPScope *scope = nullptr) const;

+ 20 - 9
dtool/src/cppparser/cppFunctionType.cxx

@@ -224,10 +224,13 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
     if (_flags & F_override) {
       out << " override";
     }
+    if (!_attributes.is_empty()) {
+      out << " " << _attributes;
+    }
     out << " -> ";
     _return_type->output(out, indent_level, scope, false);
-
-  } else {
+  }
+  else {
     _return_type->output(out, indent_level, scope, complete);
     out << "(";
     _parameters->output(out, scope, true, num_default_parameters);
@@ -244,6 +247,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete,
     if (_flags & F_override) {
       out << " override";
     }
+    if (!_attributes.is_empty()) {
+      out << " " << _attributes;
+    }
   }
 }
 
@@ -278,8 +284,8 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
   if (_flags & (F_constructor | F_destructor)) {
     // No return type for constructors and destructors.
     out << prename << name << str;
-
-  } else if (_flags & F_trailing_return_type) {
+  }
+  else if (_flags & F_trailing_return_type) {
     // It was declared using trailing return type, so let's format it that
     // way.
     out << "auto ";
@@ -291,12 +297,13 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
     }
 
     out << str;
-
-  } else if (_flags & F_operator_typecast) {
+  }
+  else if (_flags & F_operator_typecast) {
     out << "operator ";
-    _return_type->output_instance(out, indent_level, scope, complete, "", prename + str);
-
-  } else {
+    _return_type->output_instance(out, indent_level, scope, complete,
+                                  "", prename + str);
+  }
+  else {
     if (prename.empty()) {
       _return_type->output_instance(out, indent_level, scope, complete,
                                     "", prename + name + str);
@@ -322,6 +329,10 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
     out << " override";
   }
 
+  if (!_attributes.is_empty()) {
+    out << " " << _attributes;
+  }
+
   if (_flags & F_trailing_return_type) {
     out << " -> ";
     _return_type->output(out, indent_level, scope, false);

+ 8 - 0
dtool/src/cppparser/cppIdentifier.cxx

@@ -84,6 +84,14 @@ add_name(const CPPNameComponent &name) {
   _names.push_back(name);
 }
 
+/**
+ *
+ */
+void CPPIdentifier::
+prepend(CPPIdentifier *ident) {
+  _names.insert(_names.begin(), ident->_names.begin(), ident->_names.end());
+}
+
 /**
  *
  */

+ 2 - 0
dtool/src/cppparser/cppIdentifier.h

@@ -41,6 +41,8 @@ public:
   void add_name(const std::string &name);
   void add_name(const CPPNameComponent &name);
 
+  void prepend(CPPIdentifier *ident);
+
   bool operator == (const CPPIdentifier &other) const;
   bool operator != (const CPPIdentifier &other) const;
   bool operator < (const CPPIdentifier &other) const;

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

@@ -37,7 +37,6 @@ CPPInstance(CPPType *type, const string &name, int storage_class) :
   _type(type),
   _ident(new CPPIdentifier(name)),
   _storage_class(storage_class),
-  _alignment(nullptr),
   _bit_width(-1)
 {
   _initializer = nullptr;
@@ -52,7 +51,6 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
   _type(type),
   _ident(ident),
   _storage_class(storage_class),
-  _alignment(nullptr),
   _bit_width(-1)
 {
   _initializer = nullptr;
@@ -66,11 +64,11 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
 CPPInstance::
 CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
             const CPPFile &file) :
-  CPPDeclaration(file),
-  _alignment(nullptr)
+  CPPDeclaration(file)
 {
   _type = ii->unroll_type(type);
   _ident = ii->_ident;
+  _attributes = ii->_attributes;
   ii->_ident = nullptr;
   _storage_class = storage_class;
   _initializer = nullptr;
@@ -111,7 +109,6 @@ CPPInstance(const CPPInstance &copy) :
   _ident(copy._ident),
   _initializer(copy._initializer),
   _storage_class(copy._storage_class),
-  _alignment(copy._alignment),
   _bit_width(copy._bit_width)
 {
   assert(_type != nullptr);
@@ -156,7 +153,7 @@ operator == (const CPPInstance &other) const {
   if (_storage_class != other._storage_class) {
     return false;
   }
-  if (_alignment != other._alignment) {
+  if (_attributes != other._attributes) {
     return false;
   }
 
@@ -200,8 +197,8 @@ operator < (const CPPInstance &other) const {
   if (_storage_class != other._storage_class) {
     return _storage_class < other._storage_class;
   }
-  if (_alignment != other._alignment) {
-    return _alignment < other._alignment;
+  if (_attributes != other._attributes) {
+    return _attributes < other._attributes;
   }
 
   // We *do* care about the identifier.  We need to differentiate types of
@@ -264,7 +261,7 @@ set_initializer(CPPExpression *initializer) {
  */
 void CPPInstance::
 set_alignment(int align) {
-  _alignment = new CPPExpression(align);
+  _attributes.add_alignas(align);
 }
 
 /**
@@ -274,7 +271,7 @@ set_alignment(int align) {
  */
 void CPPInstance::
 set_alignment(CPPExpression *const_expr) {
-  _alignment = const_expr;
+  _attributes.add_alignas(const_expr);
 }
 
 /**
@@ -544,8 +541,8 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete,
     indent(out, indent_level);
   }
 
-  if (_alignment != nullptr) {
-    out << "alignas(" << *_alignment << ") ";
+  if (!_attributes.is_empty()) {
+    out << _attributes << " ";
   }
 
   if (_storage_class & SC_static) {
@@ -600,8 +597,8 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete,
     _type->as_function_type()->
       output_instance(out, indent_level, scope, complete, "", name,
                       num_default_parameters);
-
-  } else {
+  }
+  else {
     _type->output_instance(out, indent_level, scope, complete, "", name);
   }
 
@@ -623,7 +620,6 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete,
   }
 }
 
-
 /**
  *
  */

+ 1 - 1
dtool/src/cppparser/cppInstance.h

@@ -19,6 +19,7 @@
 #include "cppDeclaration.h"
 #include "cppType.h"
 #include "cppTemplateParameterList.h"
+#include "cppAttributeList.h"
 
 class CPPInstanceIdentifier;
 class CPPIdentifier;
@@ -127,7 +128,6 @@ public:
   CPPExpression *_initializer;
 
   int _storage_class;
-  CPPExpression *_alignment;
   int _bit_width;
 
 private:

+ 40 - 16
dtool/src/cppparser/cppInstanceIdentifier.cxx

@@ -25,20 +25,22 @@
  *
  */
 CPPInstanceIdentifier::Modifier::
-Modifier(CPPInstanceIdentifierType type) :
+Modifier(CPPInstanceIdentifierType type, CPPAttributeList attr) :
   _type(type),
   _func_params(nullptr),
   _func_flags(0),
   _scoping(nullptr),
-  _expr(nullptr) {
+  _expr(nullptr),
+  _attributes(std::move(attr)) {
 }
 
 /**
  *
  */
 CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier::
-func_type(CPPParameterList *params, int flags, CPPType *trailing_return_type) {
-  Modifier mod(IIT_func);
+func_type(CPPParameterList *params, int flags, CPPType *trailing_return_type,
+          CPPAttributeList attr) {
+  Modifier mod(IIT_func, std::move(attr));
   mod._func_params = params;
   mod._func_flags = flags;
   mod._trailing_return_type = trailing_return_type;
@@ -49,8 +51,8 @@ func_type(CPPParameterList *params, int flags, CPPType *trailing_return_type) {
  *
  */
 CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier::
-array_type(CPPExpression *expr) {
-  Modifier mod(IIT_array);
+array_type(CPPExpression *expr, CPPAttributeList attr) {
+  Modifier mod(IIT_array, std::move(attr));
   mod._expr = expr;
   return mod;
 }
@@ -59,8 +61,8 @@ array_type(CPPExpression *expr) {
  *
  */
 CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier::
-scoped_pointer_type(CPPIdentifier *scoping) {
-  Modifier mod(IIT_scoped_pointer);
+scoped_pointer_type(CPPIdentifier *scoping, CPPAttributeList attr) {
+  Modifier mod(IIT_scoped_pointer, std::move(attr));
   mod._scoping = scoping;
   return mod;
 }
@@ -86,6 +88,17 @@ CPPInstanceIdentifier(CPPIdentifier *ident) :
   _packed(false) {
 }
 
+/**
+ *
+ */
+CPPInstanceIdentifier::
+CPPInstanceIdentifier(CPPIdentifier *ident, CPPAttributeList attributes) :
+  _ident(ident),
+  _attributes(std::move(attributes)),
+  _bit_width(nullptr),
+  _packed(false) {
+}
+
 /**
  * Unrolls the list of type punctuation on either side of the identifier to
  * determine the actual type represented by the identifier, given the
@@ -103,15 +116,16 @@ unroll_type(CPPType *start_type) {
  *
  */
 void CPPInstanceIdentifier::
-add_modifier(CPPInstanceIdentifierType type) {
-  _modifiers.push_back(Modifier(type));
+add_modifier(CPPInstanceIdentifierType type, CPPAttributeList attr) {
+  _modifiers.push_back(Modifier(type, std::move(attr)));
 }
 
 /**
  *
  */
 void CPPInstanceIdentifier::
-add_func_modifier(CPPParameterList *params, int flags, CPPType *trailing_return_type) {
+add_func_modifier(CPPParameterList *params, int flags,
+                  CPPType *trailing_return_type, CPPAttributeList attr) {
   // As a special hack, if we added a parameter list to an operator function,
   // check if the parameter list is empty.  If it is, this is really a unary
   // operator, so set the unary_op flag.  Operators () and [] are never
@@ -134,22 +148,22 @@ add_func_modifier(CPPParameterList *params, int flags, CPPType *trailing_return_
     flags |= CPPFunctionType::F_trailing_return_type;
   }
 
-  _modifiers.push_back(Modifier::func_type(params, flags, trailing_return_type));
+  _modifiers.push_back(Modifier::func_type(params, flags, trailing_return_type, std::move(attr)));
 }
 
 /**
  *
  */
 void CPPInstanceIdentifier::
-add_scoped_pointer_modifier(CPPIdentifier *scoping) {
-  _modifiers.push_back(Modifier::scoped_pointer_type(scoping));
+add_scoped_pointer_modifier(CPPIdentifier *scoping, CPPAttributeList attr) {
+  _modifiers.push_back(Modifier::scoped_pointer_type(scoping, std::move(attr)));
 }
 
 /**
  *
  */
 void CPPInstanceIdentifier::
-add_array_modifier(CPPExpression *expr) {
+add_array_modifier(CPPExpression *expr, CPPAttributeList attr) {
   // Special case for operator new[] and delete[].  We're not really adding an
   // array modifier to them, but appending [] to the identifier.  This is to
   // work around a parser ambiguity.
@@ -158,7 +172,7 @@ add_array_modifier(CPPExpression *expr) {
 
     _ident->_names.back().append_name("[]");
   } else {
-    _modifiers.push_back(Modifier::array_type(expr));
+    _modifiers.push_back(Modifier::array_type(expr, std::move(attr)));
   }
 }
 
@@ -187,6 +201,14 @@ add_trailing_return_type(CPPType *type) {
   std::cerr << "trailing return type can only be added to a function\n";
 }
 
+/**
+ * Add attributes to the instance (not the type).
+ */
+void CPPInstanceIdentifier::
+add_attributes(const CPPAttributeList &attributes) {
+  _attributes.add_attributes_from(attributes);
+}
+
 /**
  * Returns the initializer parameter list that was set for this particular
  * instance, e.g.  if the instance were:
@@ -316,5 +338,7 @@ r_unroll_type(CPPType *start_type,
     abort();
   }
 
+  result->_attributes = mod._attributes;
+
   return CPPType::new_type(result);
 }

+ 22 - 8
dtool/src/cppparser/cppInstanceIdentifier.h

@@ -15,6 +15,7 @@
 #define CPPINSTANCEIDENTIFIER_H
 
 #include "dtoolbase.h"
+#include "cppAttributeList.h"
 
 #include <vector>
 #include <string>
@@ -48,18 +49,25 @@ enum CPPInstanceIdentifierType {
 class CPPInstanceIdentifier {
 public:
   CPPInstanceIdentifier(CPPIdentifier *ident);
+  CPPInstanceIdentifier(CPPIdentifier *ident, CPPAttributeList attributes);
 
   CPPType *unroll_type(CPPType *start_type);
 
-  void add_modifier(CPPInstanceIdentifierType type);
+  void add_modifier(CPPInstanceIdentifierType type,
+                    CPPAttributeList attr = CPPAttributeList());
   void add_func_modifier(CPPParameterList *params, int flags,
-                         CPPType *trailing_return_type = nullptr);
-  void add_scoped_pointer_modifier(CPPIdentifier *scoping);
-  void add_array_modifier(CPPExpression *expr);
+                         CPPType *trailing_return_type = nullptr,
+                         CPPAttributeList attr = CPPAttributeList());
+  void add_scoped_pointer_modifier(CPPIdentifier *scoping,
+                                   CPPAttributeList attr = CPPAttributeList());
+  void add_array_modifier(CPPExpression *expr,
+                          CPPAttributeList attr = CPPAttributeList());
   void add_initializer_modifier(CPPParameterList *params);
 
   void add_trailing_return_type(CPPType *type);
 
+  void add_attributes(const CPPAttributeList &attributes);
+
   CPPParameterList *get_initializer() const;
 
   CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope,
@@ -69,11 +77,14 @@ public:
 
   class Modifier {
   public:
-    Modifier(CPPInstanceIdentifierType type);
+    Modifier(CPPInstanceIdentifierType type,
+             CPPAttributeList attr = CPPAttributeList());
     static Modifier func_type(CPPParameterList *params, int flags,
-                              CPPType *trailing_return_type);
-    static Modifier array_type(CPPExpression *expr);
-    static Modifier scoped_pointer_type(CPPIdentifier *scoping);
+                              CPPType *trailing_return_type,
+                              CPPAttributeList attr);
+    static Modifier array_type(CPPExpression *expr, CPPAttributeList attr);
+    static Modifier scoped_pointer_type(CPPIdentifier *scoping,
+                                        CPPAttributeList attr);
     static Modifier initializer_type(CPPParameterList *params);
 
     CPPInstanceIdentifierType _type;
@@ -82,10 +93,13 @@ public:
     CPPIdentifier *_scoping;
     CPPExpression *_expr;
     CPPType *_trailing_return_type;
+    CPPAttributeList _attributes;
   };
   typedef std::vector<Modifier> Modifiers;
   Modifiers _modifiers;
 
+  CPPAttributeList _attributes;
+
   // If not null, indicates a bitfield
   CPPExpression *_bit_width;
 

+ 12 - 6
dtool/src/cppparser/cppNamespace.cxx

@@ -20,8 +20,9 @@
  *
  */
 CPPNamespace::
-CPPNamespace(CPPIdentifier *ident, CPPScope *scope, const CPPFile &file) :
-  CPPDeclaration(file),
+CPPNamespace(CPPIdentifier *ident, CPPScope *scope, const CPPFile &file,
+             CPPAttributeList attr) :
+  CPPDeclaration(file, std::move(attr)),
   _is_inline(false),
   _ident(ident),
   _scope(scope)
@@ -77,15 +78,20 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
   if (_is_inline) {
     out << "inline ";
   }
+  out << "namespace ";
+
   if (!complete && _ident != nullptr) {
     // If we have a name, use it.
     out << "namespace " << _ident->get_local_name(scope);
-
-  } else {
+  }
+  else {
+    if (!_attributes.is_empty()) {
+      out << _attributes << " ";
+    }
     if (_ident != nullptr) {
-      out << "namespace " << _ident->get_local_name(scope) << " {\n";
+      out << _ident->get_local_name(scope) << " {\n";
     } else {
-      out << "namespace {\n";
+      out << "{\n";
     }
 
     _scope->write(out, indent_level + 2, _scope);

+ 1 - 1
dtool/src/cppparser/cppNamespace.h

@@ -27,7 +27,7 @@ class CPPScope;
 class CPPNamespace : public CPPDeclaration {
 public:
   CPPNamespace(CPPIdentifier *ident, CPPScope *scope,
-               const CPPFile &file);
+               const CPPFile &file, CPPAttributeList attr = CPPAttributeList());
 
   std::string get_simple_name() const;
   std::string get_local_name(CPPScope *scope = nullptr) const;

+ 6 - 0
dtool/src/cppparser/cppPointerType.cxx

@@ -247,6 +247,12 @@ output_instance(std::ostream &out, int indent_level, CPPScope *scope,
     star = ftype->_class_owner->get_fully_scoped_name() + "::*";
   }
 
+  if (!_attributes.is_empty()) {
+    std::ostringstream strm;
+    strm << star << _attributes << " ";
+    star = strm.str();
+  }
+
   _pointing_at->output_instance(out, indent_level, scope, complete,
                                 star + prename, name);
 }

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

@@ -72,10 +72,10 @@ public:
   typedef std::map<std::string, CPPManifest *> Manifests;
   Manifests _manifests;
 
-  typedef pvector<CPPManifest *> ManifestStack;
+  typedef std::vector<CPPManifest *> ManifestStack;
   std::map<std::string, ManifestStack> _manifest_stack;
 
-  pvector<CPPFile::Source> _quote_include_kind;
+  std::vector<CPPFile::Source> _quote_include_kind;
   DSearchPath _quote_include_path;
   DSearchPath _angle_include_path;
   bool _noangles;

+ 9 - 6
dtool/src/cppparser/cppReferenceType.cxx

@@ -228,13 +228,16 @@ output_instance(std::ostream &out, int indent_level, CPPScope *scope,
                 bool complete, const std::string &prename,
                 const std::string &name) const {
 
-  if (_value_category == VC_rvalue) {
-    _pointing_at->output_instance(out, indent_level, scope, complete,
-                                  "&&" + prename, name);
-  } else {
-    _pointing_at->output_instance(out, indent_level, scope, complete,
-                                  "&" + prename, name);
+  std::string prefix((_value_category == VC_rvalue) ? "&&" : "&");
+
+  if (!_attributes.is_empty()) {
+    std::ostringstream strm;
+    strm << prefix << _attributes << " ";
+    prefix = strm.str();
   }
+
+  _pointing_at->output_instance(out, indent_level, scope, complete,
+                                prefix + prename, name);
 }
 
 /**

+ 9 - 5
dtool/src/cppparser/cppStructType.cxx

@@ -41,8 +41,8 @@ output(std::ostream &out) const {
 CPPStructType::
 CPPStructType(CPPStructType::Type type, CPPIdentifier *ident,
               CPPScope *current_scope, CPPScope *scope,
-              const CPPFile &file) :
-  CPPExtensionType(type, ident, current_scope, file),
+              const CPPFile &file, CPPAttributeList attr) :
+  CPPExtensionType(type, ident, current_scope, file, std::move(attr)),
   _scope(scope),
   _final(false)
 {
@@ -1261,10 +1261,14 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
       get_template_scope()->_parameters.write_formal(out, scope);
       indent(out, indent_level);
     }
+    out << _type;
+
+    if (!_attributes.is_empty()) {
+      out << " " << _attributes;
+    }
+
     if (_ident != nullptr) {
-      out << _type << " " << _ident->get_local_name(scope);
-    } else {
-      out << _type;
+      out << " " << _ident->get_local_name(scope);
     }
 
     if (_final) {

+ 2 - 1
dtool/src/cppparser/cppStructType.h

@@ -35,7 +35,8 @@ public:
   CPPStructType(Type type, CPPIdentifier *ident,
                 CPPScope *current_scope,
                 CPPScope *scope,
-                const CPPFile &file);
+                const CPPFile &file,
+                CPPAttributeList attr = CPPAttributeList());
   CPPStructType(const CPPStructType &copy);
   void operator = (const CPPStructType &copy);
 

+ 13 - 2
dtool/src/cppparser/cppTypedefType.cxx

@@ -43,7 +43,8 @@ CPPTypedefType(CPPType *type, const string &name, CPPScope *current_scope) :
  *
  */
 CPPTypedefType::
-CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope) :
+CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope,
+               CPPAttributeList attr) :
   CPPType(CPPFile()),
   _type(type),
   _ident(ident),
@@ -53,6 +54,8 @@ CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope) :
     _ident->_native_scope = current_scope;
   }
   _subst_decl_recursive_protect = false;
+
+  _attributes = std::move(attr);
 }
 
 /**
@@ -69,6 +72,7 @@ CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii,
   assert(ii != nullptr);
   _type = ii->unroll_type(type);
   _ident = ii->_ident;
+  _attributes = std::move(ii->_attributes);
   ii->_ident = nullptr;
   delete ii;
 
@@ -388,9 +392,16 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
         get_template_scope()->_parameters.write_formal(out, scope);
         indent(out, indent_level);
       }
-      out << "using " << name << " = ";
+      out << "using " << name;
+      if (!_attributes.is_empty()) {
+        out << " " << _attributes;
+      }
+      out << " = ";
       _type->output(out, 0, scope, false);
     } else {
+      if (!_attributes.is_empty()) {
+        out << _attributes << " ";
+      }
       out << "typedef ";
       _type->output_instance(out, indent_level, scope, false, "", name);
     }

+ 2 - 1
dtool/src/cppparser/cppTypedefType.h

@@ -28,7 +28,8 @@ class CPPInstanceIdentifier;
 class CPPTypedefType : public CPPType {
 public:
   CPPTypedefType(CPPType *type, const std::string &name, CPPScope *current_scope);
-  CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope);
+  CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope,
+                 CPPAttributeList attr = CPPAttributeList());
   CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii,
                  CPPScope *current_scope, const CPPFile &file);
 

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

@@ -1,4 +1,4 @@
-
+#include "cppAttributeList.cxx"
 #include "cppFunctionType.cxx"
 #include "cppGlobals.cxx"
 #include "cppCommentBlock.cxx"

+ 9 - 5
dtool/src/dtoolbase/CMakeLists.txt

@@ -21,7 +21,7 @@ set(P3DTOOLBASE_HEADERS
   atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I
   cmath.I cmath.h
   deletedBufferChain.h deletedBufferChain.I
-  deletedChain.h deletedChain.T
+  deletedChain.h deletedChain.I
   dtoolbase.h dtoolbase_cc.h dtoolsymbols.h
   dtool_platform.h
   fakestringstream.h
@@ -94,12 +94,16 @@ add_component_library(p3dtoolbase NOINIT SYMBOL BUILDING_DTOOL_DTOOLBASE
 target_include_directories(p3dtoolbase PUBLIC
   $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
   $<BUILD_INTERFACE:${PANDA_OUTPUT_DIR}/include>)
-target_link_libraries(p3dtoolbase PKG::EIGEN PKG::THREADS PKG::MIMALLOC)
+target_link_libraries(p3dtoolbase PKG::EIGEN PKG::THREADS)
 target_interrogate(p3dtoolbase ${P3DTOOLBASE_SOURCES} EXTENSIONS ${P3DTOOLBASE_IGATEEXT})
 
-if(HAVE_MIMALLOC AND CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$")
-  # Do not re-export symbols from these libraries.
-  target_link_options(p3dtoolbase PRIVATE "LINKER:--exclude-libs,libmimalloc.a")
+if(HAVE_MIMALLOC AND USE_MEMORY_MIMALLOC)
+  target_link_libraries(p3dtoolbase PKG::MIMALLOC)
+
+  if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$")
+    # Do not re-export symbols from these libraries.
+    target_link_options(p3dtoolbase PRIVATE "LINKER:--exclude-libs,libmimalloc.a")
+  endif()
 endif()
 
 if(NOT BUILD_METALIBS)

+ 52 - 0
dtool/src/dtoolbase/deletedBufferChain.I

@@ -11,6 +11,34 @@
  * @date 2007-07-20
  */
 
+/**
+ * Use get_deleted_chain() to get a new DeletedBufferChain of the appropriate
+ * size.
+ */
+constexpr DeletedBufferChain::
+DeletedBufferChain(size_t buffer_size) : _buffer_size(buffer_size) {
+}
+
+/**
+ * Move constructor.
+ */
+INLINE DeletedBufferChain::
+DeletedBufferChain(DeletedBufferChain &&from) noexcept :
+  _deleted_chain(from._deleted_chain),
+  _buffer_size(from._buffer_size) {
+  from._deleted_chain = nullptr;
+}
+
+/**
+ * Copy constructor.
+ */
+INLINE DeletedBufferChain::
+DeletedBufferChain(const DeletedBufferChain &copy) :
+  _deleted_chain(nullptr),
+  _buffer_size(copy._buffer_size) {
+  assert(copy._deleted_chain == nullptr);
+}
+
 /**
  * Returns true if the pointer is valid, false if it has been deleted or if it
  * was never a valid pointer.
@@ -41,6 +69,30 @@ get_buffer_size() const {
   return _buffer_size;
 }
 
+/**
+ *
+ */
+INLINE bool DeletedBufferChain::
+operator < (const DeletedBufferChain &other) const {
+  return _buffer_size < other._buffer_size;
+}
+
+/**
+ * Returns a deleted chain of the given size.
+ */
+INLINE DeletedBufferChain *DeletedBufferChain::
+get_deleted_chain(size_t buffer_size) {
+  // We must allocate at least this much space for bookkeeping reasons.
+  buffer_size = (std::max)(buffer_size, sizeof(ObjectNode));
+
+  size_t index = ((buffer_size + sizeof(void *) - 1) / sizeof(void *)) - 1;
+  if (index < num_small_deleted_chains) {
+    return &_small_deleted_chains[index];
+  } else {
+    return get_large_deleted_chain((index + 1) * sizeof(void *));
+  }
+}
+
 /**
  * Casts an ObjectNode* to a void* buffer.
  */

+ 42 - 12
dtool/src/dtoolbase/deletedBufferChain.cxx

@@ -14,18 +14,34 @@
 #include "deletedBufferChain.h"
 #include "memoryHook.h"
 
-/**
- * Use the global MemoryHook to get a new DeletedBufferChain of the
- * appropriate size.
- */
-DeletedBufferChain::
-DeletedBufferChain(size_t buffer_size) {
-  _deleted_chain = nullptr;
-  _buffer_size = buffer_size;
-
-  // We must allocate at least this much space for bookkeeping reasons.
-  _buffer_size = std::max(_buffer_size, sizeof(ObjectNode));
-}
+#include <set>
+
+DeletedBufferChain DeletedBufferChain::_small_deleted_chains[DeletedBufferChain::num_small_deleted_chains] = {
+  DeletedBufferChain(sizeof(void *)),
+  DeletedBufferChain(sizeof(void *) * 2),
+  DeletedBufferChain(sizeof(void *) * 3),
+  DeletedBufferChain(sizeof(void *) * 4),
+  DeletedBufferChain(sizeof(void *) * 5),
+  DeletedBufferChain(sizeof(void *) * 6),
+  DeletedBufferChain(sizeof(void *) * 7),
+  DeletedBufferChain(sizeof(void *) * 8),
+  DeletedBufferChain(sizeof(void *) * 9),
+  DeletedBufferChain(sizeof(void *) * 10),
+  DeletedBufferChain(sizeof(void *) * 11),
+  DeletedBufferChain(sizeof(void *) * 12),
+  DeletedBufferChain(sizeof(void *) * 13),
+  DeletedBufferChain(sizeof(void *) * 14),
+  DeletedBufferChain(sizeof(void *) * 15),
+  DeletedBufferChain(sizeof(void *) * 16),
+  DeletedBufferChain(sizeof(void *) * 17),
+  DeletedBufferChain(sizeof(void *) * 18),
+  DeletedBufferChain(sizeof(void *) * 19),
+  DeletedBufferChain(sizeof(void *) * 20),
+  DeletedBufferChain(sizeof(void *) * 21),
+  DeletedBufferChain(sizeof(void *) * 22),
+  DeletedBufferChain(sizeof(void *) * 23),
+  DeletedBufferChain(sizeof(void *) * 24),
+};
 
 /**
  * Allocates the memory for a new buffer of the indicated size (which must be
@@ -36,6 +52,7 @@ allocate(size_t size, TypeHandle type_handle) {
 #ifdef USE_DELETED_CHAIN
   // TAU_PROFILE("void *DeletedBufferChain::allocate(size_t, TypeHandle)", "
   // ", TAU_USER);
+  // If this triggers, maybe you forgot ALLOC_DELETED_CHAIN in a subclass?
   assert(size <= _buffer_size);
 
   // Determine how much space to allocate.
@@ -139,3 +156,16 @@ deallocate(void *ptr, TypeHandle type_handle) {
   PANDA_FREE_SINGLE(ptr);
 #endif  // USE_DELETED_CHAIN
 }
+
+/**
+ * Returns a new DeletedBufferChain.
+ */
+DeletedBufferChain *DeletedBufferChain::
+get_large_deleted_chain(size_t buffer_size) {
+  static MutexImpl lock;
+  lock.lock();
+  static std::set<DeletedBufferChain> deleted_chains;
+  DeletedBufferChain *result = (DeletedBufferChain *)&*deleted_chains.insert(DeletedBufferChain(buffer_size)).first;
+  lock.unlock();
+  return result;
+}

+ 17 - 3
dtool/src/dtoolbase/deletedBufferChain.h

@@ -58,16 +58,25 @@ enum DeletedChainFlag : unsigned int {
  */
 class EXPCL_DTOOL_DTOOLBASE DeletedBufferChain {
 protected:
-  DeletedBufferChain(size_t buffer_size);
+  constexpr explicit DeletedBufferChain(size_t buffer_size);
 
 public:
+  INLINE DeletedBufferChain(DeletedBufferChain &&from) noexcept;
+  INLINE DeletedBufferChain(const DeletedBufferChain &copy);
+
   void *allocate(size_t size, TypeHandle type_handle);
   void deallocate(void *ptr, TypeHandle type_handle);
 
   INLINE bool validate(void *ptr);
   INLINE size_t get_buffer_size() const;
 
+  INLINE bool operator < (const DeletedBufferChain &other) const;
+
+  static INLINE DeletedBufferChain *get_deleted_chain(size_t buffer_size);
+
 private:
+  static DeletedBufferChain *get_large_deleted_chain(size_t buffer_size);
+
   class ObjectNode {
   public:
 #ifdef USE_DELETEDCHAINFLAG
@@ -87,10 +96,10 @@ private:
   static INLINE void *node_to_buffer(ObjectNode *node);
   static INLINE ObjectNode *buffer_to_node(void *buffer);
 
-  ObjectNode *_deleted_chain;
+  ObjectNode *_deleted_chain = nullptr;
 
   MutexImpl _lock;
-  size_t _buffer_size;
+  const size_t _buffer_size;
 
 #ifndef USE_DELETEDCHAINFLAG
   // Without DELETEDCHAINFLAG, we don't even store the _flag member at all.
@@ -101,6 +110,11 @@ private:
   static const size_t flag_reserved_bytes = sizeof(AtomicAdjust::Integer);
 #endif  // USE_DELETEDCHAINFLAG
 
+  // This array stores the deleted chains for smaller sizes, starting with
+  // sizeof(void *) and increasing in multiples thereof.
+  static const size_t num_small_deleted_chains = 24;
+  static DeletedBufferChain _small_deleted_chains[num_small_deleted_chains];
+
   friend class MemoryHook;
 };
 

+ 4 - 5
dtool/src/dtoolbase/deletedChain.T → dtool/src/dtoolbase/deletedChain.I

@@ -6,7 +6,7 @@
  * license.  You should have received a copy of this license along
  * with this source code in a file named "LICENSE."
  *
- * @file deletedChain.T
+ * @file deletedChain.I
  * @author drose
  * @date 2006-04-01
  */
@@ -82,7 +82,7 @@ validate(const Type *ptr) {
 template<class Type>
 INLINE ReferenceCount *DeletedChain<Type>::
 make_ref_ptr(void *) {
-  return NULL;
+  return nullptr;
 }
 
 /**
@@ -106,9 +106,8 @@ make_ref_ptr(ReferenceCount *ptr) {
 template<class Type>
 void DeletedChain<Type>::
 init_deleted_chain() {
-  if (_chain == (DeletedBufferChain *)NULL) {
-    init_memory_hook();
-    _chain = memory_hook->get_deleted_chain(sizeof(Type));
+  if (_chain == nullptr) {
+    _chain = DeletedBufferChain::get_deleted_chain(sizeof(Type));
   }
 }
 

+ 1 - 1
dtool/src/dtoolbase/deletedChain.h

@@ -136,6 +136,6 @@ public:
 
 #endif  // USE_DELETED_CHAIN
 
-#include "deletedChain.T"
+#include "deletedChain.I"
 
 #endif

+ 3 - 0
dtool/src/dtoolbase/dtool_platform.h

@@ -79,6 +79,9 @@
 
 #elif defined(__ppc__)
 #define DTOOL_PLATFORM "linux_ppc"
+
+#elif defined(__e2k__)
+#define DTOOL_PLATFORM "linux_e2k"
 #endif
 
 #if !defined(DTOOL_PLATFORM) && !defined(CPPPARSER)

+ 5 - 21
dtool/src/dtoolbase/dtoolbase.cxx

@@ -23,34 +23,18 @@
 bool __tau_shutdown = false;
 #endif
 
-MemoryHook *memory_hook;
+MemoryHook default_memory_hook;
+MemoryHook *memory_hook = &default_memory_hook;
 
 /**
- * Any code that might need to use PANDA_MALLOC or PANDA_FREE, or any methods
- * of the global memory_hook object, at static init time, should ensure that
- * it calls init_memory_hook() first to ensure that the pointer has been
- * properly initialized.  There is no harm in calling this function more than
- * once.
- *
- * There is no need to call this function other than at static init time.
+ * It used to be necessary to call this before using operator new at static
+ * init time.  There is no need to call this function anymore.
  */
 void
 init_memory_hook() {
-  if (memory_hook == nullptr) {
-    memory_hook = new MemoryHook;
-  }
+  assert(memory_hook != nullptr);
 }
 
-// Here's a quick way to ensure the above function is called at least once at
-// static init time.
-class InitMemoryHook {
-public:
-  InitMemoryHook() {
-    init_memory_hook();
-  }
-};
-static InitMemoryHook _imh_object;
-
 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
 
 static void

+ 8 - 2
dtool/src/dtoolbase/memoryHook.I

@@ -18,7 +18,7 @@
 INLINE void MemoryHook::
 inc_heap(size_t size) {
 #ifdef DO_MEMORY_USAGE
-  AtomicAdjust::add(_requested_heap_size, (AtomicAdjust::Integer)size);
+  _requested_heap_size.fetch_add(size, std::memory_order_relaxed);
 #endif  // DO_MEMORY_USAGE
 }
 
@@ -30,7 +30,7 @@ INLINE void MemoryHook::
 dec_heap(size_t size) {
 #ifdef DO_MEMORY_USAGE
   // assert((int)size <= _requested_heap_size);
-  AtomicAdjust::add(_requested_heap_size, -(AtomicAdjust::Integer)size);
+  _requested_heap_size.fetch_sub(size, std::memory_order_relaxed);
 #endif  // DO_MEMORY_USAGE
 }
 
@@ -40,6 +40,9 @@ dec_heap(size_t size) {
  */
 INLINE size_t MemoryHook::
 get_page_size() const {
+  if (_page_size == 0) {
+    determine_page_size();
+  }
   return _page_size;
 }
 
@@ -49,6 +52,9 @@ get_page_size() const {
  */
 INLINE size_t MemoryHook::
 round_up_to_page_size(size_t size) const {
+  if (_page_size == 0) {
+    determine_page_size();
+  }
   return  ((size + _page_size - 1) / _page_size) * _page_size;
 }
 

+ 43 - 80
dtool/src/dtoolbase/memoryHook.cxx

@@ -198,58 +198,19 @@ ptr_to_alloc(void *ptr, size_t &size) {
 #endif  // DO_MEMORY_USAGE
 }
 
-/**
- *
- */
-MemoryHook::
-MemoryHook() {
-#ifdef _WIN32
-
-  // Windows case.
-  SYSTEM_INFO sysinfo;
-  GetSystemInfo(&sysinfo);
-
-  _page_size = (size_t)sysinfo.dwPageSize;
-
-#else
-
-  // Posix case.
-  _page_size = sysconf(_SC_PAGESIZE);
-
-#endif  // WIN32
-
-  _total_heap_single_size = 0;
-  _total_heap_array_size = 0;
-  _requested_heap_size = 0;
-  _total_mmap_size = 0;
-  _max_heap_size = ~(size_t)0;
-}
-
 /**
  *
  */
 MemoryHook::
 MemoryHook(const MemoryHook &copy) :
-  _total_heap_single_size(copy._total_heap_single_size),
-  _total_heap_array_size(copy._total_heap_array_size),
-  _requested_heap_size(copy._requested_heap_size),
-  _total_mmap_size(copy._total_mmap_size),
+  _total_heap_single_size(copy._total_heap_single_size.load(std::memory_order_relaxed)),
+  _total_heap_array_size(copy._total_heap_array_size.load(std::memory_order_relaxed)),
+  _requested_heap_size(copy._requested_heap_size.load(std::memory_order_relaxed)),
+  _total_mmap_size(copy._total_mmap_size.load(std::memory_order_relaxed)),
   _max_heap_size(copy._max_heap_size),
   _page_size(copy._page_size) {
-
-  copy._lock.lock();
-  _deleted_chains = copy._deleted_chains;
-  copy._lock.unlock();
 }
 
-/**
- *
- */
-MemoryHook::
-~MemoryHook() {
-  // Really, we only have this destructor to shut up gcc about the virtual
-  // functions warning.
-}
 
 /**
  * Allocates a block of memory from the heap, similar to malloc().  This will
@@ -289,9 +250,9 @@ heap_alloc_single(size_t size) {
   size = get_ptr_size(alloc);
   inflated_size = size;
 #endif
-  AtomicAdjust::add(_total_heap_single_size, (AtomicAdjust::Integer)size);
-  if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
-      (size_t)AtomicAdjust::get(_total_heap_array_size) >
+  _total_heap_single_size.fetch_add(size, std::memory_order_relaxed);
+  if (_total_heap_single_size.load(std::memory_order_relaxed) +
+      _total_heap_array_size.load(std::memory_order_relaxed) >
       _max_heap_size) {
     overflow_heap_size();
   }
@@ -314,8 +275,8 @@ heap_free_single(void *ptr) {
   void *alloc = ptr_to_alloc(ptr, size);
 
 #ifdef DO_MEMORY_USAGE
-  assert((int)size <= _total_heap_single_size);
-  AtomicAdjust::add(_total_heap_single_size, -(AtomicAdjust::Integer)size);
+  assert((int)size <= _total_heap_single_size.load(std::memory_order_relaxed));
+  _total_heap_single_size.fetch_sub(size, std::memory_order_relaxed);
 #endif  // DO_MEMORY_USAGE
 
 #ifdef MEMORY_HOOK_MALLOC_LOCK
@@ -366,9 +327,9 @@ heap_alloc_array(size_t size) {
   size = get_ptr_size(alloc);
   inflated_size = size;
 #endif
-  AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size);
-  if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
-      (size_t)AtomicAdjust::get(_total_heap_array_size) >
+  _total_heap_array_size.fetch_add(size, std::memory_order_relaxed);
+  if (_total_heap_single_size.load(std::memory_order_relaxed) +
+      _total_heap_array_size.load(std::memory_order_relaxed) >
       _max_heap_size) {
     overflow_heap_size();
   }
@@ -422,8 +383,8 @@ heap_realloc_array(void *ptr, size_t size) {
   size = get_ptr_size(alloc1);
   inflated_size = size;
 #endif
-  assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size);
-  AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size);
+  assert(orig_size <= _total_heap_array_size.load(std::memory_order_relaxed));
+  _total_heap_array_size.fetch_add(size - orig_size, std::memory_order_relaxed);
 #endif  // DO_MEMORY_USAGE
 
   // Align this to the requested boundary.
@@ -463,7 +424,7 @@ heap_free_array(void *ptr) {
 
 #ifdef DO_MEMORY_USAGE
   assert((int)size <= _total_heap_array_size);
-  AtomicAdjust::add(_total_heap_array_size, -(AtomicAdjust::Integer)size);
+  _total_heap_array_size.fetch_sub(size, std::memory_order_relaxed);
 #endif  // DO_MEMORY_USAGE
 
 #ifdef MEMORY_HOOK_MALLOC_LOCK
@@ -522,10 +483,13 @@ heap_trim(size_t pad) {
  */
 void *MemoryHook::
 mmap_alloc(size_t size, bool allow_exec) {
+  if (_page_size == 0) {
+    determine_page_size();
+  }
   assert((size % _page_size) == 0);
 
 #ifdef DO_MEMORY_USAGE
-  _total_mmap_size += size;
+  _total_mmap_size.fetch_add(size, std::memory_order_relaxed);
 #endif
 
 #ifdef _WIN32
@@ -576,11 +540,12 @@ mmap_alloc(size_t size, bool allow_exec) {
  */
 void MemoryHook::
 mmap_free(void *ptr, size_t size) {
+  assert(_page_size != 0);
   assert((size % _page_size) == 0);
 
 #ifdef DO_MEMORY_USAGE
-  assert((int)size <= _total_mmap_size);
-  _total_mmap_size -= size;
+  assert((int)size <= _total_mmap_size.load(std::memory_order_relaxed));
+  _total_mmap_size.fetch_sub(size, std::memory_order_relaxed);
 #endif
 
 #ifdef _WIN32
@@ -601,29 +566,6 @@ void MemoryHook::
 mark_pointer(void *, size_t, ReferenceCount *) {
 }
 
-/**
- * Returns a pointer to a global DeletedBufferChain object suitable for
- * allocating arrays of the indicated size.  There is one unique
- * DeletedBufferChain object for every different size.
- */
-DeletedBufferChain *MemoryHook::
-get_deleted_chain(size_t buffer_size) {
-  DeletedBufferChain *chain;
-
-  _lock.lock();
-  DeletedChains::iterator dci = _deleted_chains.find(buffer_size);
-  if (dci != _deleted_chains.end()) {
-    chain = (*dci).second;
-  } else {
-    // Once allocated, this DeletedBufferChain object is never deleted.
-    chain = new DeletedBufferChain(buffer_size);
-    _deleted_chains.insert(DeletedChains::value_type(buffer_size, chain));
-  }
-
-  _lock.unlock();
-  return chain;
-}
-
 /**
  * This callback method is called whenever a low-level call to call_malloc()
  * has returned NULL, indicating failure.
@@ -656,3 +598,24 @@ overflow_heap_size() {
   _max_heap_size = ~(size_t)0;
 #endif  // DO_MEMORY_USAGE
 }
+
+/**
+ * Asks the operating system for the page size.
+ */
+void MemoryHook::
+determine_page_size() const {
+#ifdef _WIN32
+  // Windows case.
+  SYSTEM_INFO sysinfo;
+  GetSystemInfo(&sysinfo);
+
+  _page_size = (size_t)sysinfo.dwPageSize;
+
+#else
+  // Posix case.
+  _page_size = sysconf(_SC_PAGESIZE);
+
+#endif  // WIN32
+
+  assert(_page_size != 0);
+}

+ 11 - 16
dtool/src/dtoolbase/memoryHook.h

@@ -16,12 +16,10 @@
 
 #include "dtoolbase.h"
 #include "numeric_types.h"
-#include "atomicAdjust.h"
+#include "patomic.h"
 #include "mutexImpl.h"
 #include <map>
 
-class DeletedBufferChain;
-
 /**
  * This class provides a wrapper around the various possible malloc schemes
  * Panda might employ.  It also exists to allow the MemoryUsage class in Panda
@@ -36,9 +34,9 @@ class DeletedBufferChain;
  */
 class EXPCL_DTOOL_DTOOLBASE MemoryHook {
 public:
-  MemoryHook();
+  constexpr MemoryHook() = default;
   MemoryHook(const MemoryHook &copy);
-  virtual ~MemoryHook();
+  virtual ~MemoryHook() = default;
 
   virtual void *heap_alloc_single(size_t size);
   virtual void heap_free_single(void *ptr);
@@ -63,29 +61,26 @@ public:
 
   virtual void mark_pointer(void *ptr, size_t orig_size, ReferenceCount *ref_ptr);
 
-  DeletedBufferChain *get_deleted_chain(size_t buffer_size);
-
   virtual void alloc_fail(size_t attempted_size);
 
   INLINE static size_t get_ptr_size(void *ptr);
 
 protected:
-  TVOLATILE AtomicAdjust::Integer _total_heap_single_size;
-  TVOLATILE AtomicAdjust::Integer _total_heap_array_size;
-  TVOLATILE AtomicAdjust::Integer _requested_heap_size;
-  TVOLATILE AtomicAdjust::Integer _total_mmap_size;
+  patomic<size_t> _total_heap_single_size { 0u };
+  patomic<size_t> _total_heap_array_size { 0u };
+  patomic<size_t> _requested_heap_size { 0u };
+  patomic<size_t> _total_mmap_size { 0u };
 
   // If the allocated heap size crosses this threshold, we call
   // overflow_heap_size().
-  size_t _max_heap_size;
+  size_t _max_heap_size = ~(size_t)0;
 
   virtual void overflow_heap_size();
 
-private:
-  size_t _page_size;
+  void determine_page_size() const;
 
-  typedef std::map<size_t, DeletedBufferChain *> DeletedChains;
-  DeletedChains _deleted_chains;
+private:
+  mutable size_t _page_size = 0;
 
   mutable MutexImpl _lock;
 };

+ 2 - 0
dtool/src/dtoolbase/mutexSpinlockImpl.cxx

@@ -20,6 +20,8 @@
 #if defined(__i386__) || defined(__x86_64) || defined(_M_IX86) || defined(_M_X64)
 #include <emmintrin.h>
 #define PAUSE() _mm_pause()
+#elif defined(_WIN32)
+#define PAUSE() YieldProcessor()
 #else
 #define PAUSE()
 #endif

+ 1 - 0
dtool/src/dtoolbase/patomic.I

@@ -63,6 +63,7 @@ template<class T>
 ALWAYS_INLINE T patomic<T>::
 operator=(T desired) noexcept {
   _value = desired;
+  return desired;
 }
 
 /**

+ 0 - 19
dtool/src/dtoolbase/typeHandle.cxx

@@ -166,25 +166,6 @@ get_python_type() const {
 }
 #endif
 
-/**
- * Return the Index of the BEst fit Classs from a set
- */
-int TypeHandle::
-get_best_parent_from_Set(const std::set< int > &legal_vals) const {
-  if (legal_vals.find(_index) != legal_vals.end()) {
-    return _index;
-  }
-
-  for (int pi = 0; pi < get_num_parent_classes(); ++pi) {
-    TypeHandle ph = get_parent_class(pi);
-    int val = ph.get_best_parent_from_Set(legal_vals);
-    if (val > 0) {
-      return val;
-    }
-  }
-  return -1;
-}
-
 std::ostream &
 operator << (std::ostream &out, TypeHandle::MemoryClass mem_class) {
   switch (mem_class) {

+ 5 - 3
dtool/src/dtoolbase/typeHandle.h

@@ -97,7 +97,9 @@ PUBLISHED:
   // its value, it  might happen after the value had already been set
   // previously by another static initializer!
 
+#ifdef HAVE_PYTHON
   EXTENSION(static TypeHandle make(PyTypeObject *classobj));
+#endif
 
   INLINE bool operator == (const TypeHandle &other) const;
   INLINE bool operator != (const TypeHandle &other) const;
@@ -121,8 +123,6 @@ PUBLISHED:
   INLINE TypeHandle get_parent_towards(TypeHandle ancestor,
                                        TypedObject *object = nullptr) const;
 
-  int get_best_parent_from_Set(const std::set< int > &legal_vals) const;
-
   size_t get_memory_usage(MemoryClass memory_class) const;
   void inc_memory_usage(MemoryClass memory_class, size_t size);
   void dec_memory_usage(MemoryClass memory_class, size_t size);
@@ -137,13 +137,15 @@ PUBLISHED:
   MAKE_SEQ_PROPERTY(parent_classes, get_num_parent_classes, get_parent_class);
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
 
+#ifdef HAVE_PYTHON
   EXTENSION(PyObject *__reduce__() const);
   EXTENSION(void __setstate__(PyObject *));
+#endif // HAVE_PYTHON
 
 public:
 #ifdef HAVE_PYTHON
   PyObject *get_python_type() const;
-#endif
+#endif // HAVE_PYTHON
 
   void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   void *reallocate_array(void *ptr, size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);

+ 0 - 19
dtool/src/dtoolbase/typeRegistry.cxx

@@ -539,7 +539,6 @@ TypeRegistry() {
  */
 void TypeRegistry::
 init_global_pointer() {
-  init_memory_hook();
   _global_pointer = new TypeRegistry;
 }
 
@@ -696,21 +695,3 @@ look_up_invalid(TypeHandle handle, TypedObject *object) const {
 
   return _handle_registry[handle._index];
 }
-
-/**
-
- */
-extern "C" int
-get_best_parent_from_Set(int id, const std::set<int> &this_set) {
-  // most common case..
-  if (this_set.find(id) != this_set.end()) {
-    return id;
-  }
-
-  TypeHandle th = TypeRegistry::ptr()->find_type_by_id(id);
-  if (th == TypeHandle::none()) {
-    return -1;
-  }
-
-  return th.get_best_parent_from_Set(this_set);
-}

+ 0 - 3
dtool/src/dtoolbase/typeRegistry.h

@@ -118,9 +118,6 @@ private:
   friend class TypeHandle;
 };
 
-// Helper function to allow for "C" interaction into the type system
-extern "C" EXPCL_DTOOL_DTOOLBASE  int get_best_parent_from_Set(int id, const std::set<int> &this_set);
-
 #include "typeHandle.h"
 
 #include "typeRegistry.I"

+ 0 - 8
dtool/src/dtoolbase/typedObject.I

@@ -43,14 +43,6 @@ is_exact_type(TypeHandle handle) const {
   return get_type() == handle;
 }
 
-/**
- *
- */
-INLINE int TypedObject::
-get_best_parent_from_Set(const std::set<int> &inset) const {
-  return get_type().get_best_parent_from_Set(inset);
-}
-
 /**
  * Returns the object, upcast (if necessary) to a TypedObject pointer.
  */

+ 0 - 2
dtool/src/dtoolbase/typedObject.h

@@ -106,8 +106,6 @@ PUBLISHED:
   INLINE bool is_exact_type(TypeHandle handle) const;
 
 public:
-  INLINE int get_best_parent_from_Set(const std::set<int> &) const;
-
   // Derived classes should override this function to call init_type().  It
   // will only be called in error situations when the type was for some reason
   // not properly initialized.

+ 2 - 2
dtool/src/dtoolutil/dSearchPath.h

@@ -53,8 +53,8 @@ PUBLISHED:
   };
 
   DSearchPath() = default;
-  DSearchPath(const std::string &path, const std::string &separator = std::string());
-  DSearchPath(const Filename &directory);
+  explicit DSearchPath(const std::string &path, const std::string &separator = std::string());
+  explicit DSearchPath(const Filename &directory);
   DSearchPath(const DSearchPath &copy) = default;
   DSearchPath(DSearchPath &&from) = default;
   ~DSearchPath() = default;

+ 4 - 0
dtool/src/dtoolutil/executionEnvironment.cxx

@@ -418,6 +418,10 @@ ns_get_environment_variable(const string &var) const {
   } else if (var == "XDG_DATA_HOME") {
     Filename home_dir = Filename::get_home_directory();
     return home_dir.get_fullpath() + "/.local/share";
+
+  } else if (var == "XDG_STATE_HOME") {
+    Filename home_dir = Filename::get_home_directory();
+    return home_dir.get_fullpath() + "/.local/state";
   }
 #endif // _WIN32
 

+ 32 - 21
dtool/src/dtoolutil/filename.cxx

@@ -16,7 +16,6 @@
 #include "dSearchPath.h"
 #include "executionEnvironment.h"
 #include "vector_string.h"
-#include "atomicAdjust.h"
 
 #include <stdio.h>  // For rename() and tempnam()
 #include <time.h>   // for clock() and time()
@@ -60,10 +59,10 @@ using std::wstring;
 
 TextEncoder::Encoding Filename::_filesystem_encoding = TextEncoder::E_utf8;
 
-TVOLATILE AtomicAdjust::Pointer Filename::_home_directory;
-TVOLATILE AtomicAdjust::Pointer Filename::_temp_directory;
-TVOLATILE AtomicAdjust::Pointer Filename::_user_appdata_directory;
-TVOLATILE AtomicAdjust::Pointer Filename::_common_appdata_directory;
+patomic<Filename *> Filename::_home_directory(nullptr);
+patomic<Filename *> Filename::_temp_directory(nullptr);
+patomic<Filename *> Filename::_user_appdata_directory(nullptr);
+patomic<Filename *> Filename::_common_appdata_directory(nullptr);
 TypeHandle Filename::_type_handle;
 
 #ifdef ANDROID
@@ -486,7 +485,8 @@ temporary(const string &dirname, const string &prefix, const string &suffix,
  */
 const Filename &Filename::
 get_home_directory() {
-  if (AtomicAdjust::get_ptr(_home_directory) == nullptr) {
+  Filename *curdir = _home_directory.load(std::memory_order_consume);
+  if (curdir == nullptr) {
     Filename home_directory;
 
     // In all environments except Windows, check $HOME first.
@@ -538,14 +538,16 @@ get_home_directory() {
     }
 
     Filename *newdir = new Filename(home_directory);
-    if (AtomicAdjust::compare_and_exchange_ptr(_home_directory, nullptr, newdir) != nullptr) {
+    if (_home_directory.compare_exchange_strong(curdir, newdir, std::memory_order_release, std::memory_order_consume)) {
+      return *newdir;
+    } else {
       // Didn't store it.  Must have been stored by someone else.
-      assert(_home_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
     }
   }
 
-  return (*(Filename *)_home_directory);
+  return *curdir;
 }
 
 /**
@@ -553,7 +555,8 @@ get_home_directory() {
  */
 const Filename &Filename::
 get_temp_directory() {
-  if (AtomicAdjust::get_ptr(_temp_directory) == nullptr) {
+  Filename *curdir = _temp_directory.load(std::memory_order_consume);
+  if (curdir == nullptr) {
     Filename temp_directory;
 
 #ifdef _WIN32
@@ -586,14 +589,16 @@ get_temp_directory() {
     }
 
     Filename *newdir = new Filename(temp_directory);
-    if (AtomicAdjust::compare_and_exchange_ptr(_temp_directory, nullptr, newdir) != nullptr) {
+    if (_temp_directory.compare_exchange_strong(curdir, newdir, std::memory_order_release, std::memory_order_consume)) {
+      return *newdir;
+    } else {
       // Didn't store it.  Must have been stored by someone else.
-      assert(_temp_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
     }
   }
 
-  return (*(Filename *)_temp_directory);
+  return *curdir;
 }
 
 /**
@@ -603,7 +608,8 @@ get_temp_directory() {
  */
 const Filename &Filename::
 get_user_appdata_directory() {
-  if (AtomicAdjust::get_ptr(_user_appdata_directory) == nullptr) {
+  Filename *curdir = _user_appdata_directory.load(std::memory_order_consume);
+  if (curdir == nullptr) {
     Filename user_appdata_directory;
 
 #ifdef _WIN32
@@ -643,14 +649,16 @@ get_user_appdata_directory() {
     }
 
     Filename *newdir = new Filename(user_appdata_directory);
-    if (AtomicAdjust::compare_and_exchange_ptr(_user_appdata_directory, nullptr, newdir) != nullptr) {
+    if (_user_appdata_directory.compare_exchange_strong(curdir, newdir, std::memory_order_release, std::memory_order_consume)) {
+      return *newdir;
+    } else {
       // Didn't store it.  Must have been stored by someone else.
-      assert(_user_appdata_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
     }
   }
 
-  return (*(Filename *)_user_appdata_directory);
+  return *curdir;
 }
 
 /**
@@ -659,7 +667,8 @@ get_user_appdata_directory() {
  */
 const Filename &Filename::
 get_common_appdata_directory() {
-  if (AtomicAdjust::get_ptr(_common_appdata_directory) == nullptr) {
+  Filename *curdir = _common_appdata_directory.load(std::memory_order_consume);
+  if (curdir == nullptr) {
     Filename common_appdata_directory;
 
 #ifdef _WIN32
@@ -693,14 +702,16 @@ get_common_appdata_directory() {
     }
 
     Filename *newdir = new Filename(common_appdata_directory);
-    if (AtomicAdjust::compare_and_exchange_ptr(_common_appdata_directory, nullptr, newdir) != nullptr) {
+    if (_common_appdata_directory.compare_exchange_strong(curdir, newdir, std::memory_order_release, std::memory_order_consume)) {
+      return *newdir;
+    } else {
       // Didn't store it.  Must have been stored by someone else.
-      assert(_common_appdata_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
     }
   }
 
-  return (*(Filename *)_common_appdata_directory);
+  return *curdir;
 }
 
 /**

+ 12 - 9
dtool/src/dtoolutil/filename.h

@@ -20,6 +20,7 @@
 #include "register_type.h"
 #include "vector_string.h"
 #include "textEncoder.h"
+#include "patomic.h"
 
 #include <assert.h>
 
@@ -63,13 +64,13 @@ public:
 
 PUBLISHED:
   INLINE Filename();
-  Filename(const Filename &dirname, const Filename &basename);
+  explicit Filename(const Filename &dirname, const Filename &basename);
 
 #ifdef HAVE_PYTHON
   EXTENSION(Filename(PyObject *path));
 
   EXTENSION(PyObject *__reduce__(PyObject *self) const);
-#endif
+#endif // HAVE_PYTHON
 
   // Static constructors to explicitly create a filename that refers to a text
   // or binary file.  This is in lieu of calling set_text() or set_binary() or
@@ -113,8 +114,10 @@ PUBLISHED:
   INLINE size_t length() const;
   INLINE char operator [] (size_t n) const;
 
+#ifdef HAVE_PYTHON
   EXTENSION(PyObject *__repr__() const);
   EXTENSION(PyObject *__fspath__() const);
+#endif // HAVE_PYTHON
 
   INLINE std::string substr(size_t begin) const;
   INLINE std::string substr(size_t begin, size_t end) const;
@@ -201,7 +204,7 @@ PUBLISHED:
   bool scan_directory(vector_string &contents) const;
 #ifdef HAVE_PYTHON
   EXTENSION(PyObject *scan_directory() const);
-#endif
+#endif // HAVE_PYTHON
 
   bool open_read(std::ifstream &stream) const;
   bool open_write(std::ofstream &stream, bool truncate = true) const;
@@ -265,15 +268,15 @@ protected:
   int _flags;
 
   static TextEncoder::Encoding _filesystem_encoding;
-  static TVOLATILE AtomicAdjust::Pointer _home_directory;
-  static TVOLATILE AtomicAdjust::Pointer _temp_directory;
-  static TVOLATILE AtomicAdjust::Pointer _user_appdata_directory;
-  static TVOLATILE AtomicAdjust::Pointer _common_appdata_directory;
+  static patomic<Filename *> _home_directory;
+  static patomic<Filename *> _temp_directory;
+  static patomic<Filename *> _user_appdata_directory;
+  static patomic<Filename *> _common_appdata_directory;
 
 #ifdef ANDROID
 public:
   static std::string _internal_data_dir;
-#endif
+#endif // ANDROID
 
 public:
   static TypeHandle get_class_type() {
@@ -294,4 +297,4 @@ INLINE std::ostream &operator << (std::ostream &out, const Filename &n) {
 
 #include "filename.I"
 
-#endif
+#endif // !FILENAME_H

+ 10 - 10
dtool/src/dtoolutil/textEncoder.h

@@ -54,28 +54,28 @@ PUBLISHED:
   INLINE static Encoding get_default_encoding();
   MAKE_PROPERTY(default_encoding, get_default_encoding, set_default_encoding);
 
-#ifdef CPPPARSER
+#if defined(CPPPARSER) && defined(HAVE_PYTHON)
   EXTEND void set_text(PyObject *text);
   EXTEND void set_text(PyObject *text, Encoding encoding);
-#else
+#else // CPPPARSER && HAVE_PYTHON
   INLINE void set_text(const std::string &text);
   INLINE void set_text(const std::string &text, Encoding encoding);
-#endif
+#endif // CPPPARSER && HAVE_PYTHON
   INLINE void clear_text();
   INLINE bool has_text() const;
 
   void make_upper();
   void make_lower();
 
-#ifdef CPPPARSER
+#if defined(CPPPARSER) && defined(HAVE_PYTHON)
   EXTEND PyObject *get_text() const;
   EXTEND PyObject *get_text(Encoding encoding) const;
   EXTEND void append_text(PyObject *text);
-#else
+#else // CPPPARSER && HAVE_PYTHON
   INLINE std::string get_text() const;
   INLINE std::string get_text(Encoding encoding) const;
   INLINE void append_text(const std::string &text);
-#endif
+#endif // CPPPARSER && HAVE_PYTHON
   INLINE void append_unicode_char(char32_t character);
   INLINE size_t get_num_chars() const;
   INLINE int get_unicode_char(size_t index) const;
@@ -108,19 +108,19 @@ PUBLISHED:
   std::wstring get_wtext_as_ascii() const;
   bool is_wtext() const;
 
-#ifdef CPPPARSER
+#if defined(CPPPARSER) && defined(HAVE_PYTHON)
   EXTEND static PyObject *encode_wchar(char32_t ch, Encoding encoding);
   EXTEND INLINE PyObject *encode_wtext(const std::wstring &wtext) const;
   EXTEND static PyObject *encode_wtext(const std::wstring &wtext, Encoding encoding);
   EXTEND INLINE PyObject *decode_text(PyObject *text) const;
   EXTEND static PyObject *decode_text(PyObject *text, Encoding encoding);
-#else
+#else // CPPPARSER && HAVE_PYTHON
   static std::string encode_wchar(char32_t ch, Encoding encoding);
   INLINE std::string encode_wtext(const std::wstring &wtext) const;
   static std::string encode_wtext(const std::wstring &wtext, Encoding encoding);
   INLINE std::wstring decode_text(const std::string &text) const;
   static std::wstring decode_text(const std::string &text, Encoding encoding);
-#endif
+#endif // CPPPARSER && HAVE_PYTHON
 
   MAKE_PROPERTY(text, get_text, set_text);
 
@@ -156,4 +156,4 @@ INLINE std::ostream & operator << (std::ostream &out, const std::wstring &str);
 
 #include "textEncoder.I"
 
-#endif
+#endif // !TEXTENCODER_H

+ 23 - 2
dtool/src/interrogate/functionRemap.cxx

@@ -312,6 +312,22 @@ make_wrapper_entry(FunctionIndex function_index) {
     iwrapper._flags |= InterrogateFunctionWrapper::F_callable_by_name;
   }
 
+  if (_flags & F_copy_constructor) {
+    iwrapper._flags |= InterrogateFunctionWrapper::F_copy_constructor;
+  }
+
+  if (_flags & F_coerce_constructor) {
+    iwrapper._flags |= InterrogateFunctionWrapper::F_coerce_constructor;
+  }
+
+  if (_extension) {
+    iwrapper._flags |= InterrogateFunctionWrapper::F_extension;
+  }
+
+  if (_cppfunc->_attributes.has_attribute("deprecated")) {
+    iwrapper._flags |= InterrogateFunctionWrapper::F_deprecated;
+  }
+
   Parameters::const_iterator pi;
   for (pi = _parameters.begin();
        pi != _parameters.end();
@@ -856,8 +872,13 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     } else if (fname == "make") {
       if (!_has_this && _parameters.size() >= 1 &&
           TypeManager::is_pointer(_return_type->get_new_type())) {
-        // We can use this for coercion.
-        _flags |= F_coerce_constructor;
+        // We can use this for coercion, except if this is a kwargs param that
+        // does not have a default value.
+        if ((_flags & F_explicit_args) == 0 ||
+            _parameters.size() != first_param + 2 ||
+            _parameters[first_param + 1]._remap->has_default_value()) {
+          _flags |= F_coerce_constructor;
+        }
       }
 
       if (_args_type == InterfaceMaker::AT_varargs) {

+ 26 - 11
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -74,7 +74,7 @@ RenameSet methodRenameDictionary[] = {
   { "operator ="    , "assign",                 0 },
   { "operator ()"   , "__call__",               0 },
   { "operator []"   , "__getitem__",            0 },
-  { "operator [] =" , "__setitem__",            0 },
+  { "operator []="  , "__setitem__",            0 },
   { "operator ++unary", "increment",            0 },
   { "operator ++"   , "increment",              0 },
   { "operator --unary", "decrement",            0 },
@@ -1221,22 +1221,33 @@ write_class_details(ostream &out, Object *obj) {
     out << "  return nullptr;\n";
     out << "}\n\n";
 
-    out << "static void *Dtool_DowncastInterface_" << ClassName << "(void *from_this, Dtool_PyTypedObject *from_type) {\n";
+    out << "static Dtool_PyInstDef *Dtool_Wrap_" << ClassName << "(void *from_this, Dtool_PyTypedObject *from_type) {\n";
     out << "  if (from_this == nullptr || from_type == nullptr) {\n";
     out << "    return nullptr;\n";
     out << "  }\n";
-    out << "  if (from_type == Dtool_Ptr_" << ClassName << ") {\n";
-    out << "    return from_this;\n";
+    out << "  " << cClassName << " *to_this;\n";
+    out << "  if (from_type == &Dtool_" << ClassName << ") {\n";
+    out << "    to_this = (" << cClassName << "*)from_this;\n";
     out << "  }\n";
     for (di = details.begin(); di != details.end(); di++) {
       if (di->second._can_downcast && di->second._is_legal_py_class) {
-        out << "  if (from_type == Dtool_Ptr_" << make_safe_name(di->second._to_class_name) << ") {\n";
+        out << "  else if (from_type == Dtool_Ptr_" << make_safe_name(di->second._to_class_name) << ") {\n";
         out << "    " << di->second._to_class_name << "* other_this = (" << di->second._to_class_name << "*)from_this;\n" ;
-        out << "    return (" << cClassName << "*)other_this;\n";
+        out << "    to_this = (" << cClassName << "*)other_this;\n";
         out << "  }\n";
       }
     }
-    out << "  return nullptr;\n";
+    out << "  else {\n";
+    out << "    return nullptr;\n";
+    out << "  }\n";
+    out << "  // Allocate a new Python instance\n";
+    out << "  Dtool_PyInstDef *self = (Dtool_PyInstDef *)PyType_GenericAlloc(&Dtool_" << ClassName << "._PyType, 0);\n";
+    out << "  self->_signature = PY_PANDA_SIGNATURE;\n";
+    out << "  self->_My_Type = &Dtool_" << ClassName << ";\n";
+    out << "  self->_ptr_to_object = to_this;\n";
+    out << "  self->_memory_rules = false;\n";
+    out << "  self->_is_const = false;\n";
+    out << "  return self;\n";
     out << "}\n\n";
   }
 }
@@ -3251,7 +3262,7 @@ write_module_class(ostream &out, Object *obj) {
   out << "  TypeHandle::none(),\n";
   out << "  Dtool_PyModuleClassInit_" << ClassName << ",\n";
   out << "  Dtool_UpcastInterface_" << ClassName << ",\n";
-  out << "  Dtool_DowncastInterface_" << ClassName << ",\n";
+  out << "  Dtool_Wrap_" << ClassName << ",\n";
 
   int has_coerce = has_coerce_constructor(obj->_itype._cpptype->as_struct_type());
   if (has_coerce > 0) {
@@ -4819,9 +4830,13 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     // The function handles the arguments by itself.
     expected_params += "*args";
     pexprs.push_back("args");
-    if (args_type == AT_keyword_args) {
-      expected_params += ", **kwargs";
-      pexprs.push_back("kwds");
+    if (remap->_args_type == AT_keyword_args) {
+      if (args_type == AT_keyword_args) {
+        expected_params += ", **kwargs";
+        pexprs.push_back("kwds");
+      } else {
+        pexprs.push_back("nullptr");
+      }
     }
     num_params = 0;
   }

+ 10 - 11
dtool/src/interrogate/interrogate.cxx

@@ -417,8 +417,8 @@ main(int argc, char **argv) {
       break;
 
     case CO_python_native:
-        build_python_native = true;
-        break;
+      build_python_native = true;
+      break;
 
     case CO_track_interpreter:
       track_interpreter = true;
@@ -513,7 +513,7 @@ main(int argc, char **argv) {
   for (i = 1; i < argc; ++i) {
     Filename filename = Filename::from_os_specific(argv[i]);
     if (!parser.parse_file(filename)) {
-      cerr << "Error parsing file: '" << argv[i] << "'\n";
+      cerr << "interrogate failed to parse file: '" << argv[i] << "'\n";
       exit(1);
     }
     builder.add_source_file(filename.to_os_generic());
@@ -604,23 +604,22 @@ main(int argc, char **argv) {
       << " *\n"
       << " */\n\n";
 
-    if(the_output_include != nullptr)
-    {
-        output_code << "#include \""<<output_include_filename<<"\"\n";
-        *the_output_include << "#include \"" << output_include_filename.get_fullpath_wo_extension() << "_pynative.h\"\n";
+    if (the_output_include != nullptr) {
+      output_code << "#include \"" << output_include_filename << "\"\n";
+      *the_output_include << "#include \"" << output_include_filename.get_fullpath_wo_extension() << "_pynative.h\"\n";
     }
 
     if (output_code.fail()) {
       nout << "Unable to write to " << output_code_filename << "\n";
       status = -1;
     } else {
-      builder.write_code(output_code,the_output_include, def);
+      builder.write_code(output_code, the_output_include, def);
     }
   }
 
-
-  if(the_output_include != nullptr)
-      *the_output_include << "#endif  // #define   " << output_include_filename.get_basename_wo_extension() << "__HH__\n";
+  if (the_output_include != nullptr) {
+    *the_output_include << "#endif  // #define   " << output_include_filename.get_basename_wo_extension() << "__HH__\n";
+  }
 
   // And now output the bulk of the database.
   if (!output_data_filename.empty()) {

+ 5 - 1
dtool/src/interrogate/interrogateBuilder.cxx

@@ -2381,6 +2381,10 @@ get_type(CPPType *type, bool global) {
     }
   }
 
+  if (type->_attributes.has_attribute("deprecated")) {
+    itype._flags |= InterrogateType::F_deprecated;
+  }
+
   if (forced || !in_ignoretype(true_name)) {
     itype._flags |= InterrogateType::F_fully_defined;
 
@@ -3050,7 +3054,7 @@ define_method(CPPInstance *function, InterrogateType &itype,
         CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0);
 
         // Now make up an instance for the function.
-        CPPInstance *function = new CPPInstance(ftype, "operator [] =");
+        CPPInstance *function = new CPPInstance(ftype, "operator []=");
         function->_ident->_native_scope = scope;
 
         FunctionIndex index = get_function(function, "",

+ 3 - 3
dtool/src/interrogatedb/dtool_super_base.cxx

@@ -39,11 +39,11 @@ static void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module) {
   }
 }
 
-static void *Dtool_DowncastInterface_DTOOL_SUPER_BASE(void *from_this, Dtool_PyTypedObject *from_type) {
+static void *Dtool_UpcastInterface_DTOOL_SUPER_BASE(PyObject *self, Dtool_PyTypedObject *requested_type) {
   return nullptr;
 }
 
-static void *Dtool_UpcastInterface_DTOOL_SUPER_BASE(PyObject *self, Dtool_PyTypedObject *requested_type) {
+static Dtool_PyInstDef *Dtool_Wrap_DTOOL_SUPER_BASE(void *from_this, Dtool_PyTypedObject *from_type) {
   return nullptr;
 }
 
@@ -140,7 +140,7 @@ Dtool_PyTypedObject *Dtool_GetSuperBase() {
     TypeHandle::none(),
     Dtool_PyModuleClassInit_DTOOL_SUPER_BASE,
     Dtool_UpcastInterface_DTOOL_SUPER_BASE,
-    Dtool_DowncastInterface_DTOOL_SUPER_BASE,
+    Dtool_Wrap_DTOOL_SUPER_BASE,
     nullptr,
     nullptr,
   };

+ 32 - 0
dtool/src/interrogatedb/interrogateFunctionWrapper.I

@@ -63,6 +63,38 @@ is_callable_by_name() const {
   return (_flags & F_callable_by_name) != 0;
 }
 
+/**
+ * @since 1.10.13
+ */
+INLINE bool InterrogateFunctionWrapper::
+is_copy_constructor() const {
+  return (_flags & F_copy_constructor) != 0;
+}
+
+/**
+ * @since 1.10.13
+ */
+INLINE bool InterrogateFunctionWrapper::
+is_coerce_constructor() const {
+  return (_flags & F_coerce_constructor) != 0;
+}
+
+/**
+ * @since 1.10.13
+ */
+INLINE bool InterrogateFunctionWrapper::
+is_extension() const {
+  return (_flags & F_extension) != 0;
+}
+
+/**
+ * @since 1.11.0
+ */
+INLINE bool InterrogateFunctionWrapper::
+is_deprecated() const {
+  return (_flags & F_deprecated) != 0;
+}
+
 /**
  *
  */

+ 9 - 1
dtool/src/interrogatedb/interrogateFunctionWrapper.h

@@ -34,6 +34,10 @@ public:
   INLINE FunctionIndex get_function() const;
 
   INLINE bool is_callable_by_name() const;
+  INLINE bool is_copy_constructor() const;
+  INLINE bool is_coerce_constructor() const;
+  INLINE bool is_extension() const;
+  INLINE bool is_deprecated() const;
 
   INLINE bool has_return_value() const;
   INLINE TypeIndex get_return_type() const;
@@ -61,7 +65,11 @@ private:
   enum Flags {
     F_caller_manages   = 0x0001,
     F_has_return       = 0x0002,
-    F_callable_by_name = 0x0004
+    F_callable_by_name = 0x0004,
+    F_copy_constructor = 0x0008,
+    F_coerce_constructor = 0x0010,
+    F_extension        = 0x0020,
+    F_deprecated       = 0x0040,
   };
 
   enum ParameterFlags {

+ 10 - 0
dtool/src/interrogatedb/interrogateType.I

@@ -20,6 +20,16 @@ is_global() const {
   return (_flags & F_global) != 0;
 }
 
+/**
+ * Returns true if the type is marked as 'deprecated'.
+ *
+ * @since 1.11.0
+ */
+INLINE bool InterrogateType::
+is_deprecated() const {
+  return (_flags & F_deprecated) != 0;
+}
+
 /**
  *
  */

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác