Explorar o código

Merge branch 'shaderpipeline' into vulkan

rdb %!s(int64=3) %!d(string=hai) anos
pai
achega
609f3bc696
Modificáronse 100 ficheiros con 3468 adicións e 2287 borrados
  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)
     - name: Install dependencies (macOS)
       if: runner.os == 'macOS'
       if: runner.os == 'macOS'
       run: |
       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.
         # 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
         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
       uses: actions/cache@v1
       with:
       with:
         path: thirdparty
         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)
     - name: Install dependencies (Windows)
       if: runner.os == 'Windows'
       if: runner.os == 'Windows'
       shell: powershell
       shell: powershell
       run: |
       run: |
         if (!(Test-Path thirdparty/win-libs-vc14-x64)) {
         if (!(Test-Path thirdparty/win-libs-vc14-x64)) {
           $wc = New-Object System.Net.WebClient
           $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
           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)
     - name: ccache (non-Windows)
@@ -173,7 +173,7 @@ jobs:
         -D CMAKE_UNITY_BUILD=${{ matrix.unity }}
         -D CMAKE_UNITY_BUILD=${{ matrix.unity }}
         -D CMAKE_BUILD_TYPE="${{ matrix.config }}"
         -D CMAKE_BUILD_TYPE="${{ matrix.config }}"
         -D BUILD_METALIBS=${{ matrix.metalibs }}
         -D BUILD_METALIBS=${{ matrix.metalibs }}
-        -D HAVE_PYTHON=${{ matrix.python }}
+        -D HAVE_PYTHON=${{ runner.os != 'Windows' && matrix.python || 'NO' }}
         -D HAVE_EIGEN=${{ matrix.eigen }}
         -D HAVE_EIGEN=${{ matrix.eigen }}
         ..
         ..
 
 
@@ -184,25 +184,25 @@ jobs:
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
       # END A
 
 
-    - name: Setup Python (Python 3.6)
+    - name: Setup Python (Python 3.7)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
       with:
-        python-version: 3.6
-    - name: Configure (Python 3.6)
+        python-version: '3.7'
+    - name: Configure (Python 3.7)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
       shell: bash
       shell: bash
       run: >
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.6
+        cmake -DWANT_PYTHON_VERSION=3.7 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.6)
+    - name: Build (Python 3.7)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       # BEGIN A
       # BEGIN A
       working-directory: build
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
       # END A
-    - name: Test (Python 3.6)
+    - name: Test (Python 3.7)
       # BEGIN B
       # BEGIN B
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
@@ -216,25 +216,25 @@ jobs:
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
       # END B
       # END B
 
 
-    - name: Setup Python (Python 3.7)
+    - name: Setup Python (Python 3.8)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
       with:
-        python-version: 3.7
-    - name: Configure (Python 3.7)
+        python-version: '3.8'
+    - name: Configure (Python 3.8)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
       shell: bash
       shell: bash
       run: >
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.7
+        cmake -DWANT_PYTHON_VERSION=3.8 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.7)
+    - name: Build (Python 3.8)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       # BEGIN A
       # BEGIN A
       working-directory: build
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
       # END A
-    - name: Test (Python 3.7)
+    - name: Test (Python 3.8)
       # BEGIN B
       # BEGIN B
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
@@ -248,25 +248,25 @@ jobs:
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
       # END B
       # END B
 
 
-    - name: Setup Python (Python 3.8)
+    - name: Setup Python (Python 3.9)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
       with:
-        python-version: 3.8
-    - name: Configure (Python 3.8)
+        python-version: '3.9'
+    - name: Configure (Python 3.9)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
       shell: bash
       shell: bash
       run: >
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.8
+        cmake -DWANT_PYTHON_VERSION=3.9 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.8)
+    - name: Build (Python 3.9)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       # BEGIN A
       # BEGIN A
       working-directory: build
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
       # END A
-    - name: Test (Python 3.8)
+    - name: Test (Python 3.9)
       # BEGIN B
       # BEGIN B
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
@@ -280,25 +280,57 @@ jobs:
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
         $PYTHON_EXECUTABLE -m pytest ../tests --cov=.
       # END B
       # END B
 
 
-    - name: Setup Python (Python 3.9)
+    - name: Setup Python (Python 3.10)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
       with:
-        python-version: 3.9
-    - name: Configure (Python 3.9)
+        python-version: '3.10'
+    - name: Configure (Python 3.10)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
       shell: bash
       shell: bash
       run: >
       run: >
-        cmake -DWANT_PYTHON_VERSION=3.9
+        cmake -DWANT_PYTHON_VERSION=3.10 -DHAVE_PYTHON=YES
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
         -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" .
-    - name: Build (Python 3.9)
+    - name: Build (Python 3.10)
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       # BEGIN A
       # BEGIN A
       working-directory: build
       working-directory: build
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       run: cmake --build . --config ${{ matrix.config }} --parallel 4
       # END A
       # 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
       # BEGIN B
       if: contains(matrix.python, 'YES')
       if: contains(matrix.python, 'YES')
       working-directory: build
       working-directory: build
@@ -347,21 +379,50 @@ jobs:
       shell: powershell
       shell: powershell
       run: |
       run: |
         $wc = New-Object System.Net.WebClient
         $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
         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)
     - name: Get thirdparty packages (macOS)
       if: runner.os == 'macOS'
       if: runner.os == 'macOS'
       run: |
       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)
         (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
     - name: Set up Python 3.9
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
       with:
-        python-version: 3.9
+        python-version: '3.9'
     - name: Build Python 3.9
     - name: Build Python 3.9
       shell: bash
       shell: bash
       run: |
       run: |
@@ -371,10 +432,11 @@ jobs:
       run: |
       run: |
         python -m pip install pytest
         python -m pip install pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
     - name: Set up Python 3.8
     - name: Set up Python 3.8
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
       with:
-        python-version: 3.8
+        python-version: '3.8'
     - name: Build Python 3.8
     - name: Build Python 3.8
       shell: bash
       shell: bash
       run: |
       run: |
@@ -384,10 +446,11 @@ jobs:
       run: |
       run: |
         python -m pip install pytest
         python -m pip install pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
     - name: Set up Python 3.7
     - name: Set up Python 3.7
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
       with:
-        python-version: 3.7
+        python-version: '3.7'
     - name: Build Python 3.7
     - name: Build Python 3.7
       shell: bash
       shell: bash
       run: |
       run: |
@@ -397,6 +460,7 @@ jobs:
       run: |
       run: |
         python -m pip install pytest
         python -m pip install pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
         PYTHONPATH=built LD_LIBRARY_PATH=built/lib DYLD_LIBRARY_PATH=built/lib python -m pytest
+
     - name: Make installer
     - name: Make installer
       run: |
       run: |
         python makepanda/makepackage.py --verbose --lzma
         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)!
 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
 ## 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)
 [<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)
 * [Daniel Stokes](https://opencollective.com/daniel-stokes)
 * [David Rose](https://opencollective.com/david-rose)
 * [David Rose](https://opencollective.com/david-rose)
-* [ChangeCrab](https://changecrab.com)
 
 
 ## Benefactors
 ## Benefactors
 
 
@@ -24,17 +16,17 @@ This is a list of all the people who are contributing financially to Panda3D.  I
 * Sam Edwards
 * Sam Edwards
 * Max Voss
 * Max Voss
 * Hawkheart
 * Hawkheart
-* Dan Mlodecki
+* Veronica
 
 
 ## Enthusiasts
 ## Enthusiasts
 
 
 ![Enthusiasts](https://opencollective.com/panda3d/tiers/enthusiast.svg?avatarHeight=48&width=600)
 ![Enthusiasts](https://opencollective.com/panda3d/tiers/enthusiast.svg?avatarHeight=48&width=600)
 
 
 * Eric Thomson
 * Eric Thomson
-* Kyle Roach
 * Brian Lach
 * Brian Lach
-* C0MPU73R
 * Maxwell Dreytser
 * Maxwell Dreytser
+* SureBet
+* Gyedo Jeon
 
 
 ## Backers
 ## Backers
 
 

+ 6 - 6
README.md

@@ -24,7 +24,7 @@ Installing Panda3D
 ==================
 ==================
 
 
 The latest Panda3D SDK can be downloaded from
 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
 If you are familiar with installing Python packages, you can use
 the following command:
 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
 [click here](https://github.com/rdb/panda3d-thirdparty) for instructions on
 building them from source.
 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
 After acquiring these dependencies, you can build Panda3D from the command
 prompt using the following command.  Change the `--msvc-version` option based
 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
 When the build succeeds, it will produce an .exe file that you can use to
 install Panda3D on your system.
 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
 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
 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
 Linux
 -----
 -----
@@ -136,7 +136,7 @@ macOS
 -----
 -----
 
 
 On macOS, you will need to download a set of precompiled thirdparty packages in order to
 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,
 After placing the thirdparty directory inside the panda3d source directory,
 you may build Panda3D using a command like the following:
 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.
  *   list, and are waiting to get processed.
  * @return Amount of commands
  * @return Amount of commands
  */
  */
-size_t GPUCommandList::get_num_commands() {
+size_t GPUCommandList::get_num_commands() const {
   return _commands.size();
   return _commands.size();
 }
 }
 
 

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

@@ -42,7 +42,7 @@ PUBLISHED:
   GPUCommandList();
   GPUCommandList();
 
 
   void add_command(const GPUCommand& cmd);
   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);
   size_t write_commands_to(const PTA_uchar &dest, size_t limit = 32);
 
 
   MAKE_PROPERTY(num_commands, get_num_commands);
   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.
  * @param index Index of the camera.
  * @return [description]
  * @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());
   nassertr(index >= 0 && index < _cam_nodes.size(), NodePath());
   return _cam_nodes[index];
   return _cam_nodes[index];
 }
 }
@@ -193,7 +193,7 @@ inline NodePath PSSMCameraRig::get_camera(size_t index) {
  * @param split_index The index of the split
  * @param split_index The index of the split
  * @return Distance of the split, ranging from 0 .. 1
  * @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();
   float x = (float)split_index / (float)_cam_nodes.size();
   return (exp(_logarithmic_factor*x)-1) / (exp(_logarithmic_factor)-1);
   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
  * @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());
   nassertr(depth >= 0.0 && depth <= 1.0, LPoint3());
   return _curr_near_points[origin] * (1.0 - depth) + _curr_far_points[origin] * depth;
   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
  * @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;
   return _camera_mvps;
 }
 }
 
 
@@ -238,6 +238,6 @@ inline const PTA_LMatrix4 &PSSMCameraRig::get_mvp_array() {
  *
  *
  * @return Array of near and far planes
  * @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;
   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
     // Reset the film size, offset and far-plane
     Camera* cam = DCAST(Camera, _cam_nodes[i].node());
     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
     // Find a good initial position
     _cam_nodes[i].set_pos(cam_start);
     _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_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());
       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 {
     } else {
       // If we don't use a fixed film size, we can just set the film size
       // If we don't use a fixed film size, we can just set the film size
       // on the lens.
       // 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
     // 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());
     _camera_nearfar[i] = LVecBase2(10, best_max_extent.get_z());
 
 
     // Compute the camera MVP
     // Compute the camera MVP
@@ -399,7 +400,8 @@ void PSSMCameraRig::update(NodePath cam_node, const LVecBase3 &light_vector) {
   }
   }
 
 
   // Do the actual PSSM
   // 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();
   _update_collector.stop();
 }
 }

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

@@ -72,11 +72,11 @@ PUBLISHED:
   void update(NodePath cam_node, const LVecBase3 &light_vector);
   void update(NodePath cam_node, const LVecBase3 &light_vector);
   inline void reset_film_size_cache();
   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);
   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:
 public:
   // Used to access the near and far points in the array
   // Used to access the near and far points in the array
@@ -91,9 +91,9 @@ protected:
   void init_cam_nodes();
   void init_cam_nodes();
   void compute_pssm_splits(const LMatrix4& transform, float max_distance,
   void compute_pssm_splits(const LMatrix4& transform, float max_distance,
                const LVecBase3 &light_vector);
                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);
   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);
   LVecBase3 get_snap_offset(const LMatrix4& mat, size_t resolution);
 
 
   std::vector<NodePath> _cam_nodes;
   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
  * @return Bit mask of the render pass
  */
  */
 inline BitMask32 TagStateManager::
 inline BitMask32 TagStateManager::
-get_mask(const std::string &container_name) {
+get_mask(const std::string &container_name) const {
   if (container_name == "gbuffer") {
   if (container_name == "gbuffer") {
     return BitMask32::bit(1);
     return BitMask32::bit(1);
   }
   }
-  ContainerList::iterator entry = _containers.find(container_name);
+  ContainerList::const_iterator entry = _containers.find(container_name);
   nassertr(entry != _containers.end(), BitMask32());
   nassertr(entry != _containers.end(), BitMask32());
   return entry->second.mask;
   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 register_camera(const std::string& state, Camera* source);
   inline void unregister_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:
 private:
   typedef std::vector<Camera*> CameraList;
   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)
                             subpartDef.subset.isIncludeEmpty(), subpartDef.subset)
 
 
     def __doListJoints(self, indentLevel, part, isIncluded, subset):
     def __doListJoints(self, indentLevel, part, isIncluded, subset):
-        name = part.getName()
+        name = part.name
         if subset.matchesInclude(name):
         if subset.matchesInclude(name):
             isIncluded = True
             isIncluded = True
         elif subset.matchesExclude(name):
         elif subset.matchesExclude(name):
@@ -437,9 +437,9 @@ class Actor(DirectObject, NodePath):
                 part.outputValue(lineStream)
                 part.outputValue(lineStream)
                 value = lineStream.getLine()
                 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)
             self.__doListJoints(indentLevel + 2, child, isIncluded, subset)
 
 
 
 
@@ -1206,11 +1206,11 @@ class Actor(DirectObject, NodePath):
 
 
         return jointsA & jointsB
         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
         """ Recursively walks the joint hierarchy to look for matching
         joint names, implementing getJoints(). """
         joint names, implementing getJoints(). """
 
 
-        name = partNode.getName()
+        name = part.name
         if subset:
         if subset:
             # Constrain the traversal just to the named subset.
             # Constrain the traversal just to the named subset.
             if subset.matchesInclude(name):
             if subset.matchesInclude(name):
@@ -1218,10 +1218,10 @@ class Actor(DirectObject, NodePath):
             elif subset.matchesExclude(name):
             elif subset.matchesExclude(name):
                 isIncluded = False
                 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)
             self.__getPartJoints(joints, pattern, child, subset, isIncluded)
 
 
     def getJointTransform(self, partName, jointName, lodName='lodRoot'):
     def getJointTransform(self, partName, jointName, lodName='lodRoot'):

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

@@ -24,8 +24,8 @@ using std::string;
 
 
 #ifdef WITHIN_PANDA
 #ifdef WITHIN_PANDA
 #ifndef CPPPARSER
 #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
 #endif  // CPPPARSER
 
 
 ConfigVariableBool dc_multiple_inheritance
 ConfigVariableBool dc_multiple_inheritance

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

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

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

@@ -23,7 +23,7 @@
  */
  */
 INLINE bool SmoothMover::
 INLINE bool SmoothMover::
 set_pos(const LVecBase3 &pos) {
 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::
 INLINE bool SmoothMover::
 set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) {
 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::
 INLINE bool SmoothMover::
 set_hpr(const LVecBase3 &hpr) {
 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::
 INLINE bool SmoothMover::
 set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) {
 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::
 INLINE bool SmoothMover::
 set_pos_hpr(const LVecBase3 &pos, const LVecBase3 &hpr) {
 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::
 INLINE bool SmoothMover::
 set_pos_hpr(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) {
 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.compat': ['lzma', 'cmath'],
     'pandas._libs.tslibs.conversion': ['pandas._libs.tslibs.base'],
     'pandas._libs.tslibs.conversion': ['pandas._libs.tslibs.base'],
     'plyer': ['plyer.platforms'],
     '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))
             return 'ModuleDef(%s)' % (', '.join(args))
 
 
     def __init__(self, previous = None, debugLevel = 0,
     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
         # Normally, we are freezing for our own platform.  Change this
         # if untrue.
         # if untrue.
         self.platform = platform or PandaSystem.getPlatform()
         self.platform = platform or PandaSystem.getPlatform()
@@ -911,7 +917,13 @@ class Freezer:
                     ('.so', 'rb', 3),
                     ('.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):
     def excludeFrom(self, freezer):
         """ Excludes all modules that have already been processed by
         """ 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
         # Special case for sysconfig, which depends on a platform-specific
         # sysconfigdata module on POSIX systems.
         # 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):
             if sys.version_info >= (3, 6):
+                modname += '_'
+                if sys.version_info < (3, 8):
+                    modname += 'm'
+
                 if 'linux' in self.platform:
                 if 'linux' in self.platform:
                     arch = self.platform.split('_', 1)[1]
                     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:
                 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.
         # Now, any new modules we found get added to the export list.
         for origName in list(self.mf.modules.keys()):
         for origName in list(self.mf.modules.keys()):
             if origName not in origToNewName:
             if origName not in origToNewName:
                 self.modules[origName] = self.ModuleDef(origName, implicit = True)
                 self.modules[origName] = self.ModuleDef(origName, implicit = True)
 
 
-        missing = []
         for origName in self.mf.any_missing_maybe()[0]:
         for origName in self.mf.any_missing_maybe()[0]:
             if origName in startupModules:
             if origName in startupModules:
                 continue
                 continue
@@ -1398,7 +1419,7 @@ class Freezer:
                 else:
                 else:
                     filename += '.pyo'
                     filename += '.pyo'
                 if multifile.findSubfile(filename) < 0:
                 if multifile.findSubfile(filename) < 0:
-                    code = compile('', moduleName, 'exec', optimize=2)
+                    code = compile('', moduleName, 'exec', optimize=self.optimize)
                     self.__addPyc(multifile, filename, code, compressionLevel)
                     self.__addPyc(multifile, filename, code, compressionLevel)
 
 
             moduleDirs[str] = True
             moduleDirs[str] = True
@@ -1478,7 +1499,7 @@ class Freezer:
                 source = open(sourceFilename.toOsSpecific(), 'r').read()
                 source = open(sourceFilename.toOsSpecific(), 'r').read()
                 if source and source[-1] != '\n':
                 if source and source[-1] != '\n':
                     source = source + '\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)
         self.__addPyc(multifile, filename, code, compressionLevel)
 
 
@@ -1557,7 +1578,7 @@ class Freezer:
             # trouble importing it as a builtin module.  Synthesize a frozen
             # trouble importing it as a builtin module.  Synthesize a frozen
             # module that loads it as builtin.
             # module that loads it as builtin.
             if '.' in moduleName and self.linkExtensionModules:
             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)
                 code = marshal.dumps(code)
                 mangledName = self.mangleName(moduleName)
                 mangledName = self.mangleName(moduleName)
                 moduleDefs.append(self.makeModuleDef(mangledName, code))
                 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)
                     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:
                 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 = '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)
                 code = marshal.dumps(code)
                 moduleList.append((moduleName, len(pool), len(code)))
                 moduleList.append((moduleName, len(pool), len(code)))
                 pool += code
                 pool += code
@@ -1931,6 +1952,8 @@ class Freezer:
                 flags |= 1
                 flags |= 1
             if log_filename_strftime:
             if log_filename_strftime:
                 flags |= 2
                 flags |= 2
+            if self.optimize < 2:
+                flags |= 4 # keep_docstrings
 
 
             # Compose the header we will be writing to the stub, to tell it
             # 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.
             # 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.suffixes = kw.pop('suffixes', imp.get_suffixes())
+        self.optimize = kw.pop('optimize', -1)
 
 
         modulefinder.ModuleFinder.__init__(self, *args, **kw)
         modulefinder.ModuleFinder.__init__(self, *args, **kw)
 
 
@@ -2515,7 +2539,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
 
 
         if type is _PKG_NAMESPACE_DIRECTORY:
         if type is _PKG_NAMESPACE_DIRECTORY:
             m = self.add_module(fqname)
             m = self.add_module(fqname)
-            m.__code__ = compile('', '', 'exec', optimize=2)
+            m.__code__ = compile('', '', 'exec', optimize=self.optimize)
             m.__path__ = pathname
             m.__path__ = pathname
             return m
             return m
 
 
@@ -2527,7 +2551,7 @@ class PandaModuleFinder(modulefinder.ModuleFinder):
                 code = fp.read()
                 code = fp.read()
 
 
             code += b'\n' if isinstance(code, bytes) else '\n'
             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:
         elif type == imp.PY_COMPILED:
             if sys.version_info >= (3, 7):
             if sys.version_info >= (3, 7):
                 try:
                 try:

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

@@ -49,24 +49,39 @@ def _parse_dict(input):
     return d
     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'):
     if dstpath.endswith('.gz') or dstpath.endswith('.pz'):
         dstpath = dstpath[:-3]
         dstpath = dstpath[:-3]
     dstpath = dstpath + '.bam'
     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 = (
 macosx_binary_magics = (
     b'\xFE\xED\xFA\xCE', b'\xCE\xFA\xED\xFE',
     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'),
         ('platforms=', 'p', 'a list of platforms to build for'),
     ]
     ]
     default_file_handlers = {
     default_file_handlers = {
-        '.egg': egg2bam,
     }
     }
 
 
     def initialize_options(self):
     def initialize_options(self):
@@ -277,13 +291,16 @@ class build_apps(setuptools.Command):
         self.log_filename = None
         self.log_filename = None
         self.log_filename_strftime = True
         self.log_filename_strftime = True
         self.log_append = False
         self.log_append = False
+        self.prefer_discrete_gpu = False
         self.requirements_path = os.path.join(os.getcwd(), 'requirements.txt')
         self.requirements_path = os.path.join(os.getcwd(), 'requirements.txt')
+        self.strip_docstrings = True
         self.use_optimized_wheels = True
         self.use_optimized_wheels = True
         self.optimized_wheel_index = ''
         self.optimized_wheel_index = ''
         self.pypi_extra_indexes = [
         self.pypi_extra_indexes = [
             'https://archive.panda3d.org/thirdparty',
             'https://archive.panda3d.org/thirdparty',
         ]
         ]
         self.file_handlers = {}
         self.file_handlers = {}
+        self.bam_model_extensions = ['.egg', '.gltf', '.glb']
         self.exclude_dependencies = [
         self.exclude_dependencies = [
             # Windows
             # Windows
             'kernel32.dll', 'user32.dll', 'wsock32.dll', 'ws2_32.dll',
             'kernel32.dll', 'user32.dll', 'wsock32.dll', 'ws2_32.dll',
@@ -444,6 +461,15 @@ class build_apps(setuptools.Command):
         for glob in self.exclude_dependencies:
         for glob in self.exclude_dependencies:
             glob.case_sensitive = False
             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 = self.default_file_handlers.copy()
         tmp.update(self.file_handlers)
         tmp.update(self.file_handlers)
         self.file_handlers = tmp
         self.file_handlers = tmp
@@ -625,11 +651,16 @@ class build_apps(setuptools.Command):
             self.icon_objects.get('*', None),
             self.icon_objects.get('*', None),
         )
         )
 
 
-        if icon is not None:
+        if icon is not None or self.prefer_discrete_gpu:
             pef = pefile.PEFile()
             pef = pefile.PEFile()
             pef.open(runtime, 'r+')
             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.write_changes()
             pef.close()
             pef.close()
 
 
@@ -944,7 +975,8 @@ class build_apps(setuptools.Command):
             freezer = FreezeTool.Freezer(
             freezer = FreezeTool.Freezer(
                 platform=platform,
                 platform=platform,
                 path=path,
                 path=path,
-                hiddenImports=self.hidden_imports
+                hiddenImports=self.hidden_imports,
+                optimize=2 if self.strip_docstrings else 1
             )
             )
             freezer.addModule('__main__', filename=mainscript)
             freezer.addModule('__main__', filename=mainscript)
             if platform.startswith('android'):
             if platform.startswith('android'):
@@ -1617,6 +1649,10 @@ class bdist_apps(setuptools.Command):
         'manylinux_2_24_ppc64': ['gztar'],
         'manylinux_2_24_ppc64': ['gztar'],
         'manylinux_2_24_ppc64le': ['gztar'],
         'manylinux_2_24_ppc64le': ['gztar'],
         'manylinux_2_24_s390x': ['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'],
         'android': ['aab'],
         # Everything else defaults to ['zip']
         # Everything else defaults to ['zip']
     }
     }
@@ -1710,3 +1746,14 @@ class bdist_apps(setuptools.Command):
                     continue
                     continue
 
 
                 self.installer_functions[installer](self, basename, build_dir)
                 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:
         if self.res_rva.addr and self.res_rva.size:
             self.resources.unpack_from(self.vmem, self.res_rva.addr)
             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):
     def get_export_address(self, symbol_name):
         """ Finds the virtual address for a named export symbol. """
         """ Finds the virtual address for a named export symbol. """
 
 

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

@@ -120,7 +120,7 @@ class ConnectionRepository(
 
 
         self._serverAddress = ''
         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
             # set gc to preserve every object involved in a cycle, even ones that
             # would normally be freed automatically during garbage collect
             # would normally be freed automatically during garbage collect
             # allows us to find and fix these cycles, reducing or eliminating the
             # 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";
 const string CConnectionRepository::_overflow_event_name = "CRDatagramOverflow";
 
 
 #ifndef CPPPARSER
 #ifndef CPPPARSER
-PStatCollector CConnectionRepository::_update_pcollector("App:Show code:readerPollTask:Update");
+PStatCollector CConnectionRepository::_update_pcollector("App:Tasks:readerPollTask:Update");
 #endif  // CPPPARSER
 #endif  // CPPPARSER
 
 
 /**
 /**
@@ -580,7 +580,8 @@ flush() {
 
 
   #ifdef HAVE_OPENSSL
   #ifdef HAVE_OPENSSL
   if (_http_conn) {
   if (_http_conn) {
-    return _http_conn->flush();
+    _http_conn->flush();
+    return !_http_conn->is_closed();
   }
   }
   #endif  // HAVE_OPENSSL
   #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
 # clunky approach.  - Josh
 
 
 from panda3d.core import LVecBase4, LPoint2
 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 Texture, Shader, ATSNone
 from panda3d.core import FrameBufferProperties
 from panda3d.core import FrameBufferProperties
 from panda3d.core import getDefaultCoordinateSystem, CS_zup_right, CS_zup_left
 from panda3d.core import getDefaultCoordinateSystem, CS_zup_right, CS_zup_left
@@ -189,11 +189,22 @@ class CommonFilters:
                 fbprops.setSrgbColor(False)
                 fbprops.setSrgbColor(False)
                 clamping = 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)
             self.finalQuad = self.manager.renderSceneInto(textures = self.textures, auxbits=auxbits, fbprops=fbprops, clamping=clamping)
             if self.finalQuad is None:
             if self.finalQuad is None:
                 self.cleanup()
                 self.cleanup()
                 return False
                 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:
             if "BlurSharpen" in configuration:
                 blur0 = self.textures["blur0"]
                 blur0 = self.textures["blur0"]
                 blur1 = self.textures["blur1"]
                 blur1 = self.textures["blur1"]
@@ -454,6 +465,26 @@ class CommonFilters:
         if task is not None:
         if task is not None:
             return task.cont
             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)):
     def setCartoonInk(self, separation=1, color=(0, 0, 0, 1)):
         fullrebuild = ("CartoonInk" not in self.configuration)
         fullrebuild = ("CartoonInk" not in self.configuration)
         newconfig = FilterConfig()
         newconfig = FilterConfig()
@@ -679,6 +710,8 @@ class CommonFilters:
         return True
         return True
 
 
     #snake_case alias:
     #snake_case alias:
+    set_msaa = setMSAA
+    del_msaa = delMSAA
     del_cartoon_ink = delCartoonInk
     del_cartoon_ink = delCartoonInk
     set_half_pixel_shift = setHalfPixelShift
     set_half_pixel_shift = setHalfPixelShift
     del_half_pixel_shift = delHalfPixelShift
     del_half_pixel_shift = delHalfPixelShift

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

@@ -41,7 +41,7 @@ class Interval(DirectObject):
         self.pstats = None
         self.pstats = None
         if __debug__ and TaskManager.taskTimerVerbose:
         if __debug__ and TaskManager.taskTimerVerbose:
             self.pname = name.split('-', 1)[0]
             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
         # Set true if the interval should be invoked if it was
         # completely skipped over during initialize or finalize, false
         # 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
         self.pstats = None
         if __debug__ and TaskManager.taskTimerVerbose:
         if __debug__ and TaskManager.taskTimerVerbose:
             self.pname = name.split('-', 1)[0]
             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 = []
         self.pythonIvals = []
 
 

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

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

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

@@ -47,6 +47,30 @@ class MotionTrailFrame:
 
 
 
 
 class MotionTrail(NodePath, DirectObject):
 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")
     notify = directNotify.newCategory("MotionTrail")
 
 
@@ -58,9 +82,16 @@ class MotionTrail(NodePath, DirectObject):
 
 
     @classmethod
     @classmethod
     def setGlobalEnable(cls, enable):
     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
         cls.global_enable = enable
 
 
     def __init__(self, name, parent_node_path):
     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)
         NodePath.__init__(self, name)
 
 
         # required initialization
         # required initialization
@@ -91,8 +122,17 @@ class MotionTrail(NodePath, DirectObject):
         # default options
         # default options
         self.continuous_motion_trail = True
         self.continuous_motion_trail = True
         self.color_scale = 1.0
         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
         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.sampling_time = 0.0
+
         self.square_t = True
         self.square_t = True
 
 
 #        self.task_transform = False
 #        self.task_transform = False
@@ -100,7 +140,12 @@ class MotionTrail(NodePath, DirectObject):
 
 
         # node path states
         # node path states
         self.reparentTo(parent_node_path)
         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 = GeomNode("motion_trail")
+        self.geom_node.setBoundsType(BoundingVolume.BT_box)
         self.geom_node_path = self.attachNewNode(self.geom_node)
         self.geom_node_path = self.attachNewNode(self.geom_node)
         node_path = self.geom_node_path
         node_path = self.geom_node_path
 
 
@@ -127,10 +172,13 @@ class MotionTrail(NodePath, DirectObject):
 
 
             MotionTrail.task_added = True
             MotionTrail.task_added = True
 
 
-
         self.relative_to_render = False
         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
         self.use_nurbs = False
+
+        #: This can be changed to fine-tune the resolution of the NURBS curve.
         self.resolution_distance = 0.5
         self.resolution_distance = 0.5
 
 
         self.cmotion_trail = CMotionTrail()
         self.cmotion_trail = CMotionTrail()
@@ -142,14 +190,13 @@ class MotionTrail(NodePath, DirectObject):
         else:
         else:
             self.use_python_version = False
             self.use_python_version = False
 
 
-        return
-
     def delete(self):
     def delete(self):
+        """Completely cleans up the motion trail object.
+        """
         self.reset_motion_trail()
         self.reset_motion_trail()
         self.reset_motion_trail_geometry()
         self.reset_motion_trail_geometry()
         self.cmotion_trail.resetVertexList()
         self.cmotion_trail.resetVertexList()
         self.removeNode()
         self.removeNode()
-        return
 
 
     def print_matrix(self, matrix):
     def print_matrix(self, matrix):
         separator = ' '
         separator = ' '
@@ -206,11 +253,32 @@ class MotionTrail(NodePath, DirectObject):
 
 
         return Task.cont
         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)
         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)
         self.total_vertices = len(self.vertex_list)
 
 
@@ -219,15 +287,24 @@ class MotionTrail(NodePath, DirectObject):
         return motion_trail_vertex
         return motion_trail_vertex
 
 
     def set_vertex_color(self, vertex_id, start_color, end_color):
     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:
         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.start_color = start_color
             motion_trail_vertex.end_color = end_color
             motion_trail_vertex.end_color = end_color
 
 
         self.modified_vertices = True
         self.modified_vertices = True
-        return
 
 
     def set_texture(self, texture):
     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
         self.texture = texture
         if texture:
         if texture:
             self.geom_node_path.setTexture(texture)
             self.geom_node_path.setTexture(texture)
@@ -237,17 +314,21 @@ class MotionTrail(NodePath, DirectObject):
             self.geom_node_path.clearTexture()
             self.geom_node_path.clearTexture()
 
 
         self.modified_vertices = True
         self.modified_vertices = True
-        return
 
 
     def update_vertices(self):
     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)
         total_vertices = len(self.vertex_list)
 
 
         self.total_vertices = total_vertices
         self.total_vertices = total_vertices
         if total_vertices >= 2:
         if total_vertices >= 2:
             vertex_index = 0
             vertex_index = 0
             while vertex_index < total_vertices:
             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
                 vertex_index += 1
 
 
             # calculate v coordinate
             # calculate v coordinate
@@ -257,7 +338,7 @@ class MotionTrail(NodePath, DirectObject):
             float_total_vertices = 0.0
             float_total_vertices = 0.0
             float_total_vertices = total_vertices - 1.0
             float_total_vertices = total_vertices - 1.0
             while vertex_index < total_vertices:
             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
                 motion_trail_vertex.v = float_vertex_index / float_total_vertices
                 vertex_index += 1
                 vertex_index += 1
                 float_vertex_index += 1.0
                 float_vertex_index += 1.0
@@ -265,7 +346,6 @@ class MotionTrail(NodePath, DirectObject):
 #                print "motion_trail_vertex.v", motion_trail_vertex.v
 #                print "motion_trail_vertex.v", motion_trail_vertex.v
 
 
         self.modified_vertices = True
         self.modified_vertices = True
-        return
 
 
     def transferVertices(self):
     def transferVertices(self):
 
 
@@ -278,22 +358,24 @@ class MotionTrail(NodePath, DirectObject):
             vertex_index = 0
             vertex_index = 0
             total_vertices = len(self.vertex_list)
             total_vertices = len(self.vertex_list)
             while vertex_index < total_vertices:
             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)
                 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
                 vertex_index += 1
 
 
             self.modified_vertices = False
             self.modified_vertices = False
 
 
-        return
-
     def register_motion_trail(self):
     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]
         MotionTrail.motion_trail_list = MotionTrail.motion_trail_list + [self]
-        return
 
 
     def unregister_motion_trail(self):
     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:
         if self in MotionTrail.motion_trail_list:
             MotionTrail.motion_trail_list.remove(self)
             MotionTrail.motion_trail_list.remove(self)
-        return
 
 
     def begin_geometry(self):
     def begin_geometry(self):
         self.vertex_index = 0
         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):
     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:
         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
         vertex_index = self.vertex_index
 
 
@@ -352,7 +434,10 @@ class MotionTrail(NodePath, DirectObject):
         self.geom_node.addGeom(self.geometry)
         self.geom_node.addGeom(self.geometry)
 
 
     def check_for_update(self, current_time):
     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
         state = False
         if (current_time - self.last_update_time) >= self.sampling_time:
         if (current_time - self.last_update_time) >= self.sampling_time:
             state = True
             state = True
@@ -365,9 +450,12 @@ class MotionTrail(NodePath, DirectObject):
         return state
         return state
 
 
     def update_motion_trail(self, current_time, transform):
     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 len(self.frame_list) >= 1:
-            if transform == self.frame_list [0].transform:
+            if transform == self.frame_list[0].transform:
                 # ignore duplicate transform updates
                 # ignore duplicate transform updates
                 return
                 return
 
 
@@ -378,7 +466,7 @@ class MotionTrail(NodePath, DirectObject):
                 elapsed_time = current_time - self.fade_start_time
                 elapsed_time = current_time - self.fade_start_time
 
 
                 if elapsed_time < 0.0:
                 if elapsed_time < 0.0:
-                    print("elapsed_time < 0: %f" %(elapsed_time))
+                    print("elapsed_time < 0: %f" % (elapsed_time))
                     elapsed_time = 0.0
                     elapsed_time = 0.0
 
 
                 if elapsed_time < self.fade_time:
                 if elapsed_time < self.fade_time:
@@ -397,13 +485,13 @@ class MotionTrail(NodePath, DirectObject):
             last_frame_index = len(self.frame_list) - 1
             last_frame_index = len(self.frame_list) - 1
 
 
             while index <= last_frame_index:
             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:
                 if motion_trail_frame.time >= minimum_time:
                     break
                     break
                 index += 1
                 index += 1
 
 
             if index > 0:
             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
             # add new frame to beginning of list
             motion_trail_frame = MotionTrailFrame(current_time, transform)
             motion_trail_frame = MotionTrailFrame(current_time, transform)
@@ -416,15 +504,14 @@ class MotionTrail(NodePath, DirectObject):
             #
             #
             #index = 0
             #index = 0
             #while index < total_frames:
             #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)
             #    print("frame time", index, motion_trail_frame.time)
             #    index += 1
             #    index += 1
 
 
-            if (total_frames >= 2) and(self.total_vertices >= 2):
-
+            if total_frames >= 2 and self.total_vertices >= 2:
                 self.begin_geometry()
                 self.begin_geometry()
                 total_segments = total_frames - 1
                 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
                 minimum_time = last_motion_trail_frame.time
                 delta_time = current_time - minimum_time
                 delta_time = current_time - minimum_time
 
 
@@ -432,7 +519,7 @@ class MotionTrail(NodePath, DirectObject):
                     inverse_matrix = Mat4(transform)
                     inverse_matrix = Mat4(transform)
                     inverse_matrix.invertInPlace()
                     inverse_matrix.invertInPlace()
 
 
-                if self.use_nurbs and(total_frames >= 5):
+                if self.use_nurbs and total_frames >= 5:
 
 
                     total_distance = 0.0
                     total_distance = 0.0
                     vector = Vec3()
                     vector = Vec3()
@@ -452,10 +539,10 @@ class MotionTrail(NodePath, DirectObject):
                     # add vertices to each NurbsCurveEvaluator
                     # add vertices to each NurbsCurveEvaluator
                     segment_index = 0
                     segment_index = 0
                     while segment_index < total_segments:
                     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:
                         if self.calculate_relative_matrix:
                             start_transform = Mat4()
                             start_transform = Mat4()
@@ -468,34 +555,34 @@ class MotionTrail(NodePath, DirectObject):
                             start_transform = motion_trail_frame_start.transform
                             start_transform = motion_trail_frame_start.transform
                             end_transform = motion_trail_frame_end.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)
                         v0 = start_transform.xform(motion_trail_vertex_start.vertex)
                         v2 = end_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)
                         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)
                             v1 = start_transform.xform(motion_trail_vertex_end.vertex)
                             v3 = end_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)
                             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
                                 v = v1 - v3
                                 vector.set(v[0], v[1], v[2])
                                 vector.set(v[0], v[1], v[2])
                                 distance = vector.length()
                                 distance = vector.length()
                                 total_distance += distance
                                 total_distance += distance
 
 
-                            vertex_segement_index += 1
+                            vertex_segment_index += 1
 
 
                         segment_index += 1
                         segment_index += 1
 
 
@@ -531,7 +618,7 @@ class MotionTrail(NodePath, DirectObject):
                     curve_segment_index = 0.0
                     curve_segment_index = 0.0
                     while curve_segment_index < total_curve_segments:
                     while curve_segment_index < total_curve_segments:
 
 
-                        vertex_segement_index = 0
+                        vertex_segment_index = 0
 
 
                         st = curve_segment_index / total_curve_segments
                         st = curve_segment_index / total_curve_segments
                         et = (curve_segment_index + 1.0) / total_curve_segments
                         et = (curve_segment_index + 1.0) / total_curve_segments
@@ -545,7 +632,7 @@ class MotionTrail(NodePath, DirectObject):
                             start_t *= start_t
                             start_t *= start_t
                             end_t *= end_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)
                         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
                         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)
                         t0 = Vec2(one_minus_x(st), motion_trail_vertex_start.v)
                         t2 = Vec2(one_minus_x(et), 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_start_t = start_nurbs_curve_result.getStartT()
                             start_nurbs_end_t = start_nurbs_curve_result.getEndT()
                             start_nurbs_end_t = start_nurbs_curve_result.getEndT()
@@ -597,17 +684,15 @@ class MotionTrail(NodePath, DirectObject):
                             t0 = t1
                             t0 = t1
                             t2 = t3
                             t2 = t3
 
 
-                            vertex_segement_index += 1
+                            vertex_segment_index += 1
 
 
                         curve_segment_index += 1.0
                         curve_segment_index += 1.0
 
 
-
                 else:
                 else:
-
                     segment_index = 0
                     segment_index = 0
                     while segment_index < total_segments:
                     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
                         start_t = (motion_trail_frame_start.time - minimum_time) / delta_time
                         end_t = (motion_trail_frame_end.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
                             start_t *= start_t
                             end_t *= end_t
                             end_t *= end_t
 
 
-                        vertex_segement_index = 0
+                        vertex_segment_index = 0
                         total_vertex_segments = self.total_vertices - 1
                         total_vertex_segments = self.total_vertices - 1
 
 
                         if self.calculate_relative_matrix:
                         if self.calculate_relative_matrix:
@@ -631,7 +716,7 @@ class MotionTrail(NodePath, DirectObject):
                             start_transform = motion_trail_frame_start.transform
                             start_transform = motion_trail_frame_start.transform
                             end_transform = motion_trail_frame_end.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)
                         v0 = start_transform.xform(motion_trail_vertex_start.vertex)
                         v2 = end_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)
                         t0 = Vec2(st, motion_trail_vertex_start.v)
                         t2 = Vec2(et, 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)
                             v1 = start_transform.xform(motion_trail_vertex_end.vertex)
                             v3 = end_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
                             t0 = t1
                             t2 = t3
                             t2 = t3
 
 
-                            vertex_segement_index += 1
+                            vertex_segment_index += 1
 
 
                         segment_index += 1
                         segment_index += 1
 
 
                 self.end_geometry()
                 self.end_geometry()
 
 
     def enable_motion_trail(self, enable):
     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
         self.enable = enable
 
 
     def reset_motion_trail(self):
     def reset_motion_trail(self):
+        """Call this to have the motion trail restart from nothing on the next
+        update.
+        """
         self.frame_list = []
         self.frame_list = []
         self.cmotion_trail.reset()
         self.cmotion_trail.reset()
 
 
     def reset_motion_trail_geometry(self):
     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:
         if self.geom_node is not None:
             self.geom_node.removeAllGeoms()
             self.geom_node.removeAllGeoms()
 
 
     def attach_motion_trail(self):
     def attach_motion_trail(self):
+        """Alias of `reset_motion_trail()`.
+        """
         self.reset_motion_trail()
         self.reset_motion_trail()
 
 
     def begin_motion_trail(self):
     def begin_motion_trail(self):
@@ -733,7 +831,7 @@ class MotionTrail(NodePath, DirectObject):
             frame_index = 0
             frame_index = 0
             total_frames = len(self.frame_list)
             total_frames = len(self.frame_list)
             while frame_index < total_frames:
             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
                 motion_trail_frame.time += delta_time
                 frame_index += 1
                 frame_index += 1
 
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 285 - 434
direct/src/motiontrail/cMotionTrail.cxx


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

@@ -21,13 +21,11 @@
 #include "geomVertexWriter.h"
 #include "geomVertexWriter.h"
 #include "geomTriangles.h"
 #include "geomTriangles.h"
 #include "luse.h"
 #include "luse.h"
-#include "memoryBase.h"
 #include "nurbsCurveEvaluator.h"
 #include "nurbsCurveEvaluator.h"
 #include "plist.h"
 #include "plist.h"
 #include "epvector.h"
 #include "epvector.h"
 
 
-class CMotionTrailVertex : public MemoryBase {
-public:
+struct CMotionTrailVertex : public MemoryBase {
   LPoint4 _vertex;
   LPoint4 _vertex;
   LVecBase4 _start_color;
   LVecBase4 _start_color;
   LVecBase4 _end_color;
   LVecBase4 _end_color;
@@ -36,9 +34,8 @@ public:
   PT(NurbsCurveEvaluator) _nurbs_curve_evaluator;
   PT(NurbsCurveEvaluator) _nurbs_curve_evaluator;
 };
 };
 
 
-class CMotionTrailFrame {
-public:
-  UnalignedLMatrix4 _transform;
+struct CMotionTrailFrame : public MemoryBase {
+  LMatrix4 _transform;
   PN_stdfloat _time;
   PN_stdfloat _time;
 };
 };
 
 
@@ -72,8 +69,8 @@ public:
  */
  */
 class EXPCL_DIRECT_MOTIONTRAIL CMotionTrail : public TypedReferenceCount {
 class EXPCL_DIRECT_MOTIONTRAIL CMotionTrail : public TypedReferenceCount {
 PUBLISHED:
 PUBLISHED:
-  CMotionTrail();
-  ~CMotionTrail();
+  CMotionTrail() = default;
+  ~CMotionTrail() = default;
 
 
   void reset();
   void reset();
   void reset_vertex_list();
   void reset_vertex_list();
@@ -81,64 +78,66 @@ PUBLISHED:
   void enable(bool enable);
   void enable(bool enable);
 
 
   void set_geom_node(GeomNode *geom_node);
   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);
   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:
 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;
   typedef epvector<CMotionTrailVertex> VertexList;
   VertexList _vertex_list;
   VertexList _vertex_list;
-  typedef plist<CMotionTrailFrame> FrameList;
+  typedef pdeque<CMotionTrailFrame> FrameList;
   FrameList _frame_list;
   FrameList _frame_list;
+  PN_stdfloat _vertex_bounds_radius = 0.0f;
 
 
   // parameters
   // 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
   // nurbs parameters
-  bool _use_nurbs;
-  PN_stdfloat _resolution_distance;
+  bool _use_nurbs = false;
+  PN_stdfloat _resolution_distance = 0.5f;
 
 
   // geom
   // geom
   PT(GeomNode) _geom_node;
   PT(GeomNode) _geom_node;
 
 
   // real-time data
   // real-time data
-  int _vertex_index;
   PT(GeomVertexData) _vertex_data;
   PT(GeomVertexData) _vertex_data;
   GeomVertexWriter _vertex_writer;
   GeomVertexWriter _vertex_writer;
   GeomVertexWriter _color_writer;
   GeomVertexWriter _color_writer;
   GeomVertexWriter _texture_writer;
   GeomVertexWriter _texture_writer;
   PT(GeomTriangles) _triangles;
   PT(GeomTriangles) _triangles;
 
 
-  CMotionTrailVertex *_vertex_array;
-
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;
@@ -155,7 +154,6 @@ public:
 
 
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
-
 };
 };
 
 
 #endif
 #endif

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

@@ -240,10 +240,10 @@ class BufferViewer(DirectObject):
             offsetx = (ringoffset[ring]*2.0) / float(sizex)
             offsetx = (ringoffset[ring]*2.0) / float(sizex)
             offsety = (ringoffset[ring]*2.0) / float(sizey)
             offsety = (ringoffset[ring]*2.0) / float(sizey)
             bright = ringbright[ring]
             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)
             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 random
 import builtins
 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():
 def _createContainerLeak():
@@ -547,6 +550,23 @@ class FindContainers(Job):
                 # if we hit a dead end, start over from another container
                 # if we hit a dead end, start over from another container
                 curObjRef = None
                 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__'):
                 if hasattr(curObj, '__dict__'):
                     child = curObj.__dict__
                     child = curObj.__dict__
                     hasLength = self._hasLength(child)
                     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.PythonUtil import safeRepr
 from direct.showbase.Job import Job
 from direct.showbase.Job import Job
 from direct.showbase.JobManagerGlobal import jobMgr
 from direct.showbase.JobManagerGlobal import jobMgr
+from direct.showbase.ContainerLeakDetector import deadEndTypes
 import types
 import types
+import sys
+import io
 
 
 
 
 class ContainerReport(Job):
 class ContainerReport(Job):
@@ -89,14 +92,6 @@ class ContainerReport(Job):
             if isinstance(parentObj, (str, bytes)):
             if isinstance(parentObj, (str, bytes)):
                 continue
                 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):
             if isinstance(parentObj, dict):
                 key = None
                 key = None
                 attr = None
                 attr = None
@@ -126,7 +121,25 @@ class ContainerReport(Job):
                 del attr
                 del attr
                 continue
                 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:
                 try:
                     itr = iter(parentObj)
                     itr = iter(parentObj)
                 except:
                 except:
@@ -161,7 +174,10 @@ class ContainerReport(Job):
                 childName = None
                 childName = None
                 child = None
                 child = None
                 for childName in childNames:
                 for childName in childNames:
-                    child = getattr(parentObj, childName)
+                    try:
+                        child = getattr(parentObj, childName)
+                    except:
+                        continue
                     if id(child) not in self._visitedIds:
                     if id(child) not in self._visitedIds:
                         self._visitedIds.add(id(child))
                         self._visitedIds.add(id(child))
                         if self._examine(child):
                         if self._examine(child):
@@ -198,9 +214,7 @@ class ContainerReport(Job):
             self._type2id2len[type(obj)][objId] = length
             self._type2id2len[type(obj)][objId] = length
     def _examine(self, obj):
     def _examine(self, obj):
         # return False if it's an object that can't contain or lead to other objects
         # 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
             return False
         # if it's an internal object, ignore it
         # if it's an internal object, ignore it
         if id(obj) in ContainerReport.PrivateIds:
         if id(obj) in ContainerReport.PrivateIds:
@@ -243,7 +257,7 @@ class ContainerReport(Job):
             for i in self._outputType(type, **kArgs):
             for i in self._outputType(type, **kArgs):
                 yield None
                 yield None
         otherTypes = list(set(self._type2id2len.keys()).difference(set(initialTypes)))
         otherTypes = list(set(self._type2id2len.keys()).difference(set(initialTypes)))
-        otherTypes.sort()
+        otherTypes.sort(key=lambda obj: obj.__name__)
         for type in otherTypes:
         for type in otherTypes:
             for i in self._outputType(type, **kArgs):
             for i in self._outputType(type, **kArgs):
                 yield None
                 yield None

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

@@ -137,11 +137,11 @@ class EventManager:
             hyphen = name.find('-')
             hyphen = name.find('-')
             if hyphen >= 0:
             if hyphen >= 0:
                 name = name[0:hyphen]
                 name = name[0:hyphen]
-            pstatCollector = PStatCollector('App:Show code:eventManager:' + name)
+            pstatCollector = PStatCollector('App:Tasks:eventManager:' + name)
             pstatCollector.start()
             pstatCollector.start()
             if self.eventHandler:
             if self.eventHandler:
                 cppPstatCollector = PStatCollector(
                 cppPstatCollector = PStatCollector(
-                    'App:Show code:eventManager:' + name + ':C++')
+                    'App:Tasks:eventManager:' + name + ':C++')
 
 
             messenger.send(eventName, paramList)
             messenger.send(eventName, paramList)
 
 
@@ -180,3 +180,6 @@ class EventManager:
         # since the task removal itself might also fire off an event.
         # since the task removal itself might also fire off an event.
         if self.eventQueue is not None:
         if self.eventQueue is not None:
             self.eventQueue.clear()
             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.Job import Job
 from direct.showbase.JobManagerGlobal import jobMgr
 from direct.showbase.JobManagerGlobal import jobMgr
 from direct.showbase.MessengerGlobal import messenger
 from direct.showbase.MessengerGlobal import messenger
-import direct.showbase.DConfig as config
+from panda3d.core import ConfigVariableBool
 import gc
 import gc
-import types
 
 
 GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num'
 GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num'
 
 
@@ -213,7 +212,7 @@ class GarbageReport(Job):
                     startIndex = 0
                     startIndex = 0
                     # + 1 to include a reference back to the first object
                     # + 1 to include a reference back to the first object
                     endIndex = numObjs + 1
                     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
                         startIndex -= 1
                         endIndex -= 1
                         endIndex -= 1
 
 
@@ -222,7 +221,7 @@ class GarbageReport(Job):
                             numToSkip -= 1
                             numToSkip -= 1
                             continue
                             continue
                         obj = objs[index]
                         obj = objs[index]
-                        if type(obj) is types.InstanceType:
+                        if hasattr(obj, '__dict__'):
                             if not objAlreadyRepresented:
                             if not objAlreadyRepresented:
                                 cycleBySyntax += '%s' % obj.__class__.__name__
                                 cycleBySyntax += '%s' % obj.__class__.__name__
                             cycleBySyntax += '.'
                             cycleBySyntax += '.'
@@ -307,7 +306,7 @@ class GarbageReport(Job):
             while n > 0:
             while n > 0:
                 yield None
                 yield None
                 digits += 1
                 digits += 1
-                n /= 10
+                n = n // 10
             digits = digits
             digits = digits
             format = '%0' + '%s' % digits + 'i:%s \t%s'
             format = '%0' + '%s' % digits + 'i:%s \t%s'
 
 
@@ -562,7 +561,7 @@ class _CFGLGlobals:
 def checkForGarbageLeaks():
 def checkForGarbageLeaks():
     gc.collect()
     gc.collect()
     numGarbage = len(gc.garbage)
     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:
         if numGarbage != _CFGLGlobals.LastNumGarbage:
             print("")
             print("")
             gr = GarbageReport('found garbage', threaded=False, collect=False)
             gr = GarbageReport('found garbage', threaded=False, collect=False)
@@ -572,7 +571,7 @@ def checkForGarbageLeaks():
             messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
             messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
             gr.destroy()
             gr.destroy()
         notify = directNotify.newCategory("GarbageDetect")
         notify = directNotify.newCategory("GarbageDetect")
-        if config.GetBool('allow-garbage-cycles', 1):
+        if ConfigVariableBool('allow-garbage-cycles', True):
             func = notify.warning
             func = notify.warning
         else:
         else:
             func = notify.error
             func = notify.error

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

@@ -35,7 +35,7 @@ class Job(DirectObject):
         self._priority = Job.Priorities.Normal
         self._priority = Job.Priorities.Normal
         self._finished = False
         self._finished = False
         if __debug__:
         if __debug__:
-            self._pstats = PStatCollector("App:Show code:jobManager:%s" % self._name)
+            self._pstats = PStatCollector("App:Tasks:jobManager:%s" % self._name)
 
 
     def destroy(self):
     def destroy(self):
         del self._name
         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
         Creates the render scene graph, the primary scene graph for
         rendering 3-d geometry.
         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 = NodePath('render')
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
 
 
@@ -1170,7 +1170,7 @@ class ShowBase(DirectObject.DirectObject):
         # for the benefit of creating DirectGui elements before ShowBase.
         # for the benefit of creating DirectGui elements before ShowBase.
         from . import ShowBaseGlobal
         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
         self.render2d = ShowBaseGlobal.render2d
 
 
         # Set up some overrides to turn off certain properties which
         # Set up some overrides to turn off certain properties which
@@ -1191,12 +1191,12 @@ class ShowBase(DirectObject.DirectObject):
         self.render2d.setMaterialOff(1)
         self.render2d.setMaterialOff(1)
         self.render2d.setTwoSided(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
         self.aspect2d = ShowBaseGlobal.aspect2d
 
 
         aspectRatio = self.getAspectRatio()
         aspectRatio = self.getAspectRatio()
@@ -1204,13 +1204,13 @@ class ShowBase(DirectObject.DirectObject):
 
 
         self.a2dBackground = self.aspect2d.attachNewNode("a2dBackground")
         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
         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
         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
         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.a2dRight = aspectRatio
 
 
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
         self.a2dTopCenter = self.aspect2d.attachNewNode("a2dTopCenter")
@@ -1250,9 +1250,9 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRight.setPos(self.a2dRight, 0, self.a2dBottom)
         self.a2dBottomRightNs.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 = self.render2d.attachNewNode(PGTop("pixel2d"))
         self.pixel2d.setPos(-1, 0, 1)
         self.pixel2d.setPos(-1, 0, 1)
         xsize, ysize = self.getSize()
         xsize, ysize = self.getSize()
@@ -1282,25 +1282,25 @@ class ShowBase(DirectObject.DirectObject):
         self.render2dp.setMaterialOff(1)
         self.render2dp.setMaterialOff(1)
         self.render2dp.setTwoSided(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 = self.render2dp.attachNewNode(PGTop("aspect2dp"))
         self.aspect2dp.node().setStartSort(16384)
         self.aspect2dp.node().setStartSort(16384)
 
 
         aspectRatio = self.getAspectRatio()
         aspectRatio = self.getAspectRatio()
         self.aspect2dp.setScale(1.0 / aspectRatio, 1.0, 1.0)
         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
         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
         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
         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.a2dpRight = aspectRatio
 
 
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
         self.a2dpTopCenter = self.aspect2dp.attachNewNode("a2dpTopCenter")
@@ -1324,9 +1324,9 @@ class ShowBase(DirectObject.DirectObject):
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
         self.a2dpBottomLeft.setPos(self.a2dpLeft, 0, self.a2dpBottom)
         self.a2dpBottomRight.setPos(self.a2dpRight, 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 = self.render2dp.attachNewNode(PGTop("pixel2dp"))
         self.pixel2dp.node().setStartSort(16384)
         self.pixel2dp.node().setStartSort(16384)
         self.pixel2dp.setPos(-1, 0, 1)
         self.pixel2dp.setPos(-1, 0, 1)
@@ -1647,11 +1647,11 @@ class ShowBase(DirectObject.DirectObject):
 
 
         mw = self.buttonThrowers[0].getParent()
         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 = mw.attachNewNode(ButtonThrower('timeButtons'))
         self.timeButtonThrower.node().setPrefix('time-')
         self.timeButtonThrower.node().setPrefix('time-')
         self.timeButtonThrower.node().setTimeFlag(1)
         self.timeButtonThrower.node().setTimeFlag(1)
@@ -2713,7 +2713,7 @@ class ShowBase(DirectObject.DirectObject):
 
 
     def screenshot(self, namePrefix = 'screenshot',
     def screenshot(self, namePrefix = 'screenshot',
                    defaultFilename = 1, source = None,
                    defaultFilename = 1, source = None,
-                   imageComment=""):
+                   imageComment="", blocking=True):
         """ Captures a screenshot from the main window or from the
         """ Captures a screenshot from the main window or from the
         specified window or Texture and writes it to a filename in the
         specified window or Texture and writes it to a filename in the
         current directory (or to a specified directory).
         current directory (or to a specified directory).
@@ -2735,6 +2735,13 @@ class ShowBase(DirectObject.DirectObject):
         generated by makeCubeMap(), namePrefix should contain the hash
         generated by makeCubeMap(), namePrefix should contain the hash
         mark ('#') character.
         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.
         :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)
                 saved = source.write(filename, 0, 0, 1, 0)
             else:
             else:
                 saved = source.write(filename)
                 saved = source.write(filename)
-        else:
+        elif blocking:
             saved = source.saveScreenshot(filename, imageComment)
             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:
         if saved:
             # Announce to anybody that a screenshot has been taken
             # 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 = Vec3(startValues)
         newVec3.setCell(index, currBounceVal)
         newVec3.setCell(index, currBounceVal)
-        print("### newVec3 = %s" % newVec3)
 
 
         # create the right type of lerp
         # create the right type of lerp
         if ((bounceType == SX_BOUNCE) or (bounceType == SY_BOUNCE) or
         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  -----------------------
 -----------------------  RELEASE 1.10.11  -----------------------
 
 
 Maintenance release containing assorted bug fixes and minor improvements.
 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 *_inP07ytHuAm(PyObject *self, PyObject *args);
 static PyObject *_inP07yt_xr0(PyObject *self, PyObject *args);
 static PyObject *_inP07yt_xr0(PyObject *self, PyObject *args);
 static PyObject *_inP07ytH5qp(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 *_inP07ytq45U(PyObject *self, PyObject *args);
 static PyObject *_inP07yt6IPa(PyObject *self, PyObject *args);
 static PyObject *_inP07yt6IPa(PyObject *self, PyObject *args);
 static PyObject *_inP07ytU2_B(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 *_inP07ytRrg2(PyObject *self, PyObject *args);
 static PyObject *_inP07ytEJCx(PyObject *self, PyObject *args);
 static PyObject *_inP07ytEJCx(PyObject *self, PyObject *args);
 static PyObject *_inP07ytWAZr(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 *_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 *_inP07ytjolz(PyObject *self, PyObject *args);
 static PyObject *_inP07ytt_JD(PyObject *self, PyObject *args);
 static PyObject *_inP07ytt_JD(PyObject *self, PyObject *args);
 static PyObject *_inP07ytwEts(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 *_inP07ytqHrb(PyObject *self, PyObject *args);
 static PyObject *_inP07ytaOqq(PyObject *self, PyObject *args);
 static PyObject *_inP07ytaOqq(PyObject *self, PyObject *args);
 static PyObject *_inP07ytpTBb(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 *_inP07ytqWOw(PyObject *self, PyObject *args);
 static PyObject *_inP07ytHu7x(PyObject *self, PyObject *args);
 static PyObject *_inP07ytHu7x(PyObject *self, PyObject *args);
 static PyObject *_inP07ytwGnA(PyObject *self, PyObject *args);
 static PyObject *_inP07ytwGnA(PyObject *self, PyObject *args);
@@ -583,6 +600,184 @@ _inP07ytH5qp(PyObject *, PyObject *args) {
   return nullptr;
   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
  * Python simple wrapper for
  * bool interrogate_element_is_sequence(ElementIndex element)
  * bool interrogate_element_is_sequence(ElementIndex element)
@@ -1060,6 +1255,24 @@ _inP07ytWAZr(PyObject *, PyObject *args) {
   return nullptr;
   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
  * Python simple wrapper for
  * bool interrogate_wrapper_is_callable_by_name(FunctionWrapperIndex wrapper)
  * bool interrogate_wrapper_is_callable_by_name(FunctionWrapperIndex wrapper)
@@ -1074,6 +1287,62 @@ _inP07ytrD_M(PyObject *, PyObject *args) {
   return nullptr;
   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
  * Python simple wrapper for
  * bool interrogate_wrapper_has_comment(FunctionWrapperIndex wrapper)
  * bool interrogate_wrapper_has_comment(FunctionWrapperIndex wrapper)
@@ -1613,6 +1882,20 @@ _inP07ytpTBb(PyObject *, PyObject *args) {
   return nullptr;
   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
  * Python simple wrapper for
  * char const *interrogate_type_name(TypeIndex type)
  * 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_getter", &_inP07ytHuAm, METH_VARARGS, nullptr },
   { "interrogate_element_has_setter", &_inP07yt_xr0, METH_VARARGS, nullptr },
   { "interrogate_element_has_setter", &_inP07yt_xr0, METH_VARARGS, nullptr },
   { "interrogate_element_setter", &_inP07ytH5qp, 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_sequence", &_inP07ytq45U, METH_VARARGS, nullptr },
   { "interrogate_element_is_mapping", &_inP07yt6IPa, METH_VARARGS, nullptr },
   { "interrogate_element_is_mapping", &_inP07yt6IPa, METH_VARARGS, nullptr },
   { "interrogate_number_of_globals", &_inP07ytU2_B, 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_number_of_python_wrappers", &_inP07ytRrg2, METH_VARARGS, nullptr },
   { "interrogate_function_python_wrapper", &_inP07ytEJCx, METH_VARARGS, nullptr },
   { "interrogate_function_python_wrapper", &_inP07ytEJCx, METH_VARARGS, nullptr },
   { "interrogate_wrapper_name", &_inP07ytWAZr, 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_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_has_comment", &_inP07ytjolz, METH_VARARGS, nullptr },
   { "interrogate_wrapper_comment", &_inP07ytt_JD, METH_VARARGS, nullptr },
   { "interrogate_wrapper_comment", &_inP07ytt_JD, METH_VARARGS, nullptr },
   { "interrogate_wrapper_has_return_value", &_inP07ytwEts, 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_scoped_name", &_inP07ytqHrb, METH_VARARGS, nullptr },
   { "interrogate_get_type_by_true_name", &_inP07ytaOqq, METH_VARARGS, nullptr },
   { "interrogate_get_type_by_true_name", &_inP07ytaOqq, METH_VARARGS, nullptr },
   { "interrogate_type_is_global", &_inP07ytpTBb, 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_name", &_inP07ytqWOw, METH_VARARGS, nullptr },
   { "interrogate_type_scoped_name", &_inP07ytHu7x, METH_VARARGS, nullptr },
   { "interrogate_type_scoped_name", &_inP07ytHu7x, METH_VARARGS, nullptr },
   { "interrogate_type_true_name", &_inP07ytwGnA, 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
 #if PY_MAJOR_VERSION >= 3
 static struct PyModuleDef python_simple_module = {
 static struct PyModuleDef python_simple_module = {
   PyModuleDef_HEAD_INIT,
   PyModuleDef_HEAD_INIT,
-  "interrogatedb",
+  "panda3d.interrogatedb",
   nullptr,
   nullptr,
   -1,
   -1,
   python_simple_funcs,
   python_simple_funcs,

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

@@ -1,4 +1,5 @@
 set(P3CPPPARSER_HEADERS
 set(P3CPPPARSER_HEADERS
+  cppAttributeList.h
   cppArrayType.h cppBison.yxx cppBisonDefs.h
   cppArrayType.h cppBison.yxx cppBisonDefs.h
   cppClassTemplateParameter.h cppCommentBlock.h
   cppClassTemplateParameter.h cppCommentBlock.h
   cppClosureType.h cppConstType.h
   cppClosureType.h cppConstType.h
@@ -17,6 +18,7 @@ set(P3CPPPARSER_HEADERS
 )
 )
 
 
 set(P3CPPPARSER_SOURCES
 set(P3CPPPARSER_SOURCES
+  cppAttributeList.cxx
   cppArrayType.cxx ${CMAKE_CURRENT_BINARY_DIR}/cppBison.cxx
   cppArrayType.cxx ${CMAKE_CURRENT_BINARY_DIR}/cppBison.cxx
   cppClassTemplateParameter.cxx
   cppClassTemplateParameter.cxx
   cppCommentBlock.cxx cppClosureType.cxx cppConstType.cxx cppDeclaration.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 << *_bounds;
   }
   }
   brackets << "]";
   brackets << "]";
+
+  if (!_attributes.is_empty()) {
+    brackets << " " << _attributes;
+  }
+
   std::string bracketsstr = brackets.str();
   std::string bracketsstr = brackets.str();
 
 
   _element_type->output_instance(out, indent_level, scope, complete,
   _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

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 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
 /* 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.
    Inc.
 
 
    This program is free software: you can redistribute it and/or modify
    This program is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
    GNU General Public License for more details.
    GNU General Public License for more details.
 
 
    You should have received a copy of the GNU General Public License
    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
 /* As a special exception, you may create a larger work that contains
    part or all of the Bison parser skeleton and distribute that work
    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;
   typedef enum yytokentype yytoken_kind_t;
 #endif
 #endif
 /* Token kinds.  */
 /* Token kinds.  */
+#define YYEMPTY -2
 #define YYEOF 0
 #define YYEOF 0
 #define YYerror 256
 #define YYerror 256
 #define YYUNDEF 257
 #define YYUNDEF 257
@@ -380,6 +381,8 @@ struct YYLTYPE
 
 
 
 
 
 
+
 int cppyyparse (void);
 int cppyyparse (void);
 
 
+
 #endif /* !YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED  */
 #endif /* !YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED  */

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 256 - 203
dtool/src/cppparser/cppBison.yxx


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

@@ -23,6 +23,7 @@
 
 
 #include <string>
 #include <string>
 
 
+#include "cppAttributeList.h"
 #include "cppClosureType.h"
 #include "cppClosureType.h"
 #include "cppExtensionType.h"
 #include "cppExtensionType.h"
 #include "cppFile.h"
 #include "cppFile.h"
@@ -65,6 +66,7 @@ extern CPPPreprocessor *current_lexer;
 class cppyystype {
 class cppyystype {
 public:
 public:
   std::string str;
   std::string str;
+  CPPAttributeList attr_list;
   union {
   union {
     unsigned long long integer;
     unsigned long long integer;
     long double real;
     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";
     out << " noexcept";
   }
   }
 
 
+  if (!_attributes.is_empty()) {
+    out << " " << _attributes;
+  }
+
   if (_return_type != nullptr) {
   if (_return_type != nullptr) {
     out << " -> ";
     out << " -> ";
     _return_type->output(out, indent_level, scope, false);
     _return_type->output(out, indent_level, scope, false);

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

@@ -18,8 +18,9 @@
  *
  *
  */
  */
 CPPDeclaration::
 CPPDeclaration::
-CPPDeclaration(const CPPFile &file) :
-  _file(file)
+CPPDeclaration(const CPPFile &file, CPPAttributeList attr) :
+  _file(file),
+  _attributes(std::move(attr))
 {
 {
   _vis = V_unknown;
   _vis = V_unknown;
   _template_scope = nullptr;
   _template_scope = nullptr;
@@ -34,7 +35,8 @@ CPPDeclaration(const CPPDeclaration &copy) :
   _vis(copy._vis),
   _vis(copy._vis),
   _template_scope(copy._template_scope),
   _template_scope(copy._template_scope),
   _file(copy._file),
   _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;
   _template_scope = copy._template_scope;
   _file = copy._file;
   _file = copy._file;
   _leading_comment = copy._leading_comment;
   _leading_comment = copy._leading_comment;
+  _attributes = copy._attributes;
   return *this;
   return *this;
 }
 }
 
 
@@ -135,6 +138,22 @@ substitute_decl(SubstDecl &subst, CPPScope *, CPPScope *) {
   return this;
   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 "cppVisibility.h"
 #include "cppFile.h"
 #include "cppFile.h"
 #include "cppCommentBlock.h"
 #include "cppCommentBlock.h"
+#include "cppAttributeList.h"
 
 
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
@@ -59,6 +60,9 @@ class CPPPreprocessor;
 class CPPDeclaration {
 class CPPDeclaration {
 public:
 public:
   enum SubType {
   enum SubType {
+    // Empty declaration
+    ST_empty,
+
     // Subtypes of CPPDeclaration
     // Subtypes of CPPDeclaration
     ST_instance,
     ST_instance,
     ST_type_declaration,
     ST_type_declaration,
@@ -87,7 +91,7 @@ public:
     ST_closure,
     ST_closure,
   };
   };
 
 
-  CPPDeclaration(const CPPFile &file);
+  CPPDeclaration(const CPPFile &file, CPPAttributeList attr = CPPAttributeList());
   CPPDeclaration(const CPPDeclaration &copy);
   CPPDeclaration(const CPPDeclaration &copy);
   virtual ~CPPDeclaration() {};
   virtual ~CPPDeclaration() {};
 
 
@@ -114,9 +118,9 @@ public:
   Instantiations _instantiations;
   Instantiations _instantiations;
 
 
   virtual void output(std::ostream &out, int indent_level, CPPScope *scope,
   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 CPPInstance *as_instance();
   virtual CPPClassTemplateParameter *as_class_template_parameter();
   virtual CPPClassTemplateParameter *as_class_template_parameter();
@@ -216,6 +220,7 @@ public:
   CPPTemplateScope *_template_scope;
   CPPTemplateScope *_template_scope;
   CPPFile _file;
   CPPFile _file;
   CPPCommentBlock *_leading_comment;
   CPPCommentBlock *_leading_comment;
+  CPPAttributeList _attributes;
 
 
 protected:
 protected:
   virtual bool is_equal(const CPPDeclaration *other) const;
   virtual bool is_equal(const CPPDeclaration *other) const;

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

@@ -26,8 +26,8 @@
  */
  */
 CPPEnumType::
 CPPEnumType::
 CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
 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),
   _scope(scope),
   _element_type(nullptr),
   _element_type(nullptr),
   _last_value(nullptr)
   _last_value(nullptr)
@@ -44,8 +44,9 @@ CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
  */
  */
 CPPEnumType::
 CPPEnumType::
 CPPEnumType(Type type, CPPIdentifier *ident, CPPType *element_type,
 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),
   _scope(scope),
   _element_type(element_type),
   _element_type(element_type),
   _last_value(nullptr)
   _last_value(nullptr)
@@ -89,7 +90,9 @@ get_underlying_type() {
  *
  *
  */
  */
 CPPInstance *CPPEnumType::
 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);
   CPPIdentifier *ident = new CPPIdentifier(name);
   ident->_native_scope = _parent_scope;
   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 = new CPPInstance(this, ident);
   }
   }
   inst->_storage_class |= CPPInstance::SC_constexpr;
   inst->_storage_class |= CPPInstance::SC_constexpr;
+  inst->_attributes = std::move(attr);
   _elements.push_back(inst);
   _elements.push_back(inst);
 
 
   if (value == nullptr) {
   if (value == nullptr) {
@@ -269,9 +273,12 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
       out << _type << " ";
       out << _type << " ";
     }
     }
     out << _ident->get_local_name(scope);
     out << _ident->get_local_name(scope);
-
-  } else {
+  }
+  else {
     out << _type;
     out << _type;
+    if (!_attributes.is_empty()) {
+      out << " " << _attributes;
+    }
     if (_ident != nullptr) {
     if (_ident != nullptr) {
       out << " " << _ident->get_local_name(scope);
       out << " " << _ident->get_local_name(scope);
     }
     }
@@ -280,11 +287,15 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) cons
     }
     }
 
 
     out << " {\n";
     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";
       out << ",\n";
     }
     }

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

@@ -32,15 +32,18 @@ class CPPScope;
 class CPPEnumType : public CPPExtensionType {
 class CPPEnumType : public CPPExtensionType {
 public:
 public:
   CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
   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,
   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;
   bool is_scoped() const;
   CPPType *get_underlying_type();
   CPPType *get_underlying_type();
 
 
   CPPInstance *add_element(const std::string &name, CPPExpression *value,
   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;
   virtual bool is_incomplete() const;
 
 

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

@@ -23,7 +23,7 @@
 CPPExtensionType::
 CPPExtensionType::
 CPPExtensionType(CPPExtensionType::Type type,
 CPPExtensionType(CPPExtensionType::Type type,
                  CPPIdentifier *ident, CPPScope *current_scope,
                  CPPIdentifier *ident, CPPScope *current_scope,
-                 const CPPFile &file) :
+                 const CPPFile &file, CPPAttributeList attr) :
   CPPType(file),
   CPPType(file),
   _type(type), _ident(ident),
   _type(type), _ident(ident),
   _alignment(nullptr)
   _alignment(nullptr)
@@ -31,6 +31,7 @@ CPPExtensionType(CPPExtensionType::Type type,
   if (_ident != nullptr) {
   if (_ident != nullptr) {
     _ident->_native_scope = current_scope;
     _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) {
     if (complete || cppparser_output_class_keyword) {
       out << _type << " ";
       out << _type << " ";
     }
     }
+    if (complete && !_attributes.is_empty()) {
+      out << _attributes << " ";
+    }
     out << _ident->get_local_name(scope);
     out << _ident->get_local_name(scope);
 
 
   } else if (!_typedefs.empty()) {
   } else if (!_typedefs.empty()) {

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

@@ -39,7 +39,7 @@ public:
   };
   };
 
 
   CPPExtensionType(Type type, CPPIdentifier *ident, CPPScope *current_scope,
   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_simple_name() const;
   virtual std::string get_local_name(CPPScope *scope = nullptr) 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) {
     if (_flags & F_override) {
       out << " override";
       out << " override";
     }
     }
+    if (!_attributes.is_empty()) {
+      out << " " << _attributes;
+    }
     out << " -> ";
     out << " -> ";
     _return_type->output(out, indent_level, scope, false);
     _return_type->output(out, indent_level, scope, false);
-
-  } else {
+  }
+  else {
     _return_type->output(out, indent_level, scope, complete);
     _return_type->output(out, indent_level, scope, complete);
     out << "(";
     out << "(";
     _parameters->output(out, scope, true, num_default_parameters);
     _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) {
     if (_flags & F_override) {
       out << " 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)) {
   if (_flags & (F_constructor | F_destructor)) {
     // No return type for constructors and destructors.
     // No return type for constructors and destructors.
     out << prename << name << str;
     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
     // It was declared using trailing return type, so let's format it that
     // way.
     // way.
     out << "auto ";
     out << "auto ";
@@ -291,12 +297,13 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
     }
     }
 
 
     out << str;
     out << str;
-
-  } else if (_flags & F_operator_typecast) {
+  }
+  else if (_flags & F_operator_typecast) {
     out << "operator ";
     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()) {
     if (prename.empty()) {
       _return_type->output_instance(out, indent_level, scope, complete,
       _return_type->output_instance(out, indent_level, scope, complete,
                                     "", prename + name + str);
                                     "", prename + name + str);
@@ -322,6 +329,10 @@ output_instance(ostream &out, int indent_level, CPPScope *scope,
     out << " override";
     out << " override";
   }
   }
 
 
+  if (!_attributes.is_empty()) {
+    out << " " << _attributes;
+  }
+
   if (_flags & F_trailing_return_type) {
   if (_flags & F_trailing_return_type) {
     out << " -> ";
     out << " -> ";
     _return_type->output(out, indent_level, scope, false);
     _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);
   _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 std::string &name);
   void add_name(const CPPNameComponent &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;
   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),
   _type(type),
   _ident(new CPPIdentifier(name)),
   _ident(new CPPIdentifier(name)),
   _storage_class(storage_class),
   _storage_class(storage_class),
-  _alignment(nullptr),
   _bit_width(-1)
   _bit_width(-1)
 {
 {
   _initializer = nullptr;
   _initializer = nullptr;
@@ -52,7 +51,6 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
   _type(type),
   _type(type),
   _ident(ident),
   _ident(ident),
   _storage_class(storage_class),
   _storage_class(storage_class),
-  _alignment(nullptr),
   _bit_width(-1)
   _bit_width(-1)
 {
 {
   _initializer = nullptr;
   _initializer = nullptr;
@@ -66,11 +64,11 @@ CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
 CPPInstance::
 CPPInstance::
 CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
 CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
             const CPPFile &file) :
             const CPPFile &file) :
-  CPPDeclaration(file),
-  _alignment(nullptr)
+  CPPDeclaration(file)
 {
 {
   _type = ii->unroll_type(type);
   _type = ii->unroll_type(type);
   _ident = ii->_ident;
   _ident = ii->_ident;
+  _attributes = ii->_attributes;
   ii->_ident = nullptr;
   ii->_ident = nullptr;
   _storage_class = storage_class;
   _storage_class = storage_class;
   _initializer = nullptr;
   _initializer = nullptr;
@@ -111,7 +109,6 @@ CPPInstance(const CPPInstance &copy) :
   _ident(copy._ident),
   _ident(copy._ident),
   _initializer(copy._initializer),
   _initializer(copy._initializer),
   _storage_class(copy._storage_class),
   _storage_class(copy._storage_class),
-  _alignment(copy._alignment),
   _bit_width(copy._bit_width)
   _bit_width(copy._bit_width)
 {
 {
   assert(_type != nullptr);
   assert(_type != nullptr);
@@ -156,7 +153,7 @@ operator == (const CPPInstance &other) const {
   if (_storage_class != other._storage_class) {
   if (_storage_class != other._storage_class) {
     return false;
     return false;
   }
   }
-  if (_alignment != other._alignment) {
+  if (_attributes != other._attributes) {
     return false;
     return false;
   }
   }
 
 
@@ -200,8 +197,8 @@ operator < (const CPPInstance &other) const {
   if (_storage_class != other._storage_class) {
   if (_storage_class != other._storage_class) {
     return _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
   // We *do* care about the identifier.  We need to differentiate types of
@@ -264,7 +261,7 @@ set_initializer(CPPExpression *initializer) {
  */
  */
 void CPPInstance::
 void CPPInstance::
 set_alignment(int align) {
 set_alignment(int align) {
-  _alignment = new CPPExpression(align);
+  _attributes.add_alignas(align);
 }
 }
 
 
 /**
 /**
@@ -274,7 +271,7 @@ set_alignment(int align) {
  */
  */
 void CPPInstance::
 void CPPInstance::
 set_alignment(CPPExpression *const_expr) {
 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);
     indent(out, indent_level);
   }
   }
 
 
-  if (_alignment != nullptr) {
-    out << "alignas(" << *_alignment << ") ";
+  if (!_attributes.is_empty()) {
+    out << _attributes << " ";
   }
   }
 
 
   if (_storage_class & SC_static) {
   if (_storage_class & SC_static) {
@@ -600,8 +597,8 @@ output(std::ostream &out, int indent_level, CPPScope *scope, bool complete,
     _type->as_function_type()->
     _type->as_function_type()->
       output_instance(out, indent_level, scope, complete, "", name,
       output_instance(out, indent_level, scope, complete, "", name,
                       num_default_parameters);
                       num_default_parameters);
-
-  } else {
+  }
+  else {
     _type->output_instance(out, indent_level, scope, complete, "", name);
     _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 "cppDeclaration.h"
 #include "cppType.h"
 #include "cppType.h"
 #include "cppTemplateParameterList.h"
 #include "cppTemplateParameterList.h"
+#include "cppAttributeList.h"
 
 
 class CPPInstanceIdentifier;
 class CPPInstanceIdentifier;
 class CPPIdentifier;
 class CPPIdentifier;
@@ -127,7 +128,6 @@ public:
   CPPExpression *_initializer;
   CPPExpression *_initializer;
 
 
   int _storage_class;
   int _storage_class;
-  CPPExpression *_alignment;
   int _bit_width;
   int _bit_width;
 
 
 private:
 private:

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

@@ -25,20 +25,22 @@
  *
  *
  */
  */
 CPPInstanceIdentifier::Modifier::
 CPPInstanceIdentifier::Modifier::
-Modifier(CPPInstanceIdentifierType type) :
+Modifier(CPPInstanceIdentifierType type, CPPAttributeList attr) :
   _type(type),
   _type(type),
   _func_params(nullptr),
   _func_params(nullptr),
   _func_flags(0),
   _func_flags(0),
   _scoping(nullptr),
   _scoping(nullptr),
-  _expr(nullptr) {
+  _expr(nullptr),
+  _attributes(std::move(attr)) {
 }
 }
 
 
 /**
 /**
  *
  *
  */
  */
 CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier::
 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_params = params;
   mod._func_flags = flags;
   mod._func_flags = flags;
   mod._trailing_return_type = trailing_return_type;
   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::
 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;
   mod._expr = expr;
   return mod;
   return mod;
 }
 }
@@ -59,8 +61,8 @@ array_type(CPPExpression *expr) {
  *
  *
  */
  */
 CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier::
 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;
   mod._scoping = scoping;
   return mod;
   return mod;
 }
 }
@@ -86,6 +88,17 @@ CPPInstanceIdentifier(CPPIdentifier *ident) :
   _packed(false) {
   _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
  * Unrolls the list of type punctuation on either side of the identifier to
  * determine the actual type represented by the identifier, given the
  * determine the actual type represented by the identifier, given the
@@ -103,15 +116,16 @@ unroll_type(CPPType *start_type) {
  *
  *
  */
  */
 void CPPInstanceIdentifier::
 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::
 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,
   // 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
   // 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
   // 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;
     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::
 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::
 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
   // 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
   // array modifier to them, but appending [] to the identifier.  This is to
   // work around a parser ambiguity.
   // work around a parser ambiguity.
@@ -158,7 +172,7 @@ add_array_modifier(CPPExpression *expr) {
 
 
     _ident->_names.back().append_name("[]");
     _ident->_names.back().append_name("[]");
   } else {
   } 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";
   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
  * Returns the initializer parameter list that was set for this particular
  * instance, e.g.  if the instance were:
  * instance, e.g.  if the instance were:
@@ -316,5 +338,7 @@ r_unroll_type(CPPType *start_type,
     abort();
     abort();
   }
   }
 
 
+  result->_attributes = mod._attributes;
+
   return CPPType::new_type(result);
   return CPPType::new_type(result);
 }
 }

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

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

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

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

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

@@ -27,7 +27,7 @@ class CPPScope;
 class CPPNamespace : public CPPDeclaration {
 class CPPNamespace : public CPPDeclaration {
 public:
 public:
   CPPNamespace(CPPIdentifier *ident, CPPScope *scope,
   CPPNamespace(CPPIdentifier *ident, CPPScope *scope,
-               const CPPFile &file);
+               const CPPFile &file, CPPAttributeList attr = CPPAttributeList());
 
 
   std::string get_simple_name() const;
   std::string get_simple_name() const;
   std::string get_local_name(CPPScope *scope = nullptr) 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() + "::*";
     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,
   _pointing_at->output_instance(out, indent_level, scope, complete,
                                 star + prename, name);
                                 star + prename, name);
 }
 }

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

@@ -72,10 +72,10 @@ public:
   typedef std::map<std::string, CPPManifest *> Manifests;
   typedef std::map<std::string, CPPManifest *> Manifests;
   Manifests _manifests;
   Manifests _manifests;
 
 
-  typedef pvector<CPPManifest *> ManifestStack;
+  typedef std::vector<CPPManifest *> ManifestStack;
   std::map<std::string, ManifestStack> _manifest_stack;
   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 _quote_include_path;
   DSearchPath _angle_include_path;
   DSearchPath _angle_include_path;
   bool _noangles;
   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,
                 bool complete, const std::string &prename,
                 const std::string &name) const {
                 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(CPPStructType::Type type, CPPIdentifier *ident,
 CPPStructType(CPPStructType::Type type, CPPIdentifier *ident,
               CPPScope *current_scope, CPPScope *scope,
               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),
   _scope(scope),
   _final(false)
   _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);
       get_template_scope()->_parameters.write_formal(out, scope);
       indent(out, indent_level);
       indent(out, indent_level);
     }
     }
+    out << _type;
+
+    if (!_attributes.is_empty()) {
+      out << " " << _attributes;
+    }
+
     if (_ident != nullptr) {
     if (_ident != nullptr) {
-      out << _type << " " << _ident->get_local_name(scope);
-    } else {
-      out << _type;
+      out << " " << _ident->get_local_name(scope);
     }
     }
 
 
     if (_final) {
     if (_final) {

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

@@ -35,7 +35,8 @@ public:
   CPPStructType(Type type, CPPIdentifier *ident,
   CPPStructType(Type type, CPPIdentifier *ident,
                 CPPScope *current_scope,
                 CPPScope *current_scope,
                 CPPScope *scope,
                 CPPScope *scope,
-                const CPPFile &file);
+                const CPPFile &file,
+                CPPAttributeList attr = CPPAttributeList());
   CPPStructType(const CPPStructType &copy);
   CPPStructType(const CPPStructType &copy);
   void operator = (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::
-CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope) :
+CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope,
+               CPPAttributeList attr) :
   CPPType(CPPFile()),
   CPPType(CPPFile()),
   _type(type),
   _type(type),
   _ident(ident),
   _ident(ident),
@@ -53,6 +54,8 @@ CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope) :
     _ident->_native_scope = current_scope;
     _ident->_native_scope = current_scope;
   }
   }
   _subst_decl_recursive_protect = false;
   _subst_decl_recursive_protect = false;
+
+  _attributes = std::move(attr);
 }
 }
 
 
 /**
 /**
@@ -69,6 +72,7 @@ CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii,
   assert(ii != nullptr);
   assert(ii != nullptr);
   _type = ii->unroll_type(type);
   _type = ii->unroll_type(type);
   _ident = ii->_ident;
   _ident = ii->_ident;
+  _attributes = std::move(ii->_attributes);
   ii->_ident = nullptr;
   ii->_ident = nullptr;
   delete ii;
   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);
         get_template_scope()->_parameters.write_formal(out, scope);
         indent(out, indent_level);
         indent(out, indent_level);
       }
       }
-      out << "using " << name << " = ";
+      out << "using " << name;
+      if (!_attributes.is_empty()) {
+        out << " " << _attributes;
+      }
+      out << " = ";
       _type->output(out, 0, scope, false);
       _type->output(out, 0, scope, false);
     } else {
     } else {
+      if (!_attributes.is_empty()) {
+        out << _attributes << " ";
+      }
       out << "typedef ";
       out << "typedef ";
       _type->output_instance(out, indent_level, scope, false, "", name);
       _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 {
 class CPPTypedefType : public CPPType {
 public:
 public:
   CPPTypedefType(CPPType *type, const std::string &name, CPPScope *current_scope);
   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,
   CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii,
                  CPPScope *current_scope, const CPPFile &file);
                  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 "cppFunctionType.cxx"
 #include "cppGlobals.cxx"
 #include "cppGlobals.cxx"
 #include "cppCommentBlock.cxx"
 #include "cppCommentBlock.cxx"

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

@@ -21,7 +21,7 @@ set(P3DTOOLBASE_HEADERS
   atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I
   atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I
   cmath.I cmath.h
   cmath.I cmath.h
   deletedBufferChain.h deletedBufferChain.I
   deletedBufferChain.h deletedBufferChain.I
-  deletedChain.h deletedChain.T
+  deletedChain.h deletedChain.I
   dtoolbase.h dtoolbase_cc.h dtoolsymbols.h
   dtoolbase.h dtoolbase_cc.h dtoolsymbols.h
   dtool_platform.h
   dtool_platform.h
   fakestringstream.h
   fakestringstream.h
@@ -94,12 +94,16 @@ add_component_library(p3dtoolbase NOINIT SYMBOL BUILDING_DTOOL_DTOOLBASE
 target_include_directories(p3dtoolbase PUBLIC
 target_include_directories(p3dtoolbase PUBLIC
   $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
   $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
   $<BUILD_INTERFACE:${PANDA_OUTPUT_DIR}/include>)
   $<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})
 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()
 endif()
 
 
 if(NOT BUILD_METALIBS)
 if(NOT BUILD_METALIBS)

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

@@ -11,6 +11,34 @@
  * @date 2007-07-20
  * @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
  * Returns true if the pointer is valid, false if it has been deleted or if it
  * was never a valid pointer.
  * was never a valid pointer.
@@ -41,6 +69,30 @@ get_buffer_size() const {
   return _buffer_size;
   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.
  * Casts an ObjectNode* to a void* buffer.
  */
  */

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

@@ -14,18 +14,34 @@
 #include "deletedBufferChain.h"
 #include "deletedBufferChain.h"
 #include "memoryHook.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
  * 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
 #ifdef USE_DELETED_CHAIN
   // TAU_PROFILE("void *DeletedBufferChain::allocate(size_t, TypeHandle)", "
   // TAU_PROFILE("void *DeletedBufferChain::allocate(size_t, TypeHandle)", "
   // ", TAU_USER);
   // ", TAU_USER);
+  // If this triggers, maybe you forgot ALLOC_DELETED_CHAIN in a subclass?
   assert(size <= _buffer_size);
   assert(size <= _buffer_size);
 
 
   // Determine how much space to allocate.
   // Determine how much space to allocate.
@@ -139,3 +156,16 @@ deallocate(void *ptr, TypeHandle type_handle) {
   PANDA_FREE_SINGLE(ptr);
   PANDA_FREE_SINGLE(ptr);
 #endif  // USE_DELETED_CHAIN
 #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 {
 class EXPCL_DTOOL_DTOOLBASE DeletedBufferChain {
 protected:
 protected:
-  DeletedBufferChain(size_t buffer_size);
+  constexpr explicit DeletedBufferChain(size_t buffer_size);
 
 
 public:
 public:
+  INLINE DeletedBufferChain(DeletedBufferChain &&from) noexcept;
+  INLINE DeletedBufferChain(const DeletedBufferChain &copy);
+
   void *allocate(size_t size, TypeHandle type_handle);
   void *allocate(size_t size, TypeHandle type_handle);
   void deallocate(void *ptr, TypeHandle type_handle);
   void deallocate(void *ptr, TypeHandle type_handle);
 
 
   INLINE bool validate(void *ptr);
   INLINE bool validate(void *ptr);
   INLINE size_t get_buffer_size() const;
   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:
 private:
+  static DeletedBufferChain *get_large_deleted_chain(size_t buffer_size);
+
   class ObjectNode {
   class ObjectNode {
   public:
   public:
 #ifdef USE_DELETEDCHAINFLAG
 #ifdef USE_DELETEDCHAINFLAG
@@ -87,10 +96,10 @@ private:
   static INLINE void *node_to_buffer(ObjectNode *node);
   static INLINE void *node_to_buffer(ObjectNode *node);
   static INLINE ObjectNode *buffer_to_node(void *buffer);
   static INLINE ObjectNode *buffer_to_node(void *buffer);
 
 
-  ObjectNode *_deleted_chain;
+  ObjectNode *_deleted_chain = nullptr;
 
 
   MutexImpl _lock;
   MutexImpl _lock;
-  size_t _buffer_size;
+  const size_t _buffer_size;
 
 
 #ifndef USE_DELETEDCHAINFLAG
 #ifndef USE_DELETEDCHAINFLAG
   // Without DELETEDCHAINFLAG, we don't even store the _flag member at all.
   // 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);
   static const size_t flag_reserved_bytes = sizeof(AtomicAdjust::Integer);
 #endif  // USE_DELETEDCHAINFLAG
 #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;
   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
  * license.  You should have received a copy of this license along
  * with this source code in a file named "LICENSE."
  * with this source code in a file named "LICENSE."
  *
  *
- * @file deletedChain.T
+ * @file deletedChain.I
  * @author drose
  * @author drose
  * @date 2006-04-01
  * @date 2006-04-01
  */
  */
@@ -82,7 +82,7 @@ validate(const Type *ptr) {
 template<class Type>
 template<class Type>
 INLINE ReferenceCount *DeletedChain<Type>::
 INLINE ReferenceCount *DeletedChain<Type>::
 make_ref_ptr(void *) {
 make_ref_ptr(void *) {
-  return NULL;
+  return nullptr;
 }
 }
 
 
 /**
 /**
@@ -106,9 +106,8 @@ make_ref_ptr(ReferenceCount *ptr) {
 template<class Type>
 template<class Type>
 void DeletedChain<Type>::
 void DeletedChain<Type>::
 init_deleted_chain() {
 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
 #endif  // USE_DELETED_CHAIN
 
 
-#include "deletedChain.T"
+#include "deletedChain.I"
 
 
 #endif
 #endif

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

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

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

@@ -23,34 +23,18 @@
 bool __tau_shutdown = false;
 bool __tau_shutdown = false;
 #endif
 #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
 void
 init_memory_hook() {
 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)
 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)
 
 
 static void
 static void

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

@@ -18,7 +18,7 @@
 INLINE void MemoryHook::
 INLINE void MemoryHook::
 inc_heap(size_t size) {
 inc_heap(size_t size) {
 #ifdef DO_MEMORY_USAGE
 #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
 #endif  // DO_MEMORY_USAGE
 }
 }
 
 
@@ -30,7 +30,7 @@ INLINE void MemoryHook::
 dec_heap(size_t size) {
 dec_heap(size_t size) {
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
   // assert((int)size <= _requested_heap_size);
   // 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
 #endif  // DO_MEMORY_USAGE
 }
 }
 
 
@@ -40,6 +40,9 @@ dec_heap(size_t size) {
  */
  */
 INLINE size_t MemoryHook::
 INLINE size_t MemoryHook::
 get_page_size() const {
 get_page_size() const {
+  if (_page_size == 0) {
+    determine_page_size();
+  }
   return _page_size;
   return _page_size;
 }
 }
 
 
@@ -49,6 +52,9 @@ get_page_size() const {
  */
  */
 INLINE size_t MemoryHook::
 INLINE size_t MemoryHook::
 round_up_to_page_size(size_t size) const {
 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;
   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
 #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::
 MemoryHook(const MemoryHook &copy) :
 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),
   _max_heap_size(copy._max_heap_size),
   _page_size(copy._page_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
  * 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);
   size = get_ptr_size(alloc);
   inflated_size = size;
   inflated_size = size;
 #endif
 #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) {
       _max_heap_size) {
     overflow_heap_size();
     overflow_heap_size();
   }
   }
@@ -314,8 +275,8 @@ heap_free_single(void *ptr) {
   void *alloc = ptr_to_alloc(ptr, size);
   void *alloc = ptr_to_alloc(ptr, size);
 
 
 #ifdef DO_MEMORY_USAGE
 #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
 #endif  // DO_MEMORY_USAGE
 
 
 #ifdef MEMORY_HOOK_MALLOC_LOCK
 #ifdef MEMORY_HOOK_MALLOC_LOCK
@@ -366,9 +327,9 @@ heap_alloc_array(size_t size) {
   size = get_ptr_size(alloc);
   size = get_ptr_size(alloc);
   inflated_size = size;
   inflated_size = size;
 #endif
 #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) {
       _max_heap_size) {
     overflow_heap_size();
     overflow_heap_size();
   }
   }
@@ -422,8 +383,8 @@ heap_realloc_array(void *ptr, size_t size) {
   size = get_ptr_size(alloc1);
   size = get_ptr_size(alloc1);
   inflated_size = size;
   inflated_size = size;
 #endif
 #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
 #endif  // DO_MEMORY_USAGE
 
 
   // Align this to the requested boundary.
   // Align this to the requested boundary.
@@ -463,7 +424,7 @@ heap_free_array(void *ptr) {
 
 
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
   assert((int)size <= _total_heap_array_size);
   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
 #endif  // DO_MEMORY_USAGE
 
 
 #ifdef MEMORY_HOOK_MALLOC_LOCK
 #ifdef MEMORY_HOOK_MALLOC_LOCK
@@ -522,10 +483,13 @@ heap_trim(size_t pad) {
  */
  */
 void *MemoryHook::
 void *MemoryHook::
 mmap_alloc(size_t size, bool allow_exec) {
 mmap_alloc(size_t size, bool allow_exec) {
+  if (_page_size == 0) {
+    determine_page_size();
+  }
   assert((size % _page_size) == 0);
   assert((size % _page_size) == 0);
 
 
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
-  _total_mmap_size += size;
+  _total_mmap_size.fetch_add(size, std::memory_order_relaxed);
 #endif
 #endif
 
 
 #ifdef _WIN32
 #ifdef _WIN32
@@ -576,11 +540,12 @@ mmap_alloc(size_t size, bool allow_exec) {
  */
  */
 void MemoryHook::
 void MemoryHook::
 mmap_free(void *ptr, size_t size) {
 mmap_free(void *ptr, size_t size) {
+  assert(_page_size != 0);
   assert((size % _page_size) == 0);
   assert((size % _page_size) == 0);
 
 
 #ifdef DO_MEMORY_USAGE
 #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
 #endif
 
 
 #ifdef _WIN32
 #ifdef _WIN32
@@ -601,29 +566,6 @@ void MemoryHook::
 mark_pointer(void *, size_t, ReferenceCount *) {
 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()
  * This callback method is called whenever a low-level call to call_malloc()
  * has returned NULL, indicating failure.
  * has returned NULL, indicating failure.
@@ -656,3 +598,24 @@ overflow_heap_size() {
   _max_heap_size = ~(size_t)0;
   _max_heap_size = ~(size_t)0;
 #endif  // DO_MEMORY_USAGE
 #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 "dtoolbase.h"
 #include "numeric_types.h"
 #include "numeric_types.h"
-#include "atomicAdjust.h"
+#include "patomic.h"
 #include "mutexImpl.h"
 #include "mutexImpl.h"
 #include <map>
 #include <map>
 
 
-class DeletedBufferChain;
-
 /**
 /**
  * This class provides a wrapper around the various possible malloc schemes
  * This class provides a wrapper around the various possible malloc schemes
  * Panda might employ.  It also exists to allow the MemoryUsage class in Panda
  * Panda might employ.  It also exists to allow the MemoryUsage class in Panda
@@ -36,9 +34,9 @@ class DeletedBufferChain;
  */
  */
 class EXPCL_DTOOL_DTOOLBASE MemoryHook {
 class EXPCL_DTOOL_DTOOLBASE MemoryHook {
 public:
 public:
-  MemoryHook();
+  constexpr MemoryHook() = default;
   MemoryHook(const MemoryHook &copy);
   MemoryHook(const MemoryHook &copy);
-  virtual ~MemoryHook();
+  virtual ~MemoryHook() = default;
 
 
   virtual void *heap_alloc_single(size_t size);
   virtual void *heap_alloc_single(size_t size);
   virtual void heap_free_single(void *ptr);
   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);
   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);
   virtual void alloc_fail(size_t attempted_size);
 
 
   INLINE static size_t get_ptr_size(void *ptr);
   INLINE static size_t get_ptr_size(void *ptr);
 
 
 protected:
 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
   // If the allocated heap size crosses this threshold, we call
   // overflow_heap_size().
   // overflow_heap_size().
-  size_t _max_heap_size;
+  size_t _max_heap_size = ~(size_t)0;
 
 
   virtual void overflow_heap_size();
   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;
   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)
 #if defined(__i386__) || defined(__x86_64) || defined(_M_IX86) || defined(_M_X64)
 #include <emmintrin.h>
 #include <emmintrin.h>
 #define PAUSE() _mm_pause()
 #define PAUSE() _mm_pause()
+#elif defined(_WIN32)
+#define PAUSE() YieldProcessor()
 #else
 #else
 #define PAUSE()
 #define PAUSE()
 #endif
 #endif

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

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

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

@@ -166,25 +166,6 @@ get_python_type() const {
 }
 }
 #endif
 #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 &
 std::ostream &
 operator << (std::ostream &out, TypeHandle::MemoryClass mem_class) {
 operator << (std::ostream &out, TypeHandle::MemoryClass mem_class) {
   switch (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
   // its value, it  might happen after the value had already been set
   // previously by another static initializer!
   // previously by another static initializer!
 
 
+#ifdef HAVE_PYTHON
   EXTENSION(static TypeHandle make(PyTypeObject *classobj));
   EXTENSION(static TypeHandle make(PyTypeObject *classobj));
+#endif
 
 
   INLINE bool operator == (const TypeHandle &other) const;
   INLINE bool operator == (const TypeHandle &other) const;
   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,
   INLINE TypeHandle get_parent_towards(TypeHandle ancestor,
                                        TypedObject *object = nullptr) const;
                                        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;
   size_t get_memory_usage(MemoryClass memory_class) const;
   void inc_memory_usage(MemoryClass memory_class, size_t size);
   void inc_memory_usage(MemoryClass memory_class, size_t size);
   void dec_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(parent_classes, get_num_parent_classes, get_parent_class);
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
 
 
+#ifdef HAVE_PYTHON
   EXTENSION(PyObject *__reduce__() const);
   EXTENSION(PyObject *__reduce__() const);
   EXTENSION(void __setstate__(PyObject *));
   EXTENSION(void __setstate__(PyObject *));
+#endif // HAVE_PYTHON
 
 
 public:
 public:
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
   PyObject *get_python_type() const;
   PyObject *get_python_type() const;
-#endif
+#endif // HAVE_PYTHON
 
 
   void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   void *reallocate_array(void *ptr, 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::
 void TypeRegistry::
 init_global_pointer() {
 init_global_pointer() {
-  init_memory_hook();
   _global_pointer = new TypeRegistry;
   _global_pointer = new TypeRegistry;
 }
 }
 
 
@@ -696,21 +695,3 @@ look_up_invalid(TypeHandle handle, TypedObject *object) const {
 
 
   return _handle_registry[handle._index];
   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;
   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 "typeHandle.h"
 
 
 #include "typeRegistry.I"
 #include "typeRegistry.I"

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

@@ -43,14 +43,6 @@ is_exact_type(TypeHandle handle) const {
   return get_type() == handle;
   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.
  * 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;
   INLINE bool is_exact_type(TypeHandle handle) const;
 
 
 public:
 public:
-  INLINE int get_best_parent_from_Set(const std::set<int> &) const;
-
   // Derived classes should override this function to call init_type().  It
   // 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
   // will only be called in error situations when the type was for some reason
   // not properly initialized.
   // not properly initialized.

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

@@ -53,8 +53,8 @@ PUBLISHED:
   };
   };
 
 
   DSearchPath() = default;
   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(const DSearchPath &copy) = default;
   DSearchPath(DSearchPath &&from) = default;
   DSearchPath(DSearchPath &&from) = default;
   ~DSearchPath() = 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") {
   } else if (var == "XDG_DATA_HOME") {
     Filename home_dir = Filename::get_home_directory();
     Filename home_dir = Filename::get_home_directory();
     return home_dir.get_fullpath() + "/.local/share";
     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
 #endif // _WIN32
 
 

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

@@ -16,7 +16,6 @@
 #include "dSearchPath.h"
 #include "dSearchPath.h"
 #include "executionEnvironment.h"
 #include "executionEnvironment.h"
 #include "vector_string.h"
 #include "vector_string.h"
-#include "atomicAdjust.h"
 
 
 #include <stdio.h>  // For rename() and tempnam()
 #include <stdio.h>  // For rename() and tempnam()
 #include <time.h>   // for clock() and time()
 #include <time.h>   // for clock() and time()
@@ -60,10 +59,10 @@ using std::wstring;
 
 
 TextEncoder::Encoding Filename::_filesystem_encoding = TextEncoder::E_utf8;
 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;
 TypeHandle Filename::_type_handle;
 
 
 #ifdef ANDROID
 #ifdef ANDROID
@@ -486,7 +485,8 @@ temporary(const string &dirname, const string &prefix, const string &suffix,
  */
  */
 const Filename &Filename::
 const Filename &Filename::
 get_home_directory() {
 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;
     Filename home_directory;
 
 
     // In all environments except Windows, check $HOME first.
     // In all environments except Windows, check $HOME first.
@@ -538,14 +538,16 @@ get_home_directory() {
     }
     }
 
 
     Filename *newdir = new Filename(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.
       // Didn't store it.  Must have been stored by someone else.
-      assert(_home_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
       delete newdir;
     }
     }
   }
   }
 
 
-  return (*(Filename *)_home_directory);
+  return *curdir;
 }
 }
 
 
 /**
 /**
@@ -553,7 +555,8 @@ get_home_directory() {
  */
  */
 const Filename &Filename::
 const Filename &Filename::
 get_temp_directory() {
 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;
     Filename temp_directory;
 
 
 #ifdef _WIN32
 #ifdef _WIN32
@@ -586,14 +589,16 @@ get_temp_directory() {
     }
     }
 
 
     Filename *newdir = new Filename(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.
       // Didn't store it.  Must have been stored by someone else.
-      assert(_temp_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
       delete newdir;
     }
     }
   }
   }
 
 
-  return (*(Filename *)_temp_directory);
+  return *curdir;
 }
 }
 
 
 /**
 /**
@@ -603,7 +608,8 @@ get_temp_directory() {
  */
  */
 const Filename &Filename::
 const Filename &Filename::
 get_user_appdata_directory() {
 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;
     Filename user_appdata_directory;
 
 
 #ifdef _WIN32
 #ifdef _WIN32
@@ -643,14 +649,16 @@ get_user_appdata_directory() {
     }
     }
 
 
     Filename *newdir = new Filename(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.
       // Didn't store it.  Must have been stored by someone else.
-      assert(_user_appdata_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
       delete newdir;
     }
     }
   }
   }
 
 
-  return (*(Filename *)_user_appdata_directory);
+  return *curdir;
 }
 }
 
 
 /**
 /**
@@ -659,7 +667,8 @@ get_user_appdata_directory() {
  */
  */
 const Filename &Filename::
 const Filename &Filename::
 get_common_appdata_directory() {
 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;
     Filename common_appdata_directory;
 
 
 #ifdef _WIN32
 #ifdef _WIN32
@@ -693,14 +702,16 @@ get_common_appdata_directory() {
     }
     }
 
 
     Filename *newdir = new Filename(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.
       // Didn't store it.  Must have been stored by someone else.
-      assert(_common_appdata_directory != nullptr);
+      assert(curdir != nullptr);
       delete newdir;
       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 "register_type.h"
 #include "vector_string.h"
 #include "vector_string.h"
 #include "textEncoder.h"
 #include "textEncoder.h"
+#include "patomic.h"
 
 
 #include <assert.h>
 #include <assert.h>
 
 
@@ -63,13 +64,13 @@ public:
 
 
 PUBLISHED:
 PUBLISHED:
   INLINE Filename();
   INLINE Filename();
-  Filename(const Filename &dirname, const Filename &basename);
+  explicit Filename(const Filename &dirname, const Filename &basename);
 
 
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
   EXTENSION(Filename(PyObject *path));
   EXTENSION(Filename(PyObject *path));
 
 
   EXTENSION(PyObject *__reduce__(PyObject *self) const);
   EXTENSION(PyObject *__reduce__(PyObject *self) const);
-#endif
+#endif // HAVE_PYTHON
 
 
   // Static constructors to explicitly create a filename that refers to a text
   // 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
   // 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 size_t length() const;
   INLINE char operator [] (size_t n) const;
   INLINE char operator [] (size_t n) const;
 
 
+#ifdef HAVE_PYTHON
   EXTENSION(PyObject *__repr__() const);
   EXTENSION(PyObject *__repr__() const);
   EXTENSION(PyObject *__fspath__() const);
   EXTENSION(PyObject *__fspath__() const);
+#endif // HAVE_PYTHON
 
 
   INLINE std::string substr(size_t begin) const;
   INLINE std::string substr(size_t begin) const;
   INLINE std::string substr(size_t begin, size_t end) const;
   INLINE std::string substr(size_t begin, size_t end) const;
@@ -201,7 +204,7 @@ PUBLISHED:
   bool scan_directory(vector_string &contents) const;
   bool scan_directory(vector_string &contents) const;
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
   EXTENSION(PyObject *scan_directory() const);
   EXTENSION(PyObject *scan_directory() const);
-#endif
+#endif // HAVE_PYTHON
 
 
   bool open_read(std::ifstream &stream) const;
   bool open_read(std::ifstream &stream) const;
   bool open_write(std::ofstream &stream, bool truncate = true) const;
   bool open_write(std::ofstream &stream, bool truncate = true) const;
@@ -265,15 +268,15 @@ protected:
   int _flags;
   int _flags;
 
 
   static TextEncoder::Encoding _filesystem_encoding;
   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
 #ifdef ANDROID
 public:
 public:
   static std::string _internal_data_dir;
   static std::string _internal_data_dir;
-#endif
+#endif // ANDROID
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
@@ -294,4 +297,4 @@ INLINE std::ostream &operator << (std::ostream &out, const Filename &n) {
 
 
 #include "filename.I"
 #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();
   INLINE static Encoding get_default_encoding();
   MAKE_PROPERTY(default_encoding, get_default_encoding, set_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);
   EXTEND void set_text(PyObject *text, Encoding encoding);
   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);
   INLINE void set_text(const std::string &text, Encoding encoding);
   INLINE void set_text(const std::string &text, Encoding encoding);
-#endif
+#endif // CPPPARSER && HAVE_PYTHON
   INLINE void clear_text();
   INLINE void clear_text();
   INLINE bool has_text() const;
   INLINE bool has_text() const;
 
 
   void make_upper();
   void make_upper();
   void make_lower();
   void make_lower();
 
 
-#ifdef CPPPARSER
+#if defined(CPPPARSER) && defined(HAVE_PYTHON)
   EXTEND PyObject *get_text() const;
   EXTEND PyObject *get_text() const;
   EXTEND PyObject *get_text(Encoding encoding) const;
   EXTEND PyObject *get_text(Encoding encoding) const;
   EXTEND void append_text(PyObject *text);
   EXTEND void append_text(PyObject *text);
-#else
+#else // CPPPARSER && HAVE_PYTHON
   INLINE std::string get_text() const;
   INLINE std::string get_text() const;
   INLINE std::string get_text(Encoding encoding) const;
   INLINE std::string get_text(Encoding encoding) const;
   INLINE void append_text(const std::string &text);
   INLINE void append_text(const std::string &text);
-#endif
+#endif // CPPPARSER && HAVE_PYTHON
   INLINE void append_unicode_char(char32_t character);
   INLINE void append_unicode_char(char32_t character);
   INLINE size_t get_num_chars() const;
   INLINE size_t get_num_chars() const;
   INLINE int get_unicode_char(size_t index) const;
   INLINE int get_unicode_char(size_t index) const;
@@ -108,19 +108,19 @@ PUBLISHED:
   std::wstring get_wtext_as_ascii() const;
   std::wstring get_wtext_as_ascii() const;
   bool is_wtext() const;
   bool is_wtext() const;
 
 
-#ifdef CPPPARSER
+#if defined(CPPPARSER) && defined(HAVE_PYTHON)
   EXTEND static PyObject *encode_wchar(char32_t ch, Encoding encoding);
   EXTEND static PyObject *encode_wchar(char32_t ch, Encoding encoding);
   EXTEND INLINE PyObject *encode_wtext(const std::wstring &wtext) const;
   EXTEND INLINE PyObject *encode_wtext(const std::wstring &wtext) const;
   EXTEND static PyObject *encode_wtext(const std::wstring &wtext, Encoding encoding);
   EXTEND static PyObject *encode_wtext(const std::wstring &wtext, Encoding encoding);
   EXTEND INLINE PyObject *decode_text(PyObject *text) const;
   EXTEND INLINE PyObject *decode_text(PyObject *text) const;
   EXTEND static PyObject *decode_text(PyObject *text, Encoding encoding);
   EXTEND static PyObject *decode_text(PyObject *text, Encoding encoding);
-#else
+#else // CPPPARSER && HAVE_PYTHON
   static std::string encode_wchar(char32_t ch, Encoding encoding);
   static std::string encode_wchar(char32_t ch, Encoding encoding);
   INLINE std::string encode_wtext(const std::wstring &wtext) const;
   INLINE std::string encode_wtext(const std::wstring &wtext) const;
   static std::string encode_wtext(const std::wstring &wtext, Encoding encoding);
   static std::string encode_wtext(const std::wstring &wtext, Encoding encoding);
   INLINE std::wstring decode_text(const std::string &text) const;
   INLINE std::wstring decode_text(const std::string &text) const;
   static std::wstring decode_text(const std::string &text, Encoding encoding);
   static std::wstring decode_text(const std::string &text, Encoding encoding);
-#endif
+#endif // CPPPARSER && HAVE_PYTHON
 
 
   MAKE_PROPERTY(text, get_text, set_text);
   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"
 #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;
     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;
   Parameters::const_iterator pi;
   for (pi = _parameters.begin();
   for (pi = _parameters.begin();
        pi != _parameters.end();
        pi != _parameters.end();
@@ -856,8 +872,13 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     } else if (fname == "make") {
     } else if (fname == "make") {
       if (!_has_this && _parameters.size() >= 1 &&
       if (!_has_this && _parameters.size() >= 1 &&
           TypeManager::is_pointer(_return_type->get_new_type())) {
           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) {
       if (_args_type == InterfaceMaker::AT_varargs) {

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

@@ -74,7 +74,7 @@ RenameSet methodRenameDictionary[] = {
   { "operator ="    , "assign",                 0 },
   { "operator ="    , "assign",                 0 },
   { "operator ()"   , "__call__",               0 },
   { "operator ()"   , "__call__",               0 },
   { "operator []"   , "__getitem__",            0 },
   { "operator []"   , "__getitem__",            0 },
-  { "operator [] =" , "__setitem__",            0 },
+  { "operator []="  , "__setitem__",            0 },
   { "operator ++unary", "increment",            0 },
   { "operator ++unary", "increment",            0 },
   { "operator ++"   , "increment",              0 },
   { "operator ++"   , "increment",              0 },
   { "operator --unary", "decrement",            0 },
   { "operator --unary", "decrement",            0 },
@@ -1221,22 +1221,33 @@ write_class_details(ostream &out, Object *obj) {
     out << "  return nullptr;\n";
     out << "  return nullptr;\n";
     out << "}\n\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 << "  if (from_this == nullptr || from_type == nullptr) {\n";
     out << "    return nullptr;\n";
     out << "    return nullptr;\n";
     out << "  }\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";
     out << "  }\n";
     for (di = details.begin(); di != details.end(); di++) {
     for (di = details.begin(); di != details.end(); di++) {
       if (di->second._can_downcast && di->second._is_legal_py_class) {
       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 << "    " << 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 << "  }\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";
     out << "}\n\n";
   }
   }
 }
 }
@@ -3251,7 +3262,7 @@ write_module_class(ostream &out, Object *obj) {
   out << "  TypeHandle::none(),\n";
   out << "  TypeHandle::none(),\n";
   out << "  Dtool_PyModuleClassInit_" << ClassName << ",\n";
   out << "  Dtool_PyModuleClassInit_" << ClassName << ",\n";
   out << "  Dtool_UpcastInterface_" << 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());
   int has_coerce = has_coerce_constructor(obj->_itype._cpptype->as_struct_type());
   if (has_coerce > 0) {
   if (has_coerce > 0) {
@@ -4819,9 +4830,13 @@ write_function_instance(ostream &out, FunctionRemap *remap,
     // The function handles the arguments by itself.
     // The function handles the arguments by itself.
     expected_params += "*args";
     expected_params += "*args";
     pexprs.push_back("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;
     num_params = 0;
   }
   }

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

@@ -417,8 +417,8 @@ main(int argc, char **argv) {
       break;
       break;
 
 
     case CO_python_native:
     case CO_python_native:
-        build_python_native = true;
-        break;
+      build_python_native = true;
+      break;
 
 
     case CO_track_interpreter:
     case CO_track_interpreter:
       track_interpreter = true;
       track_interpreter = true;
@@ -513,7 +513,7 @@ main(int argc, char **argv) {
   for (i = 1; i < argc; ++i) {
   for (i = 1; i < argc; ++i) {
     Filename filename = Filename::from_os_specific(argv[i]);
     Filename filename = Filename::from_os_specific(argv[i]);
     if (!parser.parse_file(filename)) {
     if (!parser.parse_file(filename)) {
-      cerr << "Error parsing file: '" << argv[i] << "'\n";
+      cerr << "interrogate failed to parse file: '" << argv[i] << "'\n";
       exit(1);
       exit(1);
     }
     }
     builder.add_source_file(filename.to_os_generic());
     builder.add_source_file(filename.to_os_generic());
@@ -604,23 +604,22 @@ main(int argc, char **argv) {
       << " *\n"
       << " *\n"
       << " */\n\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()) {
     if (output_code.fail()) {
       nout << "Unable to write to " << output_code_filename << "\n";
       nout << "Unable to write to " << output_code_filename << "\n";
       status = -1;
       status = -1;
     } else {
     } 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.
   // And now output the bulk of the database.
   if (!output_data_filename.empty()) {
   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)) {
   if (forced || !in_ignoretype(true_name)) {
     itype._flags |= InterrogateType::F_fully_defined;
     itype._flags |= InterrogateType::F_fully_defined;
 
 
@@ -3050,7 +3054,7 @@ define_method(CPPInstance *function, InterrogateType &itype,
         CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0);
         CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0);
 
 
         // Now make up an instance for the function.
         // 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;
         function->_ident->_native_scope = scope;
 
 
         FunctionIndex index = get_function(function, "",
         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;
   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;
   return nullptr;
 }
 }
 
 
@@ -140,7 +140,7 @@ Dtool_PyTypedObject *Dtool_GetSuperBase() {
     TypeHandle::none(),
     TypeHandle::none(),
     Dtool_PyModuleClassInit_DTOOL_SUPER_BASE,
     Dtool_PyModuleClassInit_DTOOL_SUPER_BASE,
     Dtool_UpcastInterface_DTOOL_SUPER_BASE,
     Dtool_UpcastInterface_DTOOL_SUPER_BASE,
-    Dtool_DowncastInterface_DTOOL_SUPER_BASE,
+    Dtool_Wrap_DTOOL_SUPER_BASE,
     nullptr,
     nullptr,
     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;
   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 FunctionIndex get_function() const;
 
 
   INLINE bool is_callable_by_name() 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 bool has_return_value() const;
   INLINE TypeIndex get_return_type() const;
   INLINE TypeIndex get_return_type() const;
@@ -61,7 +65,11 @@ private:
   enum Flags {
   enum Flags {
     F_caller_manages   = 0x0001,
     F_caller_manages   = 0x0001,
     F_has_return       = 0x0002,
     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 {
   enum ParameterFlags {

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

@@ -20,6 +20,16 @@ is_global() const {
   return (_flags & F_global) != 0;
   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;
+}
+
 /**
 /**
  *
  *
  */
  */

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio