瀏覽代碼

Merge branch 'cmake'

rdb 5 年之前
父節點
當前提交
b272af8bbf
共有 100 個文件被更改,包括 9173 次插入0 次删除
  1. 345 0
      .github/workflows/ci.yml
  2. 152 0
      CMakeLists.txt
  3. 78 0
      cmake/README.md
  4. 157 0
      cmake/install/Panda3DConfig.cmake
  5. 75 0
      cmake/macros/AddBisonTarget.cmake
  6. 77 0
      cmake/macros/AddFlexTarget.cmake
  7. 426 0
      cmake/macros/BuildMetalib.cmake
  8. 167 0
      cmake/macros/CompositeSources.cmake
  9. 400 0
      cmake/macros/Interrogate.cmake
  10. 506 0
      cmake/macros/PackageConfig.cmake
  11. 163 0
      cmake/macros/Python.cmake
  12. 9 0
      cmake/macros/README.md
  13. 37 0
      cmake/macros/RunPzip.cmake
  14. 21 0
      cmake/macros/Versioning.cmake
  15. 33 0
      cmake/modules/FindARToolKit.cmake
  16. 33 0
      cmake/modules/FindAssimp.cmake
  17. 175 0
      cmake/modules/FindCg.cmake
  18. 104 0
      cmake/modules/FindDirect3D9.cmake
  19. 21 0
      cmake/modules/FindEGL.cmake
  20. 25 0
      cmake/modules/FindEigen3.cmake
  21. 88 0
      cmake/modules/FindFCollada.cmake
  22. 116 0
      cmake/modules/FindFFMPEG.cmake
  23. 107 0
      cmake/modules/FindFFTW3.cmake
  24. 83 0
      cmake/modules/FindFMODEx.cmake
  25. 23 0
      cmake/modules/FindHarfBuzz.cmake
  26. 78 0
      cmake/modules/FindLibSquish.cmake
  27. 157 0
      cmake/modules/FindODE.cmake
  28. 20 0
      cmake/modules/FindOgg.cmake
  29. 92 0
      cmake/modules/FindOpenCV.cmake
  30. 88 0
      cmake/modules/FindOpenEXR.cmake
  31. 21 0
      cmake/modules/FindOpenGLES1.cmake
  32. 21 0
      cmake/modules/FindOpenGLES2.cmake
  33. 34 0
      cmake/modules/FindOpusFile.cmake
  34. 50 0
      cmake/modules/FindSWResample.cmake
  35. 50 0
      cmake/modules/FindSWScale.cmake
  36. 40 0
      cmake/modules/FindVRPN.cmake
  37. 34 0
      cmake/modules/FindVorbisFile.cmake
  38. 7 0
      cmake/modules/README.md
  39. 70 0
      cmake/scripts/ConcatenateToCXX.cmake
  40. 27 0
      cmake/scripts/CopyPattern.cmake
  41. 78 0
      cmake/scripts/CopyPython.cmake
  42. 28 0
      cmake/scripts/MakeComposite.cmake
  43. 10 0
      cmake/scripts/README.md
  44. 9 0
      cmake/templates/metalib_init.cxx.in
  45. 9 0
      cmake/templates/metalib_init.h.in
  46. 23 0
      cmake/templates/win32_python/__init__.py
  47. 18 0
      contrib/CMakeLists.txt
  48. 54 0
      contrib/src/ai/CMakeLists.txt
  49. 14 0
      contrib/src/contribbase/CMakeLists.txt
  50. 52 0
      contrib/src/rplight/CMakeLists.txt
  51. 75 0
      direct/CMakeLists.txt
  52. 3 0
      direct/src/dcparse/CMakeLists.txt
  53. 87 0
      direct/src/dcparser/CMakeLists.txt
  54. 24 0
      direct/src/deadrec/CMakeLists.txt
  55. 14 0
      direct/src/directbase/CMakeLists.txt
  56. 35 0
      direct/src/distributed/CMakeLists.txt
  57. 54 0
      direct/src/interval/CMakeLists.txt
  58. 24 0
      direct/src/motiontrail/CMakeLists.txt
  59. 32 0
      direct/src/showbase/CMakeLists.txt
  60. 14 0
      dtool/CMakeLists.txt
  61. 247 0
      dtool/CompilerFlags.cmake
  62. 600 0
      dtool/Config.cmake
  63. 219 0
      dtool/LocalSetup.cmake
  64. 765 0
      dtool/Package.cmake
  65. 103 0
      dtool/PandaVersion.cmake
  66. 251 0
      dtool/dtool_config.h.in
  67. 13 0
      dtool/metalibs/dtool/CMakeLists.txt
  68. 44 0
      dtool/src/cppparser/CMakeLists.txt
  69. 6 0
      dtool/src/dconfig/CMakeLists.txt
  70. 106 0
      dtool/src/dtoolbase/CMakeLists.txt
  71. 21 0
      dtool/src/dtoolbase/checkPandaVersion.cxx.in
  72. 64 0
      dtool/src/dtoolbase/checkPandaVersion.h.in
  73. 73 0
      dtool/src/dtoolbase/pandaVersion.h.in
  74. 153 0
      dtool/src/dtoolutil/CMakeLists.txt
  75. 128 0
      dtool/src/interrogate/CMakeLists.txt
  76. 76 0
      dtool/src/interrogatedb/CMakeLists.txt
  77. 157 0
      dtool/src/prc/CMakeLists.txt
  78. 56 0
      dtool/src/prc/prc_parameters.h.in
  79. 47 0
      makepanda/selfdestruct.py
  80. 174 0
      panda/CMakeLists.txt
  81. 32 0
      panda/metalibs/panda/CMakeLists.txt
  82. 18 0
      panda/metalibs/pandadx9/CMakeLists.txt
  83. 19 0
      panda/metalibs/pandaegg/CMakeLists.txt
  84. 12 0
      panda/metalibs/pandaexpress/CMakeLists.txt
  85. 45 0
      panda/metalibs/pandagl/CMakeLists.txt
  86. 28 0
      panda/metalibs/pandagles/CMakeLists.txt
  87. 18 0
      panda/metalibs/pandagles2/CMakeLists.txt
  88. 12 0
      panda/metalibs/pandaphysics/CMakeLists.txt
  89. 39 0
      panda/src/audio/CMakeLists.txt
  90. 61 0
      panda/src/audiotraits/CMakeLists.txt
  91. 130 0
      panda/src/bullet/CMakeLists.txt
  92. 69 0
      panda/src/chan/CMakeLists.txt
  93. 36 0
      panda/src/char/CMakeLists.txt
  94. 47 0
      panda/src/cocoadisplay/CMakeLists.txt
  95. 82 0
      panda/src/collide/CMakeLists.txt
  96. 79 0
      panda/src/configfiles/CMakeLists.txt
  97. 130 0
      panda/src/configfiles/panda.prc.in
  98. 37 0
      panda/src/cull/CMakeLists.txt
  99. 80 0
      panda/src/device/CMakeLists.txt
  100. 29 0
      panda/src/dgraph/CMakeLists.txt

+ 345 - 0
.github/workflows/ci.yml

@@ -1,6 +1,351 @@
 name: Continuous Integration
 on: [push, pull_request]
+
 jobs:
+  cmake:
+    name: CMake Buildsystem
+
+    strategy:
+      fail-fast: false
+
+      matrix:
+        profile:
+        - ubuntu-xenial-standard-unity-makefile
+        - ubuntu-bionic-coverage-ninja
+        - macos-eigen-coverage-unity-xcode
+        - macos-nometa-standard-makefile
+#       - windows-standard-unity-msvc # FIXME when GH Actions runners upgrade CMake to >=3.16.1
+        - windows-nopython-nometa-standard-msvc
+
+        include:
+        - profile: ubuntu-xenial-standard-unity-makefile
+          os: ubuntu-16.04
+          config: Standard
+          unity: YES
+          generator: Unix Makefiles
+          compiler: Default
+          metalibs: YES
+          python: YES
+          eigen: NO
+
+        - profile: ubuntu-bionic-coverage-ninja
+          os: ubuntu-18.04
+          config: Coverage
+          unity: NO
+          generator: Ninja
+          compiler: Clang
+          metalibs: YES
+          python: YES
+          eigen: NO
+
+        - profile: macos-eigen-coverage-unity-xcode
+          os: macOS-latest
+          config: Coverage
+          unity: YES
+          generator: Xcode
+          compiler: Default
+          metalibs: YES
+          python: YES
+          eigen: YES
+
+        - profile: macos-nometa-standard-makefile
+          os: macOS-latest
+          config: Standard
+          unity: NO
+          generator: Unix Makefiles
+          compiler: Default
+          metalibs: NO
+          python: YES
+          eigen: NO
+
+        - profile: windows-standard-unity-msvc
+          os: windows-2019
+          config: Standard
+          unity: YES
+          generator: Visual Studio 16 2019
+          compiler: Default
+          metalibs: YES
+          python: YES
+          eigen: NO
+
+        - profile: windows-nopython-nometa-standard-msvc
+          os: windows-2019
+          config: Standard
+          unity: NO
+          generator: Visual Studio 16 2019
+          compiler: Default
+          metalibs: NO
+          python: NO
+          eigen: NO
+
+    runs-on: ${{ matrix.os }}
+
+    steps:
+    - uses: actions/checkout@v1
+      with:
+        fetch-depth: 10
+
+    - name: Self-destruct makepanda
+      run: python makepanda/selfdestruct.py --yes
+
+    - name: Install dependencies (macOS)
+      if: runner.os == 'macOS'
+      run: |
+        curl -O https://www.panda3d.org/download/panda3d-1.10.5/panda3d-1.10.5-tools-mac.tar.gz
+        tar -xf panda3d-1.10.5-tools-mac.tar.gz
+
+        brew install ccache
+
+        echo "##[set-env name=thirdpartyOption;]-D THIRDPARTY_DIRECTORY=../panda3d-1.10.5/thirdparty" -DHAVE_CG=OFF
+
+    - name: Install dependencies (Ubuntu)
+      if: startsWith(matrix.os, 'ubuntu')
+      run: >
+        sudo apt-get update
+
+        sudo apt-get install
+        build-essential ninja-build clang llvm ccache
+        bison flex
+        libeigen3-dev libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev
+        libopenal-dev libpng-dev libssl-dev libvorbis-dev libx11-dev
+        libxcursor-dev libxrandr-dev nvidia-cg-toolkit zlib1g-dev
+
+        # Workaround for CMake 3.12 finding this first:
+
+        sudo rm /usr/bin/x86_64-linux-gnu-python2.7-config
+
+    - name: Cache dependencies (Windows)
+      if: runner.os == 'Windows'
+      uses: actions/cache@v1
+      with:
+        path: thirdparty-tools
+        key: ci-cmake-${{ runner.OS }}-thirdparty-v1.10.5-r1
+    - name: Install dependencies (Windows)
+      if: runner.os == 'Windows'
+      shell: powershell
+      run: |
+        if (!(Test-Path thirdparty-tools/panda3d-1.10.5)) {
+          $wc = New-Object System.Net.WebClient
+          $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.5/panda3d-1.10.5-tools-win64.zip", "thirdparty-tools.zip")
+          Expand-Archive -Path thirdparty-tools.zip
+        }
+
+        echo "##[set-env name=thirdpartyOption;]-D THIRDPARTY_DIRECTORY=../thirdparty-tools/panda3d-1.10.5/thirdparty"
+
+    - name: ccache (non-Windows)
+      if: runner.os != 'Windows'
+      uses: actions/cache@v1
+      with:
+        path: ccache
+        key: ci-cmake-ccache-${{ matrix.profile }}
+
+    - name: Configure
+      shell: bash
+      env:
+        CMAKE_GENERATOR: "${{ matrix.generator }}"
+      run: >
+        mkdir build
+
+        cd build
+
+        if ${{ matrix.compiler == 'Clang' }}; then
+          if [[ "$CMAKE_GENERATOR" == *Studio*2019* ]]; then
+            export CMAKE_GENERATOR_TOOLSET=ClangCL thirdpartyOption="$thirdpartyOption -DHAVE_HARFBUZZ=NO"
+          elif [[ "$CMAKE_GENERATOR" == *Studio* ]]; then
+            export CMAKE_GENERATOR_TOOLSET=LLVM thirdpartyOption="$thirdpartyOption -DHAVE_HARFBUZZ=NO"
+          else
+            export CC=clang CXX=clang++
+          fi
+        fi
+
+        if ${{ runner.os != 'Windows' }}; then
+          compilerLauncher=$(echo -DCMAKE_C{,XX}_COMPILER_LAUNCHER=ccache)
+          echo "##[set-env name=CCACHE_DIR;]$(dirname $PWD)/ccache"
+        fi
+
+        cmake
+        ${compilerLauncher:-}
+        -D CMAKE_UNITY_BUILD=${{ matrix.unity }}
+        -D CMAKE_BUILD_TYPE="${{ matrix.config }}"
+        -D BUILD_METALIBS=${{ matrix.metalibs }}
+        -D HAVE_PYTHON=${{ matrix.python }}
+        -D HAVE_EIGEN=${{ matrix.eigen }}
+        ${thirdpartyOption:-}
+        ..
+
+    - name: Build (no Python)
+      if: contains(matrix.python, 'NO')
+      # BEGIN A
+      working-directory: build
+      run: cmake --build . --config ${{ matrix.config }} --parallel 4
+      # END A
+
+    - name: Setup Python (Python 2.7)
+      if: contains(matrix.python, 'YES')
+      uses: actions/setup-python@v1
+      with:
+        python-version: 2.7
+    - name: Configure (Python 2.7)
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: >
+        cmake -DWANT_PYTHON_VERSION=2.7
+        -DPython_FIND_REGISTRY=NEVER -DPython_ROOT=$pythonLocation .
+    - name: Build (Python 2.7)
+      if: contains(matrix.python, 'YES')
+      # BEGIN A
+      working-directory: build
+      run: cmake --build . --config ${{ matrix.config }} --parallel 4
+      # END A
+    - name: Test (Python 2.7)
+      # BEGIN B
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: |
+        PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:FILEPATH' CMakeCache.txt | sed 's/.*=//')
+        $PYTHON_EXECUTABLE -m pip install pytest pytest-cov
+        export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
+        ctest -V -C ${{ matrix.config }}
+      # END B
+
+    - name: Setup Python (Python 3.5)
+      if: contains(matrix.python, 'YES')
+      uses: actions/setup-python@v1
+      with:
+        python-version: 3.5
+    - name: Configure (Python 3.5)
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: >
+        cmake -DWANT_PYTHON_VERSION=3.5
+        -DPython_FIND_REGISTRY=NEVER -DPython_ROOT=$pythonLocation .
+    - name: Build (Python 3.5)
+      if: contains(matrix.python, 'YES')
+      # BEGIN A
+      working-directory: build
+      run: cmake --build . --config ${{ matrix.config }} --parallel 4
+      # END A
+    - name: Test (Python 3.5)
+      # BEGIN B
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: |
+        PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:FILEPATH' CMakeCache.txt | sed 's/.*=//')
+        $PYTHON_EXECUTABLE -m pip install pytest pytest-cov
+        export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
+        ctest -V -C ${{ matrix.config }}
+      # END B
+
+    - name: Setup Python (Python 3.6)
+      if: contains(matrix.python, 'YES')
+      uses: actions/setup-python@v1
+      with:
+        python-version: 3.6
+    - name: Configure (Python 3.6)
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: >
+        cmake -DWANT_PYTHON_VERSION=3.6
+        -DPython_FIND_REGISTRY=NEVER -DPython_ROOT=$pythonLocation .
+    - name: Build (Python 3.6)
+      if: contains(matrix.python, 'YES')
+      # BEGIN A
+      working-directory: build
+      run: cmake --build . --config ${{ matrix.config }} --parallel 4
+      # END A
+    - name: Test (Python 3.6)
+      # BEGIN B
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: |
+        PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:FILEPATH' CMakeCache.txt | sed 's/.*=//')
+        $PYTHON_EXECUTABLE -m pip install pytest pytest-cov
+        export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
+        ctest -V -C ${{ matrix.config }}
+      # END B
+
+    - name: Setup Python (Python 3.7)
+      if: contains(matrix.python, 'YES')
+      uses: actions/setup-python@v1
+      with:
+        python-version: 3.7
+    - name: Configure (Python 3.7)
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: >
+        cmake -DWANT_PYTHON_VERSION=3.7
+        -DPython_FIND_REGISTRY=NEVER -DPython_ROOT=$pythonLocation .
+    - name: Build (Python 3.7)
+      if: contains(matrix.python, 'YES')
+      # BEGIN A
+      working-directory: build
+      run: cmake --build . --config ${{ matrix.config }} --parallel 4
+      # END A
+    - name: Test (Python 3.7)
+      # BEGIN B
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: |
+        PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:FILEPATH' CMakeCache.txt | sed 's/.*=//')
+        $PYTHON_EXECUTABLE -m pip install pytest pytest-cov
+        export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
+        ctest -V -C ${{ matrix.config }}
+      # END B
+
+    - name: Setup Python (Python 3.8)
+      if: contains(matrix.python, 'YES')
+      uses: actions/setup-python@v1
+      with:
+        python-version: 3.8
+    - name: Configure (Python 3.8)
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: >
+        cmake -DWANT_PYTHON_VERSION=3.8
+        -DPython_FIND_REGISTRY=NEVER -DPython_ROOT=$pythonLocation .
+    - name: Build (Python 3.8)
+      if: contains(matrix.python, 'YES')
+      # BEGIN A
+      working-directory: build
+      run: cmake --build . --config ${{ matrix.config }} --parallel 4
+      # END A
+    - name: Test (Python 3.8)
+      # BEGIN B
+      if: contains(matrix.python, 'YES')
+      working-directory: build
+      shell: bash
+      run: |
+        PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:FILEPATH' CMakeCache.txt | sed 's/.*=//')
+        $PYTHON_EXECUTABLE -m pip install pytest pytest-cov
+        export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw
+        ctest -V -C ${{ matrix.config }}
+      # END B
+
+    - name: Upload coverage reports
+      if: always() && matrix.config == 'Coverage'
+      working-directory: build
+      shell: bash
+      env:
+        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+      run: |
+        shopt -s expand_aliases
+        if ${{ runner.os == 'macOS' }}; then alias llvm-profdata='xcrun llvm-profdata' llvm-cov='xcrun llvm-cov'; fi
+
+        python -m coverage combine $(find . -name '.coverage.*')
+
+        llvm-profdata merge pid-*.profraw -o coverage.profdata
+        llvm-cov show $(grep -Rl LLVM_PROFILE_FILE . | sed 's/^/-object /') -instr-profile=coverage.profdata > coverage.txt
+        bash <(curl -s https://codecov.io/bash)
+
   makepanda:
     strategy:
       matrix:

+ 152 - 0
CMakeLists.txt

@@ -0,0 +1,152 @@
+cmake_minimum_required(VERSION 3.0.2)
+set(CMAKE_DISABLE_SOURCE_CHANGES ON) # Must go before project() below
+set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) # Must go before project() below
+
+if(CMAKE_VERSION VERSION_GREATER "3.11" OR POLICY CMP0072)
+  # Prefer GLVND over libGL when available; this will be enabled by default
+  # once the minimum CMake version is at least 3.11.
+  cmake_policy(SET CMP0072 NEW)
+endif()
+
+if(CMAKE_VERSION VERSION_GREATER "3.12" OR POLICY CMP0074)
+  # Needed for THIRDPARTY_DIRECTORY support; this will be enabled by default
+  # once the minimum CMake version is at least 3.12.
+  cmake_policy(SET CMP0074 NEW)
+endif()
+
+# Figure out the version
+set(_s "[\\t ]*") # CMake doesn't support \s*
+file(STRINGS "setup.cfg" _version REGEX "^version${_s}=${_s}")
+string(REGEX REPLACE "^.*=${_s}" "" _version "${_version}")
+project(Panda3D VERSION ${_version})
+unset(_version)
+unset(_s)
+
+enable_testing()
+
+string(REPLACE "$(EFFECTIVE_PLATFORM_NAME)" "" PANDA_CFG_INTDIR "${CMAKE_CFG_INTDIR}")
+
+# Add generic modules to cmake module path,
+# and add Panda3D specific modules to cmake module path
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/macros/")
+
+if(CMAKE_VERSION VERSION_GREATER "3.8")
+  # When using the Xcode generator, don't append the platform name to the
+  # intermediate configuration directory.
+  set_property(GLOBAL PROPERTY XCODE_EMIT_EFFECTIVE_PLATFORM_NAME OFF)
+endif()
+
+# Include modules builtin to CMake
+include(GNUInstallDirs)     # Defines CMAKE_INSTALL_<dir> variables
+
+# Include global modules needed for configure scripts
+include(PackageConfig)      # Defines package_option
+
+# Configure Panda3D
+include(dtool/CompilerFlags.cmake)
+include(dtool/PandaVersion.cmake)
+include(dtool/Package.cmake)
+include(dtool/Config.cmake)
+
+# Include global modules
+include(AddBisonTarget)     # Defines add_bison_target function
+include(AddFlexTarget)      # Defines add_flex_target function
+include(BuildMetalib)       # Defines add_component_library AND add_metalib
+include(CompositeSources)   # Defines composite_sources function
+include(Python)             # Defines add_python_target AND install_python_package
+include(Interrogate)        # Defines target_interrogate AND add_python_module
+include(RunPzip)            # Defines run_pzip function
+include(Versioning)         # Hooks 'add_library' to apply VERSION/SOVERSION
+
+# Determine which trees to build.
+option(BUILD_DTOOL "Build the dtool source tree." ON)
+option(BUILD_PANDA "Build the panda source tree." ON)
+option(BUILD_DIRECT "Build the direct source tree." ON)
+option(BUILD_PANDATOOL "Build the pandatool source tree." ON)
+option(BUILD_CONTRIB "Build the contrib source tree." ON)
+option(BUILD_MODELS "Build/install the built-in models." ON)
+
+# Include Panda3D packages
+if(BUILD_DTOOL)
+  add_subdirectory(dtool "${CMAKE_BINARY_DIR}/dtool")
+endif()
+
+if(BUILD_PANDA)
+  add_subdirectory(panda "${CMAKE_BINARY_DIR}/panda")
+endif()
+
+if(BUILD_DIRECT)
+  add_subdirectory(direct "${CMAKE_BINARY_DIR}/direct")
+endif()
+
+if(BUILD_PANDATOOL)
+  add_subdirectory(pandatool "${CMAKE_BINARY_DIR}/pandatool")
+endif()
+
+if(BUILD_CONTRIB)
+  add_subdirectory(contrib "${CMAKE_BINARY_DIR}/contrib")
+endif()
+
+if(BUILD_MODELS)
+  run_pzip(models
+    "${CMAKE_CURRENT_SOURCE_DIR}/models/"
+    "${PROJECT_BINARY_DIR}/${PANDA_CFG_INTDIR}/models"
+    *.egg)
+  run_pzip(dmodels
+    "${CMAKE_CURRENT_SOURCE_DIR}/dmodels/src/"
+    "${PROJECT_BINARY_DIR}/${PANDA_CFG_INTDIR}/models"
+    *.egg)
+
+  add_custom_command(TARGET models
+                     POST_BUILD
+                     COMMAND ${CMAKE_COMMAND}
+                             -DSOURCE="${CMAKE_CURRENT_SOURCE_DIR}/models/maps/"
+                             -DDESTINATION="${PANDA_OUTPUT_DIR}/models/maps"
+                             -P ${PROJECT_SOURCE_DIR}/cmake/scripts/CopyPattern.cmake
+                     COMMENT "Copying models/maps")
+  add_custom_command(TARGET dmodels
+                     POST_BUILD
+                     COMMAND ${CMAKE_COMMAND}
+                             -DSOURCE="${CMAKE_CURRENT_SOURCE_DIR}/dmodels/src/"
+                             -DDESTINATION="${PANDA_OUTPUT_DIR}/models"
+                             -DFILES_MATCHING="PATTERN;*.rgb;PATTERN;*.png;PATTERN;*.jpg;PATTERN;*.wav"
+                             -P ${PROJECT_SOURCE_DIR}/cmake/scripts/CopyPattern.cmake
+                     COMMENT "Copying dmodels' assets")
+
+  install(DIRECTORY "${PANDA_OUTPUT_DIR}/models"
+    COMPONENT Models DESTINATION ${CMAKE_INSTALL_DATADIR}/panda3d)
+endif()
+
+if(INTERROGATE_PYTHON_INTERFACE)
+  # If we built the Python interface, run the test suite.  Note, we do NOT test
+  # for pytest before adding this test.  If the user doesn't have pytest, we'd
+  # like for the tests to fail.
+
+  # In the Coverage configuration, we also require pytest-cov
+
+  add_test(NAME pytest
+    COMMAND "${PYTHON_EXECUTABLE}" -m pytest "${PROJECT_SOURCE_DIR}/tests"
+    $<$<CONFIG:Coverage>:--cov=.>
+    WORKING_DIRECTORY "${PANDA_OUTPUT_DIR}")
+endif()
+
+# Generate the Panda3DConfig.cmake file so find_package(Panda3D) works, and
+# also register the build directory with CMake's package registry.
+
+file(COPY "${PROJECT_SOURCE_DIR}/cmake/install/Panda3DConfig.cmake"
+  DESTINATION "${PROJECT_BINARY_DIR}")
+install(FILES "${PROJECT_SOURCE_DIR}/cmake/install/Panda3DConfig.cmake"
+  DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Panda3D")
+
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file(
+  "${PROJECT_BINARY_DIR}/Panda3DConfigVersion.cmake"
+  VERSION "${PROJECT_VERSION}"
+  COMPATIBILITY AnyNewerVersion)
+install(FILES "${PROJECT_BINARY_DIR}/Panda3DConfigVersion.cmake"
+  DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Panda3D")
+
+if(NOT CMAKE_CROSSCOMPILING)
+  export(PACKAGE Panda3D)
+endif()

+ 78 - 0
cmake/README.md

@@ -0,0 +1,78 @@
+Building with CMake
+-------------------
+
+On Windows and macOS, please ensure that you have the very latest version of
+CMake installed; older versions may work, but if not, please upgrade to the
+latest available version of CMake before requesting help.
+
+On systems that package CMake themselves (e.g. Linux distributions), we most
+likely support the provided version of CMake as long as the system itself is
+supported.
+
+CMake will also require that you already have your system's developer tools
+installed.
+
+The quickest way to build and install Panda with CMake is to install any
+third-party dependencies and then run:
+```sh
+mkdir build && cd build
+cmake ..
+cmake --build . --config Standard --parallel 4
+[sudo] cmake --build . --config Standard --target install
+```
+
+Note that, if you are targeting 64-bit on Windows, it is necessary to supply
+the `-A x64` option when first invoking `cmake` (as `cmake -A x64 ..`).
+
+CMake itself does not build Panda; rather, it generates project files for an
+existing IDE or build tool. To select a build tool, pass the `-G` option when
+first invoking CMake, (`cmake -G Ninja ..` is highly recommended on Linux).
+Some of these (Xcode, Visual Studio) support targeting multiple configurations
+(the `--config Standard`, above, selects the `Standard` configuration in those
+cases). Other build tools (Ninja, Makefiles, ...) do not support multiple
+configurations, and the `--config` option is ignored. To change the
+configuration in these cases (from `Standard`, the default), it is necessary to
+change the `CMAKE_BUILD_TYPE` variable as explained below.
+
+The configurations are:
+
+| Configuration  | Explanation                                            |
+| -------------- | ------------------------------------------------------ |
+| Standard       | Default; build provided to users of SDK                |
+| Release        | Distribution for end-users                             |
+| MinSizeRel     | Like Release, but optimized for size                   |
+| RelWithDebInfo | Like Release, but include debug symbols                |
+| Debug          | Do not optimize, enable optional debugging features    |
+| Coverage       | Like Debug, but profile code coverage; developers only |
+
+To configure CMake, it is recommended to use cmake-gui (`cmake-gui .`),
+or ccmake (`ccmake .`), however it is also possible to configure it entirely
+through CMake's command-line interface; see `man cmake` for more details.
+
+In general, the config variable for a particular third party library is:
+```
+	HAVE_<LIBRARY>=YES/NO   # Example: USE_JPEG
+```
+Panda subpackage building is handled by:
+```
+	BUILD_<SUBPACKAGE>=YES/NO   # Example: BUILD_DTOOL, BUILD_PANDA
+```
+Other configuration settings use their historical names (same names as in-source):
+```
+	# Examples
+	PANDA_DISTRIBUTOR="MyDistributor"
+	LINMATH_ALIGN=YES
+
+	# ... etc ...
+
+```
+
+For example, `makepanda.py --distributor X` becomes `cmake -DPANDA_DISTRIBUTOR=X`
+
+All found third-party libraries are enabled by default, and makepanda-style
+tools packages are searched in the same path as makepanda (however this may be
+overridden with the `THIRDPARTY_DIRECTORY` option).
+
+Most config settings are set to a sensible default for a typical PC/desktop
+Panda3D distribution. Third-party libraries and other settings can be enabled
+or disabled through configuration with the cmake GUI or CLI.

+ 157 - 0
cmake/install/Panda3DConfig.cmake

@@ -0,0 +1,157 @@
+# 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."
+#
+# Author: CFSworks (Dec. 11, 2018)
+
+# This file is installed to CMake's package search path, and is invoked for
+# find_package(Panda3D [COMPONENTS ...])
+#
+# The following components are available for importing:
+#
+#   Core      - The core Panda3D libraries; this component is always included.
+#
+#               Panda3D::Core::panda
+#               Panda3D::Core::pandaexpress
+#               etc.
+#
+#
+#   Python    - Python targets, which can be used for linking against the Python
+#               extension modules directly.  Note that this also imports the
+#               Python bindings for other requested components that have them.
+#
+#               Panda3D::Python::panda3d.core
+#               Panda3D::Python::panda3d.physics
+#               etc.
+#
+#
+#   Tools     - Various tools used in asset manipulation and debugging.
+#
+#               Panda3D::Tools::egg2bam
+#               Panda3D::Tools::egg-optchar
+#               Panda3D::Tools::pview
+#               etc.
+#
+#
+#   Direct    - Panda's "direct" Python framework; C++ support library.
+#
+#               Panda3D::Direct::p3direct
+#
+#
+#   Contrib   - Extensions not part of the Panda3D core, but contributed by the
+#               community.
+#
+#               Panda3D::Contrib::p3ai
+#               Panda3D::Contrib::p3rplight
+#
+#
+#   Framework - Panda's "p3framework" C++ framework.
+#
+#               Panda3D::Framework::p3framework
+#
+#
+#   Egg       - Support for the Egg file format.
+#
+#               Panda3D::Egg::pandaegg
+#
+#
+#   Bullet    - Support for Bullet physics.
+#
+#               Panda3D::Bullet::p3bullet
+#
+#
+#   ODE       - Support for the ODE physics engine.
+#
+#               Panda3D::ODE::p3ode
+#
+#
+#   FFmpeg    - Support for FFmpeg media format loading.
+#
+#               Panda3D::FFmpeg::p3ffmpeg
+#
+#
+#   OpenAL    - Support for OpenAL audio output.
+#
+#               Panda3D::OpenAL::p3openal_audio
+#
+#
+#   FMOD      - Support for FMOD audio output.
+#
+#               Panda3D::FMOD::p3fmod_audio
+#
+#
+#   OpenGL    - Support for OpenGL rendering.
+#
+#               Panda3D::OpenGL::pandagl
+#
+#
+#   DX9       - Support for Direct3D 9 rendering.
+#
+#               Panda3D::DX9::pandadx9
+#
+#
+#   OpenGLES1 - Support for OpenGL ES 1.x rendering.
+#
+#               Panda3D::OpenGLES1::pandagles
+#
+#
+#   OpenGLES2 - Support for OpenGL ES 2.x+ rendering.
+#
+#               Panda3D::OpenGLES2::pandagles2
+#
+#
+#   Vision    - Support for vision processing.
+#
+#               Panda3D::Vision::p3vision
+#
+#
+#   VRPN      - Support for connecting to a VRPN virtual reality server.
+#
+#               Panda3D::VRPN::p3vrpn
+
+if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 3.0)
+  message(FATAL_ERROR "CMake >= 3.0.2 required")
+endif()
+
+get_filename_component(_panda_config_prefix "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+include("${_panda_config_prefix}/Panda3DPackages.cmake")
+
+set(_panda_components
+  Core Python Tools
+  Direct Contrib Framework Egg
+  Bullet ODE
+  FFmpeg
+  OpenAL FMOD
+  OpenGL DX9 OpenGLES1 OpenGLES2
+  Vision VRPN
+)
+
+set(Panda3D_FIND_REQUIRED_Core ON)
+
+foreach(_comp Core ${Panda3D_FIND_COMPONENTS})
+  if(";${_panda_components};" MATCHES ";${_comp};" AND
+     EXISTS "${_panda_config_prefix}/Panda3D${_comp}Targets.cmake")
+
+    include("${_panda_config_prefix}/Panda3D${_comp}Targets.cmake")
+
+    if(";${Panda3D_FIND_COMPONENTS};" MATCHES ";Python;" AND
+       EXISTS "${_panda_config_prefix}/Panda3D${_comp}PythonTargets.cmake")
+
+      include("${_panda_config_prefix}/Panda3D${_comp}PythonTargets.cmake")
+
+    endif()
+
+  elseif(Panda3D_FIND_REQUIRED_${_comp})
+
+    message(FATAL_ERROR "Panda3D REQUIRED component ${_comp} not found")
+
+  endif()
+
+endforeach(_comp)
+unset(_comp)
+
+unset(_panda_components)

+ 75 - 0
cmake/macros/AddBisonTarget.cmake

@@ -0,0 +1,75 @@
+# Filename: AddBisonTarget.cmake
+# Description: This file defines the function add_bison_target which instructs
+#   cmake to use bison on an input .yxx file.  If bison is not available on
+#   the system, add_bison_target tries to use .prebuilt .cxx files instead.
+#
+# Usage:
+#   add_bison_target(output_cxx input_yxx [DEFINES output_h] [PREFIX prefix])
+#
+
+# Define add_bison_target()
+function(add_bison_target output_cxx input_yxx)
+  set(arguments "")
+  set(outputs "${output_cxx}")
+  set(keyword "")
+
+  # Parse the extra arguments to the function.
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "DEFINES")
+      set(keyword "DEFINES")
+
+    elseif(arg STREQUAL "PREFIX")
+      set(keyword "PREFIX")
+
+    elseif(keyword STREQUAL "PREFIX")
+      list(APPEND arguments -p "${arg}")
+
+    elseif(keyword STREQUAL "DEFINES")
+      list(APPEND arguments --defines="${arg}")
+      list(APPEND outputs "${arg}")
+
+    else()
+      message(SEND_ERROR "Unexpected argument ${arg} to add_bison_target")
+
+    endif()
+  endforeach()
+
+  if(keyword STREQUAL arg AND NOT keyword STREQUAL "")
+    message(SEND_ERROR "Expected argument after ${keyword}")
+  endif()
+
+  if(HAVE_BISON)
+    get_source_file_property(input_yxx "${input_yxx}" LOCATION)
+
+    # If we have bison, we can of course just run it.
+    add_custom_command(
+      OUTPUT ${outputs}
+      COMMAND ${BISON_EXECUTABLE}
+        -o "${output_cxx}" ${arguments}
+        "${input_yxx}"
+      MAIN_DEPENDENCY "${input_yxx}"
+    )
+
+  else()
+    # Look for prebuilt versions of the outputs.
+    set(commands "")
+    set(depends "")
+
+    foreach(output ${outputs})
+      set(prebuilt_file "${output}.prebuilt")
+      get_filename_component(prebuilt_file "${prebuilt_file}" ABSOLUTE)
+
+      if(NOT EXISTS "${prebuilt_file}")
+        message(SEND_ERROR "Bison was not found and ${prebuilt_file} does not exist!")
+      endif()
+
+      list(APPEND depends "${prebuilt_file}")
+      list(APPEND commands COMMAND ${CMAKE_COMMAND} -E copy ${prebuilt_file} ${output})
+    endforeach()
+
+    add_custom_command(
+      OUTPUT ${outputs}
+      ${commands}
+      DEPENDS ${depends})
+  endif()
+endfunction(add_bison_target)

+ 77 - 0
cmake/macros/AddFlexTarget.cmake

@@ -0,0 +1,77 @@
+# Filename: AddFlexTarget.cmake
+# Description: This file defines the function add_flex_target which instructs
+#   cmake to use flex on an input .lxx file.  If flex is not available on
+#   the system, add_flex_target tries to use .prebuilt .cxx files instead.
+#
+# Usage:
+#   add_flex_target(output_cxx input_lxx [DEFINES output_h] [PREFIX prefix])
+#
+
+# Define add_flex_target()
+function(add_flex_target output_cxx input_lxx)
+  set(arguments "")
+  set(outputs "${output_cxx}")
+  set(keyword "")
+
+  # Parse the extra arguments to the function.
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "DEFINES")
+      set(keyword "DEFINES")
+
+    elseif(arg STREQUAL "PREFIX")
+      set(keyword "PREFIX")
+
+    elseif(arg STREQUAL "CASE_INSENSITIVE")
+      list(APPEND arguments "-i")
+
+    elseif(keyword STREQUAL "PREFIX")
+      list(APPEND arguments "-P${arg}")
+
+    elseif(keyword STREQUAL "DEFINES")
+      list(APPEND arguments "--header-file=${arg}")
+      list(APPEND outputs "${arg}")
+
+    else()
+      message(SEND_ERROR "Unexpected argument ${arg} to add_flex_target")
+
+    endif()
+  endforeach()
+
+  if(keyword STREQUAL arg AND NOT keyword STREQUAL "")
+    message(SEND_ERROR "Expected argument after ${keyword}")
+  endif()
+
+  if(HAVE_FLEX)
+    get_source_file_property(input_lxx "${input_lxx}" LOCATION)
+
+    # If we have flex, we can of course just run it.
+    add_custom_command(
+      OUTPUT ${outputs}
+      COMMAND ${FLEX_EXECUTABLE}
+        "-o${output_cxx}" ${arguments}
+        "${input_lxx}"
+      MAIN_DEPENDENCY "${input_lxx}")
+
+  else()
+    # Look for prebuilt versions of the outputs.
+    set(commands "")
+    set(depends "")
+
+    foreach(output ${outputs})
+      set(prebuilt_file "${output}.prebuilt")
+      get_filename_component(prebuilt_file "${prebuilt_file}" ABSOLUTE)
+
+      if(NOT EXISTS "${prebuilt_file}")
+        message(SEND_ERROR "Flex was not found and ${prebuilt_file} does not exist!")
+      endif()
+
+      list(APPEND depends "${prebuilt_file}")
+      list(APPEND commands COMMAND ${CMAKE_COMMAND} -E copy ${prebuilt_file} ${output})
+    endforeach()
+
+    add_custom_command(
+      OUTPUT ${outputs}
+      ${commands}
+      DEPENDS ${depends})
+  endif()
+endfunction(add_flex_target)

+ 426 - 0
cmake/macros/BuildMetalib.cmake

@@ -0,0 +1,426 @@
+# Filename: BuildMetalib.cmake
+#
+# Description: This file contains macros to build Panda3D's "metalibs" - these
+#   are special libraries that contain no unique code themselves and are
+#   instead just an agglomeration of the various component libraries that get
+#   linked into them. A library of libraries - a "metalibrary."
+
+#
+# Function: target_link_libraries(...)
+#
+# Overrides CMake's target_link_libraries() to support "linking" object
+# libraries. This is a partial reimplementation of CMake commit dc38970f83,
+# which is only available in CMake 3.12+
+#
+if(CMAKE_VERSION VERSION_LESS "3.12")
+  function(target_link_libraries target)
+    get_target_property(target_type "${target}" TYPE)
+    if(NOT target_type STREQUAL "OBJECT_LIBRARY")
+      _target_link_libraries("${target}" ${ARGN})
+      return()
+    endif()
+
+    foreach(library ${ARGN})
+      # This is a quick and dirty regex to tell targets apart from other stuff.
+      # It just checks if it's alphanumeric and starts with p3/panda.
+      if(library MATCHES "^(PKG::|p3|panda)[A-Za-z0-9]*$")
+        # We need to add "library"'s include directories to "target"
+        # (and transitively to INTERFACE_INCLUDE_DIRECTORIES so further
+        # dependencies will work)
+        set(include_directories "$<TARGET_PROPERTY:${library},INTERFACE_INCLUDE_DIRECTORIES>")
+        set_property(TARGET "${target}" APPEND PROPERTY INCLUDE_DIRECTORIES "${include_directories}")
+        set_property(TARGET "${target}" APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${include_directories}")
+
+        # SYSTEM include directories should still be reported as SYSTEM, so
+        # that warnings from those includes are suppressed
+        set(sys_include_directories
+          "$<TARGET_PROPERTY:${library},INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>")
+        target_include_directories("${target}" SYSTEM PUBLIC "${sys_include_directories}")
+
+        # And for INTERFACE_COMPILE_DEFINITIONS as well
+        set(compile_definitions "$<TARGET_PROPERTY:${library},INTERFACE_COMPILE_DEFINITIONS>")
+        set_property(TARGET "${target}" APPEND PROPERTY COMPILE_DEFINITIONS "${compile_definitions}")
+        set_property(TARGET "${target}" APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS "${compile_definitions}")
+
+        # Build up some generator expressions for determining whether `library`
+        # is a component library or not.
+        if(library MATCHES ".*::.*")
+          # "::" messes up CMake's genex parser; fortunately, a library whose
+          # name contains that is either an interface library or alias, and
+          # definitely not a component
+          set(is_component 0)
+          set(name_of_component "")
+          set(name_of_non_component "${library}")
+
+        else()
+          set(is_component "$<TARGET_PROPERTY:${library},IS_COMPONENT>")
+
+          # CMake complains if we lookup IS_COMPONENT on an INTERFACE library :(
+          set(is_object "$<STREQUAL:$<TARGET_PROPERTY:${library},TYPE>,OBJECT_LIBRARY>")
+          set(is_component "$<BOOL:$<${is_object}:${is_component}>>")
+
+          set(name_of_component "$<${is_component}:$<TARGET_NAME:${library}>>")
+          set(name_of_non_component "$<$<NOT:${is_component}>:$<TARGET_NAME:${library}>>")
+
+        endif()
+
+        # Libraries are only linked transitively if they aren't components.
+        set_property(TARGET "${target}" APPEND PROPERTY
+          INTERFACE_LINK_LIBRARIES "${name_of_non_component}")
+
+      else()
+        # This is a file path to an out-of-tree library - this needs to be
+        # recorded so that the metalib can link them. (They aren't needed at
+        # all for the object libraries themselves, so they don't have to work
+        # transitively.)
+        set_property(TARGET "${target}" APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${library}")
+
+      endif()
+
+    endforeach(library)
+
+  endfunction(target_link_libraries)
+endif()
+
+#
+# Function: add_component_library(target [SYMBOL building_symbol]
+#                                 [SOURCES] [[NOINIT]/[INIT func [header]]])
+#
+# Used very similarly to add_library.  You can specify a symbol with SYMBOL,
+# which works like CMake's own DEFINE_SYMBOL property: it's defined when
+# building the library, but not when building something that links against the
+# library.
+#
+# INIT specifies the init function that should be called from a metalib's init
+# function when this is added to a metalib.  The header parameter can further
+# clarify what header declares this function.  By default, this is
+# init_libTARGET and config_TARGET.h, respectively, where TARGET is the
+# target name (with 'p3' stripped off, if applicable).  The NOINIT keyword
+# suppresses this default.
+#
+# Note that this function gets to decide whether the component library is
+# OBJECT or SHARED, and whether the library is installed or not.  Also, as
+# a rule, component libraries may only be linked by other component libraries
+# in the same metalib - outside of the metalib, you must link the metalib
+# itself.
+#
+function(add_component_library target_name)
+  set(sources)
+  unset(symbol)
+
+  if(target_name MATCHES "^p3.*")
+    string(SUBSTRING "${target_name}" 2 -1 name_without_prefix)
+
+  else()
+    set(name_without_prefix "${target_name}")
+
+  endif()
+
+  set(init_func "init_lib${name_without_prefix}")
+  set(init_header "config_${name_without_prefix}.h")
+
+  set(symbol_keyword OFF)
+  set(init_keyword 0)
+  foreach(source ${ARGN})
+    if(source STREQUAL "SYMBOL")
+      set(symbol_keyword ON)
+      set(init_keyword 0)
+
+    elseif(source STREQUAL "INIT")
+      set(symbol_keyword OFF)
+      set(init_keyword 2)
+
+    elseif(source STREQUAL "NOINIT")
+      set(init_func)
+      set(init_header)
+
+    elseif(symbol_keyword)
+      set(symbol_keyword OFF)
+      set(symbol "${source}")
+
+    elseif(init_keyword EQUAL 2)
+      set(init_func "${source}")
+      set(init_keyword 1)
+
+    elseif(init_keyword EQUAL 1)
+      set(init_header "${source}")
+      set(init_keyword 0)
+
+    else()
+      list(APPEND sources "${source}")
+
+    endif()
+  endforeach()
+
+  if(BUILD_METALIBS)
+    # CMake 3.0.2 doesn't like .I/.N/.T files!  We let it know that they're only
+    # headers.
+    foreach(source ${sources})
+      if(source MATCHES "\\.[INT]$")
+        set_source_files_properties(${source} PROPERTIES HEADER_FILE_ONLY ON)
+      endif()
+    endforeach(source)
+
+    add_library("${target_name}" OBJECT ${sources})
+
+  else()
+    add_library("${target_name}" ${sources})
+
+  endif()
+
+  set_target_properties("${target_name}" PROPERTIES 
+    IS_COMPONENT ON
+    INIT_FUNCTION "${init_func}"
+    INIT_HEADER "${init_header}")
+
+  if(symbol)
+    set_property(TARGET "${target_name}" PROPERTY DEFINE_SYMBOL "${symbol}")
+
+    if(BUILD_METALIBS)
+      # ... DEFINE_SYMBOL is apparently not respected for object libraries?
+      set_property(TARGET "${target_name}" APPEND PROPERTY COMPILE_DEFINITIONS "${symbol}")
+
+      # Make sure other component libraries relying on this one inherit the
+      # symbol
+      set_property(TARGET "${target_name}" APPEND PROPERTY
+        INTERFACE_COMPILE_DEFINITIONS "$<$<BOOL:$<TARGET_PROPERTY:IS_COMPONENT>>:${symbol}>")
+    endif()
+  endif()
+
+  if(BUILD_METALIBS)
+    # Apparently neither is CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE?
+    set_property(TARGET "${target_name}" PROPERTY
+      INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}")
+
+    # If we're building dynamic libraries, the object library needs to be -fPIC
+    if(BUILD_SHARED_LIBS)
+      set_property(TARGET "${target_name}" PROPERTY
+        POSITION_INDEPENDENT_CODE ON)
+    endif()
+  endif()
+
+endfunction(add_component_library)
+
+#
+# Function: add_metalib(target [source1 source2]
+#                       [INCLUDE header1.h ...]
+#                       [INIT initfunc [initheader.h] [EXPORT type name expr]]
+#                       [COMPONENTS component1 ...])
+#
+# This is add_library, but for metalibs.
+#
+# The INIT keyword can specify an initialization function/header (which will be
+# autogenerated by this function) that calls the underlying component libs'
+# init functions.
+#
+# The EXPORT keyword exports the expression `expr`, which yields a value of
+# type `type`, as the undecorated (extern "C") symbol `name`
+#
+# The INCLUDE keyword allows the init file to pull in additional headers, which
+# may be useful for EXPORT.
+#
+function(add_metalib target_name)
+  set(components_keyword OFF)
+  set(init_keyword 0)
+  set(init_func)
+  set(init_header "${target_name}.h")
+  set(export_keyword 0)
+  set(export_declarations)
+  set(export_definitions)
+  set(component_init_headers)
+  set(components)
+  set(sources)
+
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "COMPONENTS")
+      set(components_keyword ON)
+      set(include_keyword OFF)
+      set(init_keyword 0)
+      set(export_keyword 0)
+
+    elseif(arg STREQUAL "INCLUDE")
+      set(include_keyword ON)
+      set(components_keyword OFF)
+      set(init_keyword 0)
+      set(export_keyword 0)
+
+    elseif(arg STREQUAL "INIT")
+      set(init_keyword 2)
+      set(components_keyword OFF)
+      set(include_keyword OFF)
+      set(export_keyword 0)
+
+    elseif(arg STREQUAL "EXPORT")
+      if(NOT init_func)
+        message(FATAL_ERROR "EXPORT cannot be used before INIT")
+      endif()
+
+      set(export_keyword 3)
+      set(components_keyword OFF)
+      set(include_keyword OFF)
+      set(init_keyword 0)
+
+    elseif(components_keyword)
+      list(APPEND components "${arg}")
+
+    elseif(include_keyword)
+      set(component_init_headers
+        "${component_init_headers}#include \"${arg}\"\n")
+
+    elseif(init_keyword EQUAL 2)
+      set(init_func "${arg}")
+      set(init_keyword 1)
+
+    elseif(init_keyword EQUAL 1)
+      set(init_header "${arg}")
+      set(init_keyword 0)
+
+    elseif(export_keyword EQUAL 3)
+      set(_export_type "${arg}")
+      set(export_keyword 2)
+
+    elseif(export_keyword EQUAL 2)
+      set(_export_name "${arg}")
+      set(export_keyword 1)
+
+    elseif(export_keyword EQUAL 1)
+      set(export_declarations
+        "${export_declarations}\nextern \"C\" IMPORT_CLASS ${_export_type} ${_export_name}();")
+      set(export_definitions
+        "${export_definitions}\nextern \"C\" EXPORT_CLASS ${_export_type} ${_export_name}() { return ${arg}; }")
+      unset(_export_type)
+      unset(_export_name)
+      set(export_keyword 0)
+
+    else()
+      list(APPEND sources "${arg}")
+
+    endif()
+  endforeach()
+
+  string(REPLACE ";" "|" piped_components "${components}")
+  set(component_genex_regex ".*TARGET_PROPERTY:(${piped_components}),.*")
+
+  set(private_defines)
+  set(interface_defines)
+  set(includes)
+  set(libs)
+  set(component_init_funcs "")
+  foreach(component ${components})
+    if(NOT TARGET "${component}")
+      message(FATAL_ERROR
+        "Missing component library ${component} referenced by metalib ${target_name}!
+        (Component library targets must be created BEFORE add_metalib.)")
+    endif()
+
+    get_target_property(is_component "${component}" IS_COMPONENT)
+    if(NOT is_component)
+      message(FATAL_ERROR
+        "Attempted to metalink non-component ${component} into ${target_name}!")
+    endif()
+
+    get_target_property(component_init_header "${component}" INIT_HEADER)
+    get_target_property(component_init_func "${component}" INIT_FUNCTION)
+
+    if(component_init_header)
+      set(component_init_headers
+        "${component_init_headers}#include \"${component_init_header}\"\n")
+    endif()
+
+    if(component_init_func)
+      set(component_init_funcs
+        "${component_init_funcs}  ${component_init_func}();\n")
+    endif()
+
+    if(BUILD_METALIBS)
+      # This will be an object library we're pulling in; rather than link,
+      # let's try to "flatten" all of its properties into ours.
+
+      # Private defines: Just reference using a generator expression
+      list(APPEND private_defines "$<TARGET_PROPERTY:${component},COMPILE_DEFINITIONS>")
+
+      # Interface defines: Copy those, but filter out generator expressions
+      # referencing a component library
+      get_target_property(component_defines "${component}" INTERFACE_COMPILE_DEFINITIONS)
+      if(component_defines)
+        foreach(component_define ${component_defines})
+          if(component_define MATCHES "${component_genex_regex}")
+            # Filter, it's a genex referencing one of our components
+          elseif(component_define MATCHES ".*IS_COMPONENT.*")
+            # Filter, it's testing to see if the consumer is a component
+          else()
+            list(APPEND interface_defines ${component_define})
+          endif()
+        endforeach(component_define)
+      endif()
+
+      # Include directories: Filter out anything that references a component
+      # library or anything in the project path
+      get_target_property(component_includes "${component}" INTERFACE_INCLUDE_DIRECTORIES)
+      foreach(component_include ${component_includes})
+        if(component_include MATCHES "${component_genex_regex}")
+          # Ignore component references
+
+        elseif(component_include MATCHES "^${PROJECT_SOURCE_DIR}")
+          # Include path within project; should only be included when building
+          list(APPEND includes "$<BUILD_INTERFACE:${component_include}>")
+
+        else()
+          # Anything else gets included
+          list(APPEND includes "${component_include}")
+
+        endif()
+      endforeach(component_include)
+
+      # Link libraries: Filter out component libraries; we aren't linking
+      # against them, we're using their objects
+      get_target_property(component_libraries "${component}" INTERFACE_LINK_LIBRARIES)
+      foreach(component_library ${component_libraries})
+        if(NOT component_library)
+          # NOTFOUND - guess there are no INTERFACE_LINK_LIBRARIES
+
+        elseif(component_library MATCHES "${component_genex_regex}")
+          # Ignore component references
+
+        elseif(component_library MATCHES ".*(${piped_components}).*")
+          # Component library, ignore
+
+        else()
+          # Anything else gets included
+          list(APPEND libs "${component_library}")
+
+        endif()
+      endforeach(component_library)
+
+      # Consume this component's objects
+      list(APPEND sources "$<TARGET_OBJECTS:${component}>")
+
+    else() # NOT BUILD_METALIBS
+      list(APPEND libs "${component}")
+
+    endif()
+  endforeach()
+
+  if(init_func)
+    set(init_source_path "${CMAKE_CURRENT_BINARY_DIR}/init_${target_name}.cxx")
+    set(init_header_path "${CMAKE_CURRENT_BINARY_DIR}/${init_header}")
+
+    configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/metalib_init.cxx.in"
+      "${init_source_path}")
+    list(APPEND sources "${init_source_path}")
+
+    configure_file("${PROJECT_SOURCE_DIR}/cmake/templates/metalib_init.h.in"
+      "${init_header_path}")
+    install(FILES "${init_header_path}" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+  endif()
+
+  add_library("${target_name}" ${sources})
+  target_compile_definitions("${target_name}"
+    PRIVATE ${private_defines}
+    INTERFACE ${interface_defines})
+  target_link_libraries("${target_name}" ${libs})
+  target_include_directories("${target_name}"
+    PUBLIC ${includes}
+    INTERFACE "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}/panda3d>")
+
+endfunction(add_metalib)

+ 167 - 0
cmake/macros/CompositeSources.cmake

@@ -0,0 +1,167 @@
+# Filename: CompositeSources.cmake
+# Description: This file defines the function composite_sources which looks at
+#   a provided list of sources, generates _compositeN.cxx, and appends the
+#   composites to the list. The original files in the list are marked as headers
+#   so that they will be available in an IDE, but not compiled at build time.
+#
+# Usage:
+#   composite_sources(target source_var)
+#
+# Example:
+#   set(MY_SOURCES a.cxx b.cxx c.cxx)
+#   composite_sources(my_lib MY_SOURCES)
+#   add_library(my_lib ${MY_SOURCES})
+#
+
+
+# Settings for composite builds.  Should be moved to Config.cmake?
+set(CMAKE_UNITY_BUILD "ON" CACHE BOOL
+  "Enable unity builds; Panda defaults this to on.")
+
+set(CMAKE_UNITY_BUILD_BATCH_SIZE "30" CACHE STRING
+  "How many source files to build at a time through the unity build mechanism.
+  A high value will speed up the build dramatically but will be more memory
+  intensive than a low value.")
+
+set(COMPOSITE_SOURCE_EXTENSIONS ".cxx;.mm;.c" CACHE STRING
+  "Only files of these extensions will be composited.")
+
+set(COMPOSITE_SOURCE_EXCLUSIONS "" CACHE STRING
+  "A list of targets to skip when compositing sources. This is mainly
+desirable for CI builds.")
+
+set(COMPOSITE_GENERATOR "${CMAKE_SOURCE_DIR}/cmake/scripts/MakeComposite.cmake")
+
+
+# Define composite_sources()
+function(composite_sources target sources_var)
+  if(NOT CMAKE_VERSION VERSION_LESS "3.16")
+    # CMake 3.16+ implements CMAKE_UNITY_BUILD* natively; no need to continue!
+
+    # Actually - <=3.16.2 has difficulty with multi-language support, so only
+    # allow .cxx in. Hopefully this can be removed soon.
+    foreach(_source ${${sources_var}})
+      get_filename_component(_source_ext "${_source}" EXT)
+      if(NOT _source_ext STREQUAL ".cxx")
+        set_source_files_properties(${_source} PROPERTIES
+          SKIP_UNITY_BUILD_INCLUSION YES)
+      endif()
+    endforeach(_source)
+
+    return()
+  endif()
+
+  if(NOT CMAKE_UNITY_BUILD)
+    # We've been turned off
+    return()
+  endif()
+
+  # How many sources were specified?
+  set(orig_sources ${${sources_var}})
+  set(sources ${orig_sources})
+  list(LENGTH sources num_sources)
+
+  # Don't composite if in the list of exclusions, and don't bother compositing
+  # with too few sources
+  list (FIND COMPOSITE_SOURCE_EXCLUSIONS ${target} _index)
+  if(num_sources LESS 2 OR ${CMAKE_UNITY_BUILD_BATCH_SIZE} LESS 2 OR ${_index} GREATER -1)
+    return()
+  endif()
+
+  # Sort each source file into a list.
+  foreach(source ${sources})
+    get_filename_component(extension "${source}" EXT)
+    get_source_file_property(generated "${source}" GENERATED)
+    get_source_file_property(is_header "${source}" HEADER_FILE_ONLY)
+    get_source_file_property(skip_compositing "${source}" SKIP_UNITY_BUILD_INCLUSION)
+
+    # Check if we can safely add this to a composite file.
+    if(NOT generated AND NOT is_header AND NOT skip_compositing AND
+        ";${COMPOSITE_SOURCE_EXTENSIONS};" MATCHES ";${extension};")
+
+      if(NOT DEFINED sources_${extension})
+        set(sources_${extension})
+      endif()
+
+      # Append it to one of the lists.
+      list(APPEND sources_${extension} "${source}")
+    endif()
+  endforeach(source)
+
+  # Now, put it all into one big list!
+  set(sorted_sources)
+  foreach(extension ${COMPOSITE_SOURCE_EXTENSIONS})
+    if(DEFINED sources_${extension})
+      list(APPEND sorted_sources ${sources_${extension}})
+    endif()
+  endforeach(extension)
+
+  set(composite_files)
+  set(composite_sources)
+
+  # Fill in composite_ext so we can kick off the loop.
+  list(GET sorted_sources 0 first_source)
+  get_filename_component(first_source_ext "${first_source}" EXT)
+  set(composite_ext ${first_source_ext})
+
+  while(num_sources GREATER 0)
+    # Pop the first element and adjust the sorted_sources length accordingly.
+    list(GET sorted_sources 0 source)
+    list(REMOVE_AT sorted_sources 0)
+    list(LENGTH sorted_sources num_sources)
+
+    # Add this file to our composite_sources buffer.
+    list(APPEND composite_sources ${source})
+    list(LENGTH composite_sources num_composite_sources)
+
+    # Get the next source file's extension, so we can see if we're done with
+    # this set of source files.
+    if(num_sources GREATER 0)
+      list(GET sorted_sources 0 next_source)
+      get_filename_component(next_extension "${next_source}" EXT)
+    else()
+      set(next_extension "")
+    endif()
+
+    # Check if this is the point where we should cut the file.
+    if(num_sources EQUAL 0 OR NOT num_composite_sources LESS ${CMAKE_UNITY_BUILD_BATCH_SIZE}
+       OR NOT composite_ext STREQUAL next_extension)
+      # It's pointless to make a composite source from just one file.
+      if(num_composite_sources GREATER 1)
+
+        # Figure out the name of our composite file.
+        list(LENGTH composite_files index)
+        math(EXPR index "1+${index}")
+        set(composite_file "${CMAKE_CURRENT_BINARY_DIR}/${target}_composite${index}${composite_ext}")
+        list(APPEND composite_files "${composite_file}")
+
+        # Set HEADER_FILE_ONLY to prevent it from showing up in the
+        # compiler command, but still show up in the IDE environment.
+        set_source_files_properties(${composite_sources} PROPERTIES HEADER_FILE_ONLY ON)
+
+        # We'll interrogate the composite files, so exclude the original sources.
+        set_source_files_properties(${composite_sources} PROPERTIES WRAP_EXCLUDE YES)
+
+        # Finally, add the target that generates the composite file.
+        add_custom_command(
+          OUTPUT "${composite_file}"
+          COMMAND ${CMAKE_COMMAND}
+            -DCOMPOSITE_FILE="${composite_file}"
+            -DCOMPOSITE_SOURCES="${composite_sources}"
+            -P "${COMPOSITE_GENERATOR}"
+          DEPENDS ${composite_sources})
+      endif()
+
+      # Reset for the next composite file.
+      set(composite_sources "")
+      set(composite_ext ${next_extension})
+    endif()
+  endwhile()
+
+  set_source_files_properties(${composite_files} PROPERTIES GENERATED YES)
+
+  # The new files are added to the existing files, which means the old files
+  # are still there, but they won't be compiled due to the HEADER_FILE_ONLY setting.
+  set(${sources_var} ${orig_sources} ${composite_files} PARENT_SCOPE)
+
+endfunction(composite_sources)

+ 400 - 0
cmake/macros/Interrogate.cmake

@@ -0,0 +1,400 @@
+# Filename: Interrogate.cmake
+#
+# Description: This file contains macros and functions that are used to invoke
+#   interrogate, to generate wrappers for Python and/or other languages.
+#
+# Functions:
+#   target_interrogate(target [ALL] [source1 [source2 ...]])
+#   add_python_module(module [lib1 [lib2 ...]])
+#   add_python_target(target [source1 [source2 ...]])
+#
+
+set(IGATE_FLAGS -DCPPPARSER -D__cplusplus -Dvolatile -Dmutable)
+
+# In addition, Interrogate needs to know if this is a 64-bit build:
+include(CheckTypeSize)
+check_type_size(long CMAKE_SIZEOF_LONG)
+if(CMAKE_SIZEOF_LONG EQUAL 8)
+  list(APPEND IGATE_FLAGS "-D_LP64")
+endif()
+
+
+# This is a list of regexes that are applied to every filename. If one of the
+# regexes matches, that file will not be passed to Interrogate.
+set(INTERROGATE_EXCLUDE_REGEXES
+  ".*\\.I$"
+  ".*\\.N$"
+  ".*\\.c$"
+  ".*\\.lxx$"
+  ".*\\.yxx$"
+  ".*_src\\..*"
+)
+
+if(WIN32)
+  list(APPEND IGATE_FLAGS -D_X86_ -D__STDC__=1 -DWIN32_VC -D "_declspec(param)=" -D "__declspec(param)=" -D_near -D_far -D__near -D__far -D_WIN32 -D__stdcall -DWIN32)
+endif()
+if(MSVC_VERSION)
+  list(APPEND IGATE_FLAGS "-D_MSC_VER=${MSVC_VERSION}")
+endif()
+if(INTERROGATE_VERBOSE)
+  list(APPEND IGATE_FLAGS "-v")
+endif()
+
+set(IMOD_FLAGS -python-native)
+
+# This stores the names of every module added to the Interrogate system:
+set(ALL_INTERROGATE_MODULES CACHE INTERNAL "Internal variable")
+
+#
+# Function: target_interrogate(target [ALL] [source1 [source2 ...]])
+# NB. This doesn't actually invoke interrogate, but merely adds the
+# sources to the list of scan sources associated with the target.
+# Interrogate will be invoked when add_python_module is called.
+# If ALL is specified, all of the sources from the associated
+# target are added.
+#
+function(target_interrogate target)
+  set(sources)
+  set(extensions)
+  set(want_all OFF)
+  set(extensions_keyword OFF)
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "ALL")
+      set(want_all ON)
+
+    elseif(arg STREQUAL "EXTENSIONS")
+      set(extensions_keyword ON)
+
+    elseif(extensions_keyword)
+      list(APPEND extensions "${arg}")
+
+    else()
+      list(APPEND sources "${arg}")
+
+    endif()
+  endforeach()
+
+  # If ALL was specified, pull in all sources from the target.
+  if(want_all)
+    get_target_property(target_sources "${target}" SOURCES)
+    list(APPEND sources ${target_sources})
+  endif()
+
+  list(REMOVE_DUPLICATES sources)
+
+  # Now let's get everything's absolute path, so that it can be passed
+  # through a property while still preserving the reference.
+  set(absolute_sources)
+  foreach(source ${sources})
+    get_source_file_property(exclude "${source}" WRAP_EXCLUDE)
+    if(NOT exclude)
+      get_source_file_property(location "${source}" LOCATION)
+      list(APPEND absolute_sources ${location})
+    endif()
+  endforeach(source)
+
+  set(absolute_extensions)
+  foreach(extension ${extensions})
+    get_source_file_property(location "${extension}" LOCATION)
+    list(APPEND absolute_extensions ${location})
+  endforeach(extension)
+
+  set_target_properties("${target}" PROPERTIES
+    IGATE_SOURCES "${absolute_sources}")
+  set_target_properties("${target}" PROPERTIES
+    IGATE_EXTENSIONS "${absolute_extensions}")
+
+  # CMake has no property for determining the source directory where the
+  # target was originally added. interrogate_sources makes use of this
+  # property (if it is set) in order to make all paths on the command-line
+  # relative to it, thereby shortening the command-line even more.
+  # Since this is not an Interrogate-specific property, it is not named with
+  # an IGATE_ prefix.
+  set_target_properties("${target}" PROPERTIES
+    TARGET_SRCDIR "${CMAKE_CURRENT_SOURCE_DIR}")
+
+  # Also store where the build files are kept, so the Interrogate output can go
+  # there as well.
+  set_target_properties("${target}" PROPERTIES
+    TARGET_BINDIR "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}")
+
+endfunction(target_interrogate)
+
+#
+# Function: interrogate_sources(target output database language_flags module)
+#
+# This function actually runs a component-level interrogation against 'target'.
+# It generates the outfile.cxx (output) and dbfile.in (database) files, which
+# can then be used during the interrogate_module step to produce language
+# bindings.
+#
+# The target must first have had sources selected with target_interrogate.
+# Failure to do so will result in an error.
+#
+function(interrogate_sources target output database language_flags)
+  get_target_property(sources "${target}" IGATE_SOURCES)
+  get_target_property(extensions "${target}" IGATE_EXTENSIONS)
+
+  if(NOT sources)
+    message(FATAL_ERROR
+      "Cannot interrogate ${target} unless it's run through target_interrogate first!")
+  endif()
+
+  get_target_property(srcdir "${target}" TARGET_SRCDIR)
+  if(NOT srcdir)
+    # No TARGET_SRCDIR was set, so we'll do everything relative to our
+    # current binary dir instead:
+    set(srcdir "${CMAKE_CURRENT_BINARY_DIR}")
+  endif()
+
+  set(scan_sources)
+  set(nfiles)
+  foreach(source ${sources})
+    get_filename_component(source_basename "${source}" NAME)
+
+    # Only certain sources should actually be scanned by Interrogate. The
+    # rest are merely dependencies. This uses the exclusion regex above in
+    # order to determine what files are okay:
+    set(exclude OFF)
+    foreach(regex ${INTERROGATE_EXCLUDE_REGEXES})
+      if("${source_basename}" MATCHES "${regex}")
+        set(exclude ON)
+      endif()
+    endforeach(regex)
+
+    if(NOT exclude)
+      # This file is to be scanned by Interrogate. In order to avoid
+      # cluttering up the command line, we should first make it relative:
+      file(RELATIVE_PATH rel_source "${srcdir}" "${source}")
+      list(APPEND scan_sources "${rel_source}")
+
+      # Also see if this file has a .N counterpart, which has directives
+      # specific for Interrogate. If there is a .N file, we add it as a dep,
+      # so that CMake will rerun Interrogate if the .N files are modified:
+      get_filename_component(source_path "${source}" PATH)
+      get_filename_component(source_name_we "${source}" NAME_WE)
+      set(nfile "${source_path}/${source_name_we}.N")
+      if(EXISTS "${nfile}")
+        list(APPEND nfiles "${nfile}")
+      endif()
+    endif()
+  endforeach(source)
+
+  # Also add extensions, in relative-path form
+  foreach(extension ${extensions})
+    file(RELATIVE_PATH rel_extension "${srcdir}" "${extension}")
+    list(APPEND scan_sources "${rel_extension}")
+  endforeach(extension)
+
+  # Interrogate also needs the include paths, so we'll extract them from the
+  # target. These are available via a generator expression.
+
+  # When we read the INTERFACE_INCLUDE_DIRECTORIES property, we need to read it
+  # from a target that has the IS_INTERROGATE=1 property.
+  # (See PackageConfig.cmake for an explanation why.)
+  # The problem is, custom commands are not targets, so we can't put target
+  # properties on them. And if you try to use the $<TARGET_PROPERTY:prop>
+  # generator expression from the context of a custom command, it'll instead
+  # read the property from the most recent actual target. As a workaround for
+  # this, we create a fake target with the IS_INTERROGATE property set and pull
+  # the INTERFACE_INCLUDE_DIRECTORIES property out through that.
+  # I hate it, but such is CMake.
+  add_custom_target(${target}_igate_internal)
+  set_target_properties(${target}_igate_internal PROPERTIES
+    IS_INTERROGATE 1
+    INTERFACE_INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:${target},INTERFACE_INCLUDE_DIRECTORIES>")
+
+  # Note, the \t is a workaround for a CMake bug where using a plain space in
+  # a JOIN will cause it to be escaped. Tabs are not escaped and will
+  # separate correctly.
+  set(include_flags "-I$<JOIN:$<TARGET_PROPERTY:${target}_igate_internal,INTERFACE_INCLUDE_DIRECTORIES>,\t-I>")
+
+  # Get the compiler definition flags. These must be passed to Interrogate
+  # in the same way that they are passed to the compiler so that Interrogate
+  # will preprocess each file in the same way.
+  set(_compile_defs "$<TARGET_PROPERTY:${target},COMPILE_DEFINITIONS>")
+  if(NOT CMAKE_HOST_WIN32)
+    # Win32's command-line parser doesn't understand "'"
+    # that's fine, it also ignores '"'
+    set(_q "'")
+  endif()
+  set(_compile_defs_flags "-D${_q}$<JOIN:${_compile_defs},${_q}\t-D${_q}>${_q}")
+  # We may have just ended up with -D'' if there are no flags; filter that
+  set(define_flags
+    "$<$<NOT:$<STREQUAL:${_compile_defs_flags},-D${_q}${_q}>>:${_compile_defs_flags}>")
+
+  # Some of the definitions may be specified using -D flags in the global
+  # CXX_FLAGS variables; parse those out (this also picks up NDEBUG)
+  set(_configs ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE} "<ALL>")
+  list(REMOVE_DUPLICATES _configs)
+  foreach(_config ${_configs})
+    if(_config STREQUAL "<ALL>")
+      set(flags "${CMAKE_CXX_FLAGS}")
+    else()
+      string(TOUPPER "${_config}" _CONFIG)
+      set(flags "${CMAKE_CXX_FLAGS_${_CONFIG}}")
+    endif()
+
+    # Convert "/D define1" and "-Ddefine2" flags, interspersed with other
+    # compiler nonsense, into a basic "-Ddefine1 -Ddefine2" string
+    string(REGEX MATCHALL "[/-]D[ \t]*[A-Za-z0-9_]+" igate_flags "${flags}")
+    string(REPLACE ";" " " igate_flags "${igate_flags}")
+    string(REPLACE "/D" "-D" igate_flags "${igate_flags}")
+
+    if(_config STREQUAL "<ALL>")
+      list(APPEND define_flags "${igate_flags}")
+    else()
+      list(APPEND define_flags "$<$<CONFIG:${_config}>:${igate_flags}>")
+    endif()
+  endforeach(_config)
+
+  get_filename_component(output_directory "${output}" DIRECTORY)
+  get_filename_component(database_directory "${database}" DIRECTORY)
+
+  add_custom_command(
+    OUTPUT "${output}" "${database}"
+    COMMAND ${CMAKE_COMMAND} -E
+      make_directory "${output_directory}"
+    COMMAND ${CMAKE_COMMAND} -E
+      make_directory "${database_directory}"
+    COMMAND host_interrogate
+      -oc "${output}"
+      -od "${database}"
+      -srcdir "${srcdir}"
+      -library ${target}
+      ${INTERROGATE_OPTIONS}
+      ${IGATE_FLAGS}
+      ${language_flags}
+      ${define_flags}
+      -S "${PROJECT_SOURCE_DIR}/dtool/src/interrogatedb"
+      -S "${PROJECT_SOURCE_DIR}/dtool/src/parser-inc"
+      -S "${PYTHON_INCLUDE_DIRS}"
+      ${include_flags}
+      ${scan_sources}
+
+    DEPENDS host_interrogate ${sources} ${extensions} ${nfiles}
+    COMMENT "Interrogating ${target}")
+
+  # Propagate the target's compile definitions to the output file
+  set_source_files_properties("${output}" PROPERTIES
+    COMPILE_DEFINITIONS "$<TARGET_PROPERTY:${target},INTERFACE_COMPILE_DEFINITIONS>")
+
+endfunction(interrogate_sources)
+
+#
+# Function: add_python_module(module [lib1 [lib2 ...]] [LINK lib1 ...]
+#    [IMPORT mod1 ...])
+# Uses interrogate to create a Python module. If the LINK keyword is specified,
+# the Python module is linked against the specified libraries instead of those
+# listed before. The IMPORT keyword makes the output module import another
+# Python module when it's initialized.
+#
+function(add_python_module module)
+  if(NOT INTERROGATE_PYTHON_INTERFACE)
+    return()
+  endif()
+
+  set(targets)
+  set(component "Python")
+  set(link_targets)
+  set(import_flags)
+  set(infiles_rel)
+  set(infiles_abs)
+  set(sources_abs)
+  set(extensions)
+
+  set(keyword)
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "LINK" OR arg STREQUAL "IMPORT" OR arg STREQUAL "COMPONENT")
+      set(keyword "${arg}")
+
+    elseif(keyword STREQUAL "LINK")
+      list(APPEND link_targets "${arg}")
+      set(keyword)
+
+    elseif(keyword STREQUAL "IMPORT")
+      list(APPEND import_flags "-import" "${arg}")
+      set(keyword)
+
+    elseif(keyword STREQUAL "COMPONENT")
+      set(component "${arg}")
+      set(keyword)
+
+    else()
+      list(APPEND targets "${arg}")
+
+    endif()
+  endforeach(arg)
+
+  if(NOT link_targets)
+    set(link_targets ${targets})
+  endif()
+
+  string(REGEX REPLACE "^.*\\." "" modname "${module}")
+
+  foreach(target ${targets})
+    get_target_property(workdir_abs "${target}" TARGET_BINDIR)
+    if(NOT workdir_abs)
+      # No TARGET_BINDIR was set, so we'll just use our current directory:
+      set(workdir_abs "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}")
+    endif()
+    # Keep command lines short
+    file(RELATIVE_PATH workdir_rel "${CMAKE_CURRENT_BINARY_DIR}" "${workdir_abs}")
+
+    interrogate_sources(${target}
+      "${workdir_abs}/${target}_igate.cxx"
+      "${workdir_abs}/${target}.in"
+      "-python-native;-module;${module}")
+
+    get_target_property(target_extensions "${target}" IGATE_EXTENSIONS)
+    list(APPEND infiles_rel "${workdir_rel}/${target}.in")
+    list(APPEND infiles_abs "${workdir_abs}/${target}.in")
+    list(APPEND sources_abs "${workdir_abs}/${target}_igate.cxx")
+    list(APPEND extensions ${target_extensions})
+  endforeach(target)
+
+  add_custom_command(
+    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}/${module}_module.cxx"
+    COMMAND ${CMAKE_COMMAND} -E
+      make_directory "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}"
+    COMMAND host_interrogate_module
+      -oc "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}/${module}_module.cxx"
+      -module ${modname} -library ${modname}
+      ${import_flags}
+      ${INTERROGATE_MODULE_OPTIONS}
+      ${IMOD_FLAGS} ${infiles_rel}
+    DEPENDS host_interrogate_module ${infiles_abs}
+    COMMENT "Generating module ${module}")
+
+  # CMake chokes on ${CMAKE_CFG_INTDIR} in source paths when unity builds are
+  # enabled. The easiest way out of this is to skip unity for those paths.
+  # Since generated Interrogate .cxx files are pretty big already, this doesn't
+  # really inconvenience us at all.
+  set_source_files_properties(
+    "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}/${module}_module.cxx"
+    ${sources_abs} PROPERTIES
+    SKIP_UNITY_BUILD_INCLUSION YES)
+
+  add_python_target(${module} COMPONENT "${component}" EXPORT "${component}"
+    "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}/${module}_module.cxx"
+    ${sources_abs} ${extensions})
+  target_link_libraries(${module} ${link_targets})
+
+  if(CMAKE_VERSION VERSION_LESS "3.11")
+    # CMake <3.11 doesn't allow generator expressions on source files, so we
+    # need to copy them to our target, which does allow them.
+
+    foreach(source ${sources_abs})
+      get_source_file_property(compile_definitions "${source}" COMPILE_DEFINITIONS)
+      if(compile_definitions)
+        set_property(TARGET ${module} APPEND PROPERTY
+          COMPILE_DEFINITIONS ${compile_definitions})
+
+        set_source_files_properties("${source}" PROPERTIES COMPILE_DEFINITIONS "")
+      endif()
+    endforeach(source)
+  endif()
+
+  list(APPEND ALL_INTERROGATE_MODULES "${module}")
+  set(ALL_INTERROGATE_MODULES "${ALL_INTERROGATE_MODULES}" CACHE INTERNAL "Internal variable")
+endfunction(add_python_module)

+ 506 - 0
cmake/macros/PackageConfig.cmake

@@ -0,0 +1,506 @@
+# Filename: PackageConfig.cmake
+#
+# This module defines functions which find and configure libraries
+# and packages for Panda3D.
+#
+# Assumes an attempt to find the package has already been made with
+# find_package(). (i.e. relies on packagename_FOUND variable)
+#
+# The packages are added as imported/interface libraries in the PKG::
+# namespace.  If the package is not found (or disabled by the user),
+# a dummy package will be created instead.  Therefore, it is safe
+# to link against the PKG::PACKAGENAME target unconditionally.
+#
+# Function: package_option
+# Usage:
+#   package_option(package_name package_doc_string
+#                  [DEFAULT ON | OFF]
+#                  [IMPORTED_AS CMake::Imported::Target [...]]
+#                  [FOUND_AS find_name]
+#                  [LICENSE license])
+#
+# Examples:
+#   package_option(LIBNAME "Enables LIBNAME support." DEFAULT OFF)
+#
+#       If no default is given, the default in normal
+#       builds is to enable all found third-party packages.
+#       In builds for redistribution, there is the additional requirement that
+#       the package be suitably-licensed.
+#
+#       FOUND_AS indicates the name of the CMake find_package() module, which
+#       may differ from Panda3D's internal name for that package.
+#
+#       IMPORTED_AS is used to indicate that the find_package() may have
+#       provided one or more IMPORTED targets, and that if at least one is
+#       found, the IMPORTED target(s) should be used instead of the
+#       variables provided by find_package()
+#
+#
+# Function: package_status
+# Usage:
+#   package_status(package_name "Package description" ["Config summary"])
+#
+# Examples:
+#   package_status(OpenAL "OpenAL Audio Output")
+#   package_status(ROCKET "Rocket" "without Python bindings")
+#
+#
+# Function: show_packages
+# Usage:
+#   show_packages()
+#
+#   This prints the package usage report using the information provided in
+#   calls to package_status above.
+#
+
+set(_ALL_PACKAGE_OPTIONS CACHE INTERNAL "Internal variable")
+
+#
+# package_option
+#
+# In order to make sure no third-party licenses are inadvertently violated,
+# this imposes a few rules regarding license:
+# 1) If there is no license, no special restrictions.
+# 2) If there is a license, but the build is not flagged for redistribution,
+#    no special restrictions.
+# 3) If there is a license, and this is for redistribution, the package is
+#    forcibly defaulted off and must be explicitly enabled, unless the license
+#    matches a list of licenses suitable for redistribution.
+#
+function(package_option name)
+  # Parse the arguments.
+  set(command)
+  set(default)
+  set(found_as "${name}")
+  set(imported_as)
+  set(license "")
+  set(cache_string)
+
+  string(TOUPPER "${name}" name)
+
+  foreach(arg ${ARGN})
+    if(command STREQUAL "DEFAULT")
+      set(default "${arg}")
+      set(command)
+
+    elseif(command STREQUAL "FOUND_AS")
+      set(found_as "${arg}")
+      set(command)
+
+    elseif(command STREQUAL "LICENSE")
+      set(license "${arg}")
+      set(command)
+
+    elseif(arg STREQUAL "DEFAULT")
+      set(command "DEFAULT")
+
+    elseif(arg STREQUAL "FOUND_AS")
+      set(command "FOUND_AS")
+
+    elseif(arg STREQUAL "LICENSE")
+      set(command "LICENSE")
+
+    elseif(arg STREQUAL "IMPORTED_AS")
+      set(command "IMPORTED_AS")
+
+    elseif(command STREQUAL "IMPORTED_AS")
+      list(APPEND imported_as "${arg}")
+
+    else()
+      # Yes, a list, because semicolons can be in there, and
+      # that gets split up into multiple args, so we have to
+      # join it back together here.
+      list(APPEND cache_string "${arg}")
+
+    endif()
+  endforeach()
+
+  if(command AND NOT command STREQUAL "IMPORTED_AS")
+    message(SEND_ERROR "${command} in package_option takes an argument")
+  endif()
+
+  # If the default is not set, we set it.
+  if(NOT DEFINED default)
+    if(IS_DIST_BUILD)
+      # Accept things that don't have a configured license
+      if(license STREQUAL "")
+        set(default "${${found_as}_FOUND}")
+
+      else()
+        list(FIND PANDA_DIST_USE_LICENSES ${license} license_index)
+        # If the license isn't in the accept listed, don't use the package
+        if(${license_index} EQUAL "-1")
+          set(default OFF)
+
+        else()
+          set(default "${${found_as}_FOUND}")
+
+        endif()
+
+      endif()
+
+    else()
+      set(default "${${found_as}_FOUND}")
+
+    endif()
+  endif()
+
+  # If it was set by the user but not found, display an error.
+  string(TOUPPER "${found_as}" FOUND_AS)
+  if(HAVE_${name} AND NOT ${found_as}_FOUND AND NOT ${FOUND_AS}_FOUND)
+    message(SEND_ERROR "NOT FOUND: ${name}.  Disable HAVE_${name} to continue.")
+  endif()
+
+  # Prevent the function from being called twice.
+  #   This would indicate a cmake error.
+  if(";${_ALL_PACKAGE_OPTIONS};" MATCHES ";${name};")
+    message(SEND_ERROR "package_option(${name}) was called twice.
+                        This is a bug in the cmake build scripts.")
+
+  else()
+    list(APPEND _ALL_PACKAGE_OPTIONS "${name}")
+    set(_ALL_PACKAGE_OPTIONS "${_ALL_PACKAGE_OPTIONS}" CACHE INTERNAL "Internal variable")
+
+  endif()
+
+  set(PANDA_PACKAGE_DEFAULT_${name} "${default}" PARENT_SCOPE)
+
+  # Create the INTERFACE library used to depend on this package.
+  add_library(PKG::${name} INTERFACE IMPORTED GLOBAL)
+
+  # Explicitly record the package's include directories as system include
+  # directories.  CMake does do this automatically for INTERFACE libraries, but
+  # it does it by discovering all transitive links first, then reading
+  # INTERFACE_INCLUDE_DIRECTORIES for those which are INTERFACE libraries.  So,
+  # this would be broken for the metalib system (pre CMake 3.12) which doesn't
+  # "link" the object libraries.
+  if(CMAKE_VERSION VERSION_LESS "3.12")
+    set_target_properties(PKG::${name} PROPERTIES
+      INTERFACE_SYSTEM_INCLUDE_DIRECTORIES
+      "$<TARGET_PROPERTY:PKG::${name},INTERFACE_INCLUDE_DIRECTORIES>")
+  endif()
+
+  # Create the option, and if it actually is enabled, populate the INTERFACE
+  # library created above
+  option("HAVE_${name}" "${cache_string}" "${default}")
+  if(HAVE_${name})
+    set(use_variables ON)
+
+    # This is gross, but we actually want to hide package include directories
+    # from Interrogate to make sure it relies on parser-inc instead, so we'll
+    # use some generator expressions to do that.
+    set(_is_not_interface_lib
+      "$<NOT:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,INTERFACE_LIBRARY>>")
+    set(_is_not_interrogate
+      "$<NOT:$<BOOL:$<${_is_not_interface_lib}:$<TARGET_PROPERTY:IS_INTERROGATE>>>>")
+
+    foreach(implib ${imported_as})
+      if(TARGET ${implib})
+        # We found one of the implibs, so we don't need to use variables
+        # (below) anymore
+        set(use_variables OFF)
+
+        # Hide it from Interrogate
+        target_link_libraries(PKG::${name} INTERFACE
+          "$<${_is_not_interrogate}:$<TARGET_NAME:${implib}>>")
+      endif()
+    endforeach(implib)
+
+    if(use_variables)
+      if(DEFINED ${found_as}_INCLUDE_DIRS)
+        set(includes ${${found_as}_INCLUDE_DIRS})
+      elseif(DEFINED ${found_as}_INCLUDE_DIR)
+        set(includes "${${found_as}_INCLUDE_DIR}")
+      elseif(DEFINED ${FOUND_AS}_INCLUDE_DIRS)
+        set(includes ${${FOUND_AS}_INCLUDE_DIRS})
+      else()
+        set(includes "${${FOUND_AS}_INCLUDE_DIR}")
+      endif()
+
+      if(DEFINED ${found_as}_LIBRARIES)
+        set(libs ${${found_as}_LIBRARIES})
+      elseif(DEFINED ${found_as}_LIBRARY)
+        set(libs "${${found_as}_LIBRARY}")
+      elseif(DEFINED ${FOUND_AS}_LIBRARIES)
+        set(libs ${${FOUND_AS}_LIBRARIES})
+      else()
+        set(libs "${${FOUND_AS}_LIBRARY}")
+      endif()
+
+      target_link_libraries(PKG::${name} INTERFACE ${libs})
+
+      # Hide it from Interrogate
+      set_target_properties(PKG::${name} PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "$<${_is_not_interrogate}:${includes}>")
+    endif()
+  endif()
+endfunction(package_option)
+
+set(_ALL_CONFIG_PACKAGES CACHE INTERNAL "Internal variable")
+
+#
+# package_status
+#
+function(package_status name desc)
+  set(note "")
+  foreach(arg ${ARGN})
+    set(note "${arg}")
+  endforeach()
+
+  string(TOUPPER "${name}" name)
+
+  if(NOT ";${_ALL_PACKAGE_OPTIONS};" MATCHES ";${name};")
+    message(SEND_ERROR "package_status(${name}) was called before package_option(${name}).
+                        This is a bug in the cmake build scripts.")
+    return()
+  endif()
+
+  if(";${_ALL_CONFIG_PACKAGES};" MATCHES ";${name};")
+    message(SEND_ERROR "package_status(${name}) was called twice.
+                        This is a bug in the cmake build scripts.")
+
+  else()
+    list(APPEND _ALL_CONFIG_PACKAGES "${name}")
+    set(_ALL_CONFIG_PACKAGES "${_ALL_CONFIG_PACKAGES}" CACHE INTERNAL "Internal variable")
+
+  endif()
+
+  set(PANDA_PACKAGE_DESC_${name} "${desc}" PARENT_SCOPE)
+  set(PANDA_PACKAGE_NOTE_${name} "${note}" PARENT_SCOPE)
+endfunction()
+
+#
+# show_packages
+#
+function(show_packages)
+  message("")
+  message("Configuring support for the following optional third-party packages:")
+
+  foreach(package ${_ALL_CONFIG_PACKAGES})
+    set(desc "${PANDA_PACKAGE_DESC_${package}}")
+    set(note "${PANDA_PACKAGE_NOTE_${package}}")
+    if(HAVE_${package})
+      if(NOT note STREQUAL "")
+        message("+ ${desc} (${note})")
+      else()
+        message("+ ${desc}")
+      endif()
+
+    else()
+      if(NOT ${package}_FOUND)
+        set(reason "not found")
+      elseif(NOT PANDA_PACKAGE_DEFAULT_${package})
+        set(reason "not requested")
+      else()
+        set(reason "disabled")
+      endif()
+
+      message("- ${desc} (${reason})")
+
+    endif()
+  endforeach()
+endfunction()
+
+#
+# export_packages(filename)
+#
+# Generates an includable CMake file that contains definitions for every PKG::
+# package defined.
+#
+function(export_packages filename)
+  set(exports "# Exports for Panda3D PKG:: packages\n")
+
+  foreach(pkg ${_ALL_PACKAGE_OPTIONS})
+    set(exports "${exports}\n# Create imported target PKG::${pkg}\n")
+    set(exports "${exports}add_library(PKG::${pkg} INTERFACE IMPORTED)\n\n")
+
+    set(exports "${exports}set_target_properties(PKG::${pkg} PROPERTIES\n")
+    foreach(prop
+        INTERFACE_COMPILE_DEFINITIONS
+        INTERFACE_COMPILE_FEATURES
+        INTERFACE_COMPILE_OPTIONS
+        INTERFACE_INCLUDE_DIRECTORIES
+        INTERFACE_LINK_DEPENDS
+        INTERFACE_LINK_DIRECTORIES
+        INTERFACE_LINK_OPTIONS
+        INTERFACE_POSITION_INDEPENDENT_CODE
+       #INTERFACE_SYSTEM_INCLUDE_DIRECTORIES  # Let the consumer dictate this
+        INTERFACE_SOURCES)
+
+      set(prop_ex "$<TARGET_PROPERTY:PKG::${pkg},${prop}>")
+      set(exports "${exports}$<$<BOOL:${prop_ex}>:  ${prop} \"${prop_ex}\"\n>")
+
+    endforeach(prop)
+
+    # Ugh, INTERFACE_LINK_LIBRARIES isn't transitive.  Fine.  Take care of it
+    # by hand:
+    set(libraries)
+    set(stack "PKG::${pkg}")
+    set(history)
+    while(stack)
+      # Remove head item from stack
+      unset(head)
+      while(NOT DEFINED head)
+        if(NOT stack)
+          break()
+        endif()
+
+        list(GET stack 0 head)
+        list(REMOVE_AT stack 0)
+
+        # Don't visit anything twice
+        list(FIND history "${head}" _index)
+        if(_index GREATER -1)
+          unset(head)
+        endif()
+      endwhile()
+
+      if(head)
+        list(APPEND history "${head}")
+      else()
+        break()
+      endif()
+
+      # If head isn't a target, add it to `libraries`, else recurse
+      if(TARGET "${head}")
+        get_target_property(link_libs "${head}" INTERFACE_LINK_LIBRARIES)
+        if(link_libs)
+          list(APPEND stack ${link_libs})
+        endif()
+
+        get_target_property(type "${head}" TYPE)
+        if(NOT type STREQUAL "INTERFACE_LIBRARY")
+          get_target_property(imported_location "${head}" IMPORTED_LOCATION)
+          get_target_property(imported_implib "${head}" IMPORTED_IMPLIB)
+          if(imported_implib)
+            list(APPEND libraries ${imported_implib})
+          elseif(imported_location)
+            list(APPEND libraries ${imported_location})
+          endif()
+
+          get_target_property(configs "${head}" IMPORTED_CONFIGURATIONS)
+          if(configs AND NOT imported_location)
+            foreach(config ${configs})
+              get_target_property(imported_location "${head}" IMPORTED_LOCATION_${config})
+
+              # Prefer IMPORTED_IMPLIB where present
+              get_target_property(imported_implib "${head}" IMPORTED_IMPLIB_${config})
+              if(imported_implib)
+                set(imported_location "${imported_implib}")
+              endif()
+
+              if(imported_location)
+                if(configs MATCHES ".*;.*")
+                  set(_bling "$<1:$>") # genex-escaped $
+                  list(APPEND libraries "${_bling}<${_bling}<CONFIG:${config}>:${imported_location}>")
+
+                else()
+                  list(APPEND libraries ${imported_location})
+
+                endif()
+              endif()
+            endforeach(config)
+          endif()
+
+        elseif(CMAKE_VERSION VERSION_GREATER "3.8")
+          # This is an INTERFACE_LIBRARY, and CMake is new enough to support
+          # IMPORTED_IMPLIB
+          get_target_property(imported_libname "${head}" IMPORTED_LIBNAME)
+          if(imported_libname)
+            list(APPEND libraries ${imported_libname})
+          endif()
+
+        endif()
+
+      elseif("${head}" MATCHES "\\$<TARGET_NAME:\([^>]+\)>")
+        string(REGEX REPLACE ".*\\$<TARGET_NAME:\([^>]+\)>.*" "\\1" match "${head}")
+        list(APPEND stack "${match}")
+
+      else()
+        list(APPEND libraries "${head}")
+
+      endif()
+    endwhile(stack)
+
+    set(exports "${exports}  INTERFACE_LINK_LIBRARIES \"${libraries}\"\n")
+
+    set(exports "${exports})\n")
+  endforeach(pkg)
+
+  # file(GENERATE) does not like $<LINK_ONLY:...> (and it's meant to be
+  # consumed by our importer) so we escape it
+  set(_bling "$<1:$>") # genex-escaped $
+  string(REPLACE "$<LINK_ONLY:" "${_bling}<LINK_ONLY:" exports "${exports}")
+
+  file(GENERATE OUTPUT "${filename}" CONTENT "${exports}")
+endfunction(export_packages)
+
+#
+# export_targets(set [NAMESPACE namespace] [COMPONENT component])
+#
+# Export targets in the export set named by "set"
+#
+# NAMESPACE overrides the namespace prefixed to the exported targets; it
+# defaults to "Panda3D::[set]::" if no explicit override is given.
+#
+# COMPONENT overrides the install component for the generated .cmake file; it
+# defaults to "[set]" if no explicit override is given.
+#
+function(export_targets set)
+  set(namespace "Panda3D::${set}::")
+  set(component "${set}")
+  set(keyword)
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "NAMESPACE" OR
+       arg STREQUAL "COMPONENT")
+
+      set(keyword "${arg}")
+
+    elseif(keyword STREQUAL "NAMESPACE")
+      set(namespace "${arg}")
+
+    elseif(keyword STREQUAL "COMPONENT")
+      set(component "${arg}")
+
+    else()
+      message(FATAL_ERROR "export_targets() given unexpected arg: ${arg}")
+
+    endif()
+  endforeach(arg)
+
+  export(EXPORT "${set}" NAMESPACE "${namespace}"
+    FILE "${PROJECT_BINARY_DIR}/Panda3D${set}Targets.cmake")
+  install(EXPORT "${set}" NAMESPACE "${namespace}"
+    FILE "Panda3D${set}Targets.cmake"
+    COMPONENT "${component}" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Panda3D)
+
+endfunction(export_targets)
+
+#
+# find_package
+#
+# This override implements CMAKE_FIND_PACKAGE_PREFER_CONFIG on versions of
+# CMake too old to include it.
+#
+if(CMAKE_VERSION VERSION_LESS "3.15")
+  macro(find_package name)
+    if(";${ARGN};" MATCHES ";(CONFIG|MODULE|NO_MODULE);")
+      # Caller explicitly asking for a certain mode; so be it.
+      _find_package(${ARGV})
+
+    elseif(CMAKE_FIND_PACKAGE_PREFER_CONFIG)
+      # Try CONFIG
+      _find_package("${name}" CONFIG ${ARGN})
+
+      if(NOT ${name}_FOUND)
+        # CONFIG didn't work, fall back to MODULE
+        _find_package("${name}" MODULE ${ARGN})
+      endif()
+
+    else()
+      # Default behavior
+      _find_package(${ARGV})
+
+    endif()
+  endmacro(find_package)
+endif()

+ 163 - 0
cmake/macros/Python.cmake

@@ -0,0 +1,163 @@
+# Filename: Python.cmake
+#
+# Description: This file provides support functions for building/installing
+#   Python extension modules and/or pure-Python packages.
+#
+# Functions:
+#   add_python_target(target [source1 [source2 ...]])
+#   install_python_package(path [ARCH/LIB])
+#
+
+#
+# Function: add_python_target(target [EXPORT exp] [COMPONENT comp]
+#                                    [source1 [source2 ...]])
+# Build the provided source(s) as a Python extension module, linked against the
+# Python runtime library.
+#
+# Note that this also takes care of installation, unlike other target creation
+# commands in CMake.  The EXPORT and COMPONENT keywords allow passing the
+# corresponding options to install(), but default to "Python" otherwise.
+#
+function(add_python_target target)
+  if(NOT HAVE_PYTHON)
+    return()
+  endif()
+
+  string(REGEX REPLACE "^.*\\." "" basename "${target}")
+  set(sources)
+  set(component "Python")
+  set(export "Python")
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "COMPONENT")
+      set(keyword "component")
+
+    elseif(arg STREQUAL "EXPORT")
+      set(keyword "export")
+
+    elseif(keyword)
+      set(${keyword} "${arg}")
+      unset(keyword)
+
+    else()
+      list(APPEND sources "${arg}")
+
+    endif()
+  endforeach(arg)
+
+  string(REGEX REPLACE "\\.[^.]+$" "" namespace "${target}")
+  string(REPLACE "." "/" slash_namespace "${namespace}")
+
+  add_library(${target} ${MODULE_TYPE} ${sources})
+  target_link_libraries(${target} PKG::PYTHON)
+
+  if(BUILD_SHARED_LIBS)
+    set(_outdir "${PANDA_OUTPUT_DIR}/${slash_namespace}")
+
+    set_target_properties(${target} PROPERTIES
+      LIBRARY_OUTPUT_DIRECTORY "${_outdir}"
+      OUTPUT_NAME "${basename}"
+      PREFIX ""
+      SUFFIX "${PYTHON_EXTENSION_SUFFIX}")
+
+    # This is explained over in CompilerFlags.cmake
+    foreach(_config ${CMAKE_CONFIGURATION_TYPES})
+      string(TOUPPER "${_config}" _config)
+      set_target_properties(${target} PROPERTIES
+        LIBRARY_OUTPUT_DIRECTORY_${_config} "${_outdir}")
+    endforeach(_config)
+
+    if(PYTHON_ARCH_INSTALL_DIR)
+      install(TARGETS ${target} EXPORT "${export}" COMPONENT "${component}" DESTINATION "${PYTHON_ARCH_INSTALL_DIR}/${slash_namespace}")
+    endif()
+
+  else()
+    set_target_properties(${target} PROPERTIES
+      OUTPUT_NAME "${basename}"
+      PREFIX "libpy.${namespace}.")
+
+    install(TARGETS ${target} EXPORT "${export}" COMPONENT "${component}" DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
+  endif()
+
+endfunction(add_python_target)
+
+#
+# Function: install_python_package(name [SOURCE path] [ARCH/LIB] [COMPONENT component])
+#
+# Installs the Python package `name` (which may have its source at `path`).
+#
+# The package is copied to (or created in) the build directory so that the user
+# may import it before the install step.
+#
+# Note that this handles more than just installation; it will also invoke
+# Python's compileall utility to pregenerate .pyc/.pyo files.  This will only
+# happen if the Python interpreter is found.
+#
+# The ARCH or LIB keyword may be used to specify whether this package should be
+# installed into Python's architecture-dependent or architecture-independent
+# package path.  The default, if unspecified, is LIB.
+#
+# The COMPONENT keyword overrides the install component (see CMake's
+# documentation for more information on what this does).  The default is
+# "Python".
+#
+function(install_python_package package_name)
+  set(type "LIB")
+  unset(keyword)
+  set(component "Python")
+  unset(src_path)
+  foreach(arg ${ARGN})
+    if(arg STREQUAL "ARCH")
+      set(type "ARCH")
+
+    elseif(arg STREQUAL "LIB")
+      set(type "LIB")
+
+    elseif(arg STREQUAL "COMPONENT")
+      set(keyword "${arg}")
+
+    elseif(keyword STREQUAL "COMPONENT")
+      set(component "${arg}")
+      unset(keyword)
+
+    elseif(arg STREQUAL "SOURCE")
+      set(keyword "${arg}")
+
+    elseif(keyword STREQUAL "SOURCE")
+      set(src_path "${arg}")
+      unset(keyword)
+
+    else()
+      message(FATAL_ERROR "install_python_package got unexpected argument: ${ARGN}")
+
+    endif()
+  endforeach(arg)
+
+  if(NOT DEFINED src_path AND type STREQUAL "ARCH" AND WIN32 AND NOT CYGWIN)
+    # Win32 needs a special fixup so the DLLs in "bin" can be on the path;
+    # let's set src_path to the directory containing our fixup __init__.py
+    set(src_path "${CMAKE_SOURCE_DIR}/cmake/templates/win32_python")
+  endif()
+
+  set(path "${PANDA_OUTPUT_DIR}/${package_name}")
+
+  set(args -D "OUTPUT_DIR=${path}")
+  if(src_path)
+    list(APPEND args -D "SOURCE_DIR=${src_path}")
+  endif()
+  if(PYTHON_EXECUTABLE)
+    list(APPEND args -D "PYTHON_EXECUTABLES=${PYTHON_EXECUTABLE}")
+  endif()
+  add_custom_target(${package_name} ALL
+    COMMAND ${CMAKE_COMMAND}
+      ${args}
+      -P "${CMAKE_SOURCE_DIR}/cmake/scripts/CopyPython.cmake")
+
+  set(dir "${PYTHON_${type}_INSTALL_DIR}")
+  if(dir)
+    install(DIRECTORY "${path}" DESTINATION "${dir}"
+      COMPONENT "${component}"
+      FILES_MATCHING REGEX "\\.py[co]?$")
+  endif()
+
+endfunction(install_python_package)

+ 9 - 0
cmake/macros/README.md

@@ -0,0 +1,9 @@
+Directory Info
+--------------
+**Directory:** /cmake/macros  
+**License:** Unlicense  
+**Description:** This directory is used for CMake modules which may be _unsafe_
+to use outside of a Panda3D project.  These modules may rely on Panda3D specific
+cmake variables, Panda3D's directory structure, or some other dependency.
+They are not intended to be included in other projects directly, though you
+are free to copy and adapt them to your own needs.

+ 37 - 0
cmake/macros/RunPzip.cmake

@@ -0,0 +1,37 @@
+function(run_pzip target_name source destination glob)
+  file(GLOB_RECURSE files RELATIVE "${source}" "${source}/${glob}")
+
+  set(dstfiles "")
+  foreach(filename ${files})
+    string(REGEX REPLACE "^/" "" filename "${filename}")
+
+    get_filename_component(dstdir "${destination}/${filename}" DIRECTORY)
+
+    if(TARGET host_pzip)
+      set(dstfile "${filename}.pz")
+      list(APPEND dstfiles "${destination}/${dstfile}")
+
+      add_custom_command(OUTPUT "${destination}/${dstfile}"
+        COMMAND ${CMAKE_COMMAND} -E make_directory "${dstdir}"
+        COMMAND host_pzip -c > "${destination}/${dstfile}" < "${source}/${filename}"
+        DEPENDS host_pzip
+        COMMENT "")
+
+    else()
+      # If pzip isn't built, we just copy instead.
+      list(APPEND dstfiles "${destination}/${filename}")
+
+      add_custom_command(OUTPUT "${destination}/${filename}"
+        COMMAND ${CMAKE_COMMAND} -E
+          copy_if_different "${source}/${filename}" "${destination}/${filename}"
+        COMMENT "")
+
+    endif()
+
+  endforeach(filename)
+
+  add_custom_target(${target_name} ALL
+    DEPENDS ${dstfiles}
+    WORKING_DIRECTORY "${destination}")
+
+endfunction(run_pzip)

+ 21 - 0
cmake/macros/Versioning.cmake

@@ -0,0 +1,21 @@
+# Filename: Versioning.cmake
+#
+# Description: Contains an override for add_library to set the
+#   VERSION and SOVERSION properties on all shared libraries, automatically, to
+#   the project version.
+#
+# Functions:
+#   add_library(...)
+#
+
+function(add_library target_name)
+  _add_library("${target_name}" ${ARGN})
+
+  get_target_property(type "${target_name}" TYPE)
+  if(type STREQUAL "SHARED_LIBRARY")
+    set_target_properties("${target_name}" PROPERTIES
+      VERSION "${PROJECT_VERSION}"
+      SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
+  endif()
+
+endfunction(add_library)

+ 33 - 0
cmake/modules/FindARToolKit.cmake

@@ -0,0 +1,33 @@
+# Filename: FindARToolKit.cmake
+# Authors: CFSworks (3 Nov, 2018)
+#
+# Usage:
+#   find_package(ARToolKit [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   ARTOOLKIT_FOUND       - system has ARToolKit
+#   ARTOOLKIT_INCLUDE_DIR - the include directory containing ARToolKit header files
+#   ARTOOLKIT_LIBRARIES   - the paths to the ARToolKit client libraries
+#
+
+find_path(ARTOOLKIT_INCLUDE_DIR "AR/ar.h")
+
+find_library(ARTOOLKIT_AR_LIBRARY
+  NAMES "AR" "libAR")
+
+find_library(ARTOOLKIT_ARMulti_LIBRARY
+  NAMES "ARMulti" "libARMulti")
+
+mark_as_advanced(ARTOOLKIT_INCLUDE_DIR ARTOOLKIT_AR_LIBRARY ARTOOLKIT_ARMulti_LIBRARY)
+
+set(ARTOOLKIT_LIBRARIES)
+if(ARTOOLKIT_AR_LIBRARY)
+  list(APPEND ARTOOLKIT_LIBRARIES "${ARTOOLKIT_AR_LIBRARY}")
+endif()
+if(ARTOOLKIT_ARMulti_LIBRARY)
+  list(APPEND ARTOOLKIT_LIBRARIES "${ARTOOLKIT_ARMulti_LIBRARY}")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ARToolKit DEFAULT_MSG
+  ARTOOLKIT_INCLUDE_DIR ARTOOLKIT_LIBRARIES)

+ 33 - 0
cmake/modules/FindAssimp.cmake

@@ -0,0 +1,33 @@
+# Filename: FindAssimp.cmake
+# Authors: CFSworks (9 Nov, 2018)
+#
+# Usage:
+#   find_package(Assimp [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   ASSIMP_FOUND        - system has Assimp
+#   ASSIMP_INCLUDE_DIR  - the path to the location of the assimp/ directory
+#   ASSIMP_LIBRARIES    - the libraries to link against for Assimp
+#
+
+find_path(ASSIMP_INCLUDE_DIR
+  NAMES "assimp/Importer.hpp")
+
+find_library(ASSIMP_ASSIMP_LIBRARY
+  NAMES "assimp")
+
+find_library(ASSIMP_IRRXML_LIBRARY
+  NAMES "IrrXML")
+
+if(ASSIMP_ASSIMP_LIBRARY)
+  set(ASSIMP_LIBRARIES "${ASSIMP_ASSIMP_LIBRARY}")
+
+  if(ASSIMP_IRRXML_LIBRARY)
+    list(APPEND ASSIMP_LIBRARIES "${ASSIMP_IRRXML_LIBRARY}")
+  endif()
+endif()
+
+mark_as_advanced(ASSIMP_INCLUDE_DIR ASSIMP_LIBRARIES)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Assimp DEFAULT_MSG ASSIMP_INCLUDE_DIR ASSIMP_LIBRARIES)

+ 175 - 0
cmake/modules/FindCg.cmake

@@ -0,0 +1,175 @@
+# Filename: FindCg.cmake
+# Author: kestred (8 Dec, 2013)
+#
+# Usage:
+#   find_package(Cg [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   CG_FOUND         - system has NvidiaCg
+#   CG_INCLUDE_DIR   - the NvidiaCg include directory
+#   CG_INCLUDE_DIRS  - directories for all NvidiaCg components
+#   CG_LIBRARY_DIR   - the NvidiaCg library directory
+#   CG_LIBRARY       - the path to the library binary
+#   CG_LIBRARIES     - the paths to the Cg library and each library below.
+#
+#   CGGL_FOUND       - system has CgGL
+#   CGGL_INCLUDE_DIR - the CgGL include directory
+#   CGGL_LIBRARY_DIR - the CgGL library directory
+#   CGGL_LIBRARY     - the path to the library binary
+#
+
+
+### Define macros to find each sublibrary ###
+
+# Find Cg for OpenGL
+macro(find_cggl)
+  if(APPLE)
+    # GL support is built-in on Apple
+    set(CGGL_LIBRARY "${CG_LIBRARY}")
+    set(CGGL_LIBRARY_DIR "${CG_LIBRARY_DIR}")
+    set(CGGL_INCLUDE_DIR "${CG_INCLUDE_DIR}")
+  endif()
+
+  if(Cg_FIND_QUIETLY)
+    set(CgGL_FIND_QUIETLY TRUE)
+  endif()
+  if(NOT CGGL_LIBRARY_DIR OR NOT CGGL_INCLUDE_DIR)
+    # Find the include directory
+    find_path(CGGL_INCLUDE_DIR
+      NAMES "cgGL.h"
+      PATHS "C:/Program Files/Cg"
+            "C:/Program Files/NVIDIA Corporation/Cg/include"
+            "/usr/include"
+            "/usr/local/include"
+            "/opt/Cg"
+            "/opt/nvidia-cg-toolkit/include" # Gentoo
+      PATH_SUFFIXES "" "Cg" "cg"
+      DOC "The path to NvidiaCgGL's include directory."
+    )
+
+    # Find the library directory
+    find_library(CGGL_LIBRARY
+      NAMES "CgGL" "libCgGL"
+      PATHS "C:/Program Files/Cg"
+            "C:/Program Files/NVIDIA Corporation/Cg"
+            "/usr"
+            "/usr/lib/x86_64-linux-gnu"
+            "/usr/local"
+            "/opt/Cg"
+            "/opt/nvidia-cg-toolkit" # Gentoo
+      PATH_SUFFIXES "" "lib" "lib32" "lib64"
+      DOC "The filepath to NvidiaCgGL's libary binary."
+    )
+    get_filename_component(CGGL_LIBRARY_DIR "${CGGL_LIBRARY}" PATH)
+    set(CGGL_LIBRARY_DIR "${CGGL_LIBRARY_DIR}" CACHE PATH "The path to the CgGL library directory.") # Library path
+
+    mark_as_advanced(CGGL_INCLUDE_DIR)
+    mark_as_advanced(CGGL_LIBRARY_DIR)
+    mark_as_advanced(CGGL_LIBRARY)
+  endif()
+
+  find_package_handle_standard_args(CgGL DEFAULT_MSG CGGL_LIBRARY CGGL_INCLUDE_DIR CGGL_LIBRARY_DIR)
+
+endmacro()
+
+
+# Find Cg for Direct3D 9
+macro(find_cgd3d9)
+  if(Cg_FIND_QUIETLY)
+    set(CgD3D9_FIND_QUIETLY TRUE)
+  endif()
+  if(NOT CGD3D9_LIBRARY_DIR OR NOT CGD3D9_INCLUDE_DIR)
+    # Find the include directory
+    find_path(CGD3D9_INCLUDE_DIR
+      NAMES "cgD3D9.h"
+      PATHS "C:/Program Files/Cg"
+            "C:/Program Files/NVIDIA Corporation/Cg/include"
+            "/usr/include"
+            "/usr/local/include"
+            "/opt/Cg"
+            "/opt/nvidia-cg-toolkit/include" # Gentoo
+      PATH_SUFFIXES "" "Cg" "cg"
+      DOC "The path to NvidiaCgD3D9's include directory."
+    )
+
+    # Find the library directory
+    find_library(CGD3D9_LIBRARY
+      NAMES "CgD3D9" "libCgD3D9"
+      PATHS "C:/Program Files/Cg"
+            "C:/Program Files/NVIDIA Corporation/Cg"
+            "/usr"
+            "/usr/lib/x86_64-linux-gnu"
+            "/usr/local"
+            "/opt/Cg"
+            "/opt/nvidia-cg-toolkit" # Gentoo
+      PATH_SUFFIXES "" "lib" "lib32" "lib64"
+      DOC "The filepath to NvidiaCgD3D9's libary binary."
+    )
+    get_filename_component(CGD3D9_LIBRARY_DIR "${CGD3D9_LIBRARY}" PATH)
+    set(CGD3D9_LIBRARY_DIR "${CGD3D9_LIBRARY_DIR}" CACHE PATH "The path to the CgD3D9 library directory.") # Library path
+
+    mark_as_advanced(CGD3D9_INCLUDE_DIR)
+    mark_as_advanced(CGD3D9_LIBRARY_DIR)
+    mark_as_advanced(CGD3D9_LIBRARY)
+  endif()
+
+  find_package_handle_standard_args(CgD3D9 DEFAULT_MSG CGD3D9_LIBRARY CGD3D9_INCLUDE_DIR CGD3D9_LIBRARY_DIR)
+
+endmacro()
+
+
+
+# Find base Nvidia Cg
+if(NOT CG_LIBRARY_DIR OR NOT CG_INCLUDE_DIRS)
+  # Find the include directory
+  find_path(CG_INCLUDE_DIR
+    NAMES "Cg/cg.h"
+    PATHS "C:/Program Files/Cg"
+          "C:/Program Files/NVIDIA Corporation/Cg/include"
+          "/usr/include"
+          "/usr/local/include"
+          "/opt/Cg"
+          "/opt/nvidia-cg-toolkit/include" # Gentoo
+    PATH_SUFFIXES "" "Cg" "cg"
+    DOC "The path to NvidiaCg's include directory."
+  )
+
+  # Find the library directory
+  find_library(CG_LIBRARY
+    NAMES "Cg" "libCg"
+    PATHS "C:/Program Files/Cg"
+          "C:/Program Files/NVIDIA Corporation/Cg"
+          "/usr"
+          "/usr/lib/x86_64-linux-gnu"
+          "/usr/local"
+          "/opt/Cg"
+          "/opt/nvidia-cg-toolkit" # Gentoo
+    PATH_SUFFIXES "" "lib" "lib32" "lib64"
+  )
+  get_filename_component(CG_LIBRARY_DIR "${CG_LIBRARY}" PATH)
+  set(CG_LIBRARY_DIR "${CG_LIBRARY_DIR}" CACHE PATH "The path to NvidiaCG's library directory.") # Library path
+
+  string(REGEX REPLACE "/Cg$" "" CG_BASE_INCLUDE_DIR "${CG_INCLUDE_DIR}")
+  set(CG_INCLUDE_DIRS ${CG_BASE_INCLUDE_DIR} ${CG_INCLUDE_DIR})
+
+  mark_as_advanced(CG_INCLUDE_DIRS)
+  mark_as_advanced(CG_INCLUDE_DIR)
+  mark_as_advanced(CG_LIBRARY_DIR)
+  mark_as_advanced(CG_LIBRARY)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Cg DEFAULT_MSG CG_LIBRARY CG_INCLUDE_DIRS CG_LIBRARY_DIR)
+
+if(CG_INCLUDE_DIR AND CG_LIBRARY_DIR)
+  find_cggl()
+  find_cgd3d9()
+
+  set(CG_LIBRARIES ${CG_LIBRARY})
+  if(CGGL_LIBRARY)
+    list(APPEND CG_LIBRARIES "${CGGL_LIBRARY}")
+  endif()
+  if(CGD3D9_LIBRARY)
+    list(APPEND CG_LIBRARIES "${CGD3D9_LIBRARY}")
+  endif()
+endif()

+ 104 - 0
cmake/modules/FindDirect3D9.cmake

@@ -0,0 +1,104 @@
+# Filename: FindDirect3D9.cmake
+# Authors: CFSworks (26 Oct, 2018)
+#
+# Usage:
+#   find_package(Direct3D9 [REQUIRED] [QUIET])
+#
+# This supports the following components:
+#   d3dx9
+#   dxerr
+#   dxguid
+#
+# Once done this will define:
+#   DIRECT3D9_FOUND       - system has Direct3D 9.x
+#   DIRECT3D9_INCLUDE_DIR - the include directory containing d3d9.h - note that
+#                           this will be empty if it's part of the Windows SDK.
+#   DIRECT3D9_LIBRARY     - the path to d3d9.lib
+#   DIRECT3D9_LIBRARIES   - the path to d3d9.lib and all extra component
+#                           libraries
+#
+
+include(CheckIncludeFile)
+
+if(Direct3D9_FIND_QUIETLY)
+  if(DEFINED CMAKE_REQUIRED_QUIET)
+    set(_OLD_CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET})
+  endif()
+  # Suppress check_include_file messages
+  set(CMAKE_REQUIRED_QUIET ON)
+endif()
+
+check_include_file("d3d9.h" SYSTEM_INCLUDE_D3D9_H)
+mark_as_advanced(SYSTEM_INCLUDE_D3D9_H)
+
+if(Direct3D9_FIND_QUIETLY)
+  if(DEFINED _OLD_CMAKE_REQUIRED_QUIET)
+    set(CMAKE_REQUIRED_QUIET ${_OLD_CMAKE_REQUIRED_QUIET})
+    unset(_OLD_CMAKE_REQUIRED_QUIET)
+  else()
+    unset(CMAKE_REQUIRED_QUIET)
+  endif()
+endif()
+
+if(SYSTEM_INCLUDE_D3D9_H
+    AND NOT Direct3D9_FIND_REQUIRED_d3dx9
+    AND NOT Direct3D9_FIND_REQUIRED_dxerr)
+  # It's available as #include <d3d9.h> - easy enough.  We'll use "." as a way
+  # of saying "We found it, but please erase this variable later."
+  set(DIRECT3D9_INCLUDE_DIR ".")
+
+  # Since d3d9.h is on the search path, we can pretty much assume d3d9.lib is
+  # as well.
+  set(DIRECT3D9_LIBRARY "d3d9.lib")
+
+  # And dxguid.lib, why not
+  set(DIRECT3D9_dxguid_LIBRARY "dxguid.lib")
+
+else()
+  # We could not find it easily - maybe it's installed separately as part of
+  # the DirectX SDK?
+
+  find_path(DIRECT3D9_INCLUDE_DIR
+    NAMES d3d9.h
+    PATHS "$ENV{DXSDK_DIR}/Include")
+
+  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    set(dx_lib_path "$ENV{DXSDK_DIR}/Lib/x64/")
+  else()
+    set(dx_lib_path "$ENV{DXSDK_DIR}/Lib/x86/")
+  endif()
+
+  find_library(DIRECT3D9_LIBRARY d3d9 "${dx_lib_path}" NO_DEFAULT_PATH)
+
+  find_library(DIRECT3D9_d3dx9_LIBRARY d3dx9 "${dx_lib_path}" NO_DEFAULT_PATH)
+  find_library(DIRECT3D9_dxerr_LIBRARY dxerr "${dx_lib_path}" NO_DEFAULT_PATH)
+  find_library(DIRECT3D9_dxguid_LIBRARY dxguid "${dx_lib_path}" NO_DEFAULT_PATH)
+
+  unset(dx_lib_path)
+endif()
+
+mark_as_advanced(DIRECT3D9_INCLUDE_DIR DIRECT3D9_LIBRARY)
+set(DIRECT3D9_LIBRARIES "${DIRECT3D9_LIBRARY}")
+
+foreach(_component d3dx9 dxerr dxguid)
+  if(DIRECT3D9_${_component}_LIBRARY)
+    set(Direct3D9_${_component}_FOUND ON)
+    list(FIND Direct3D9_FIND_COMPONENTS "${_component}" _index)
+    if(${_index} GREATER -1)
+      list(APPEND DIRECT3D9_LIBRARIES "${DIRECT3D9_${_component}_LIBRARY}")
+    endif()
+    unset(_index)
+  endif()
+endforeach(_component)
+unset(_component)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Direct3D9 HANDLE_COMPONENTS
+  REQUIRED_VARS DIRECT3D9_INCLUDE_DIR DIRECT3D9_LIBRARY DIRECT3D9_LIBRARIES)
+
+# See above - if we found the include as part of the system path, we don't want
+# to actually modify the include search path, but we need a non-empty string to
+# satisfy find_package_handle_standard_args()
+if(DIRECT3D9_INCLUDE_DIR STREQUAL ".")
+  set(DIRECT3D9_INCLUDE_DIR "")
+endif()

+ 21 - 0
cmake/modules/FindEGL.cmake

@@ -0,0 +1,21 @@
+# Filename: FindEGL.cmake
+# Authors: CFSworks (21 Oct, 2018)
+#
+# Usage:
+#   find_package(EGL [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   EGL_FOUND        - system has EGL
+#   EGL_INCLUDE_DIR  - the include directory containing EGL/egl.h
+#   EGL_LIBRARY      - the library to link against for EGL
+#
+
+find_path(EGL_INCLUDE_DIR "EGL/egl.h")
+
+find_library(EGL_LIBRARY
+  NAMES "EGL")
+
+mark_as_advanced(EGL_INCLUDE_DIR EGL_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(EGL DEFAULT_MSG EGL_INCLUDE_DIR EGL_LIBRARY)

+ 25 - 0
cmake/modules/FindEigen3.cmake

@@ -0,0 +1,25 @@
+# Filename: FindEigen3.cmake
+# Authors: kestred (13 Dec, 2013)
+#
+# Usage:
+#   find_package(Eigen3 [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   EIGEN_FOUND        - system has any version of Eigen
+#   EIGEN3_FOUND       - system has Eigen3
+#   EIGEN3_INCLUDE_DIR - the Eigen3 include directory
+#
+
+find_path(EIGEN3_INCLUDE_DIR
+  NAMES signature_of_eigen3_matrix_library
+  PATH_SUFFIXES eigen3 eigen)
+
+mark_as_advanced(EIGEN3_INCLUDE_DIR)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR)
+
+if(EIGEN3_FOUND)
+  set(EIGEN_FOUND TRUE)
+  set(EIGEN_INCLUDE_DIR ${EIGEN3_INCLUDE_DIR})
+endif()

+ 88 - 0
cmake/modules/FindFCollada.cmake

@@ -0,0 +1,88 @@
+# Filename: FindFCollada.cmake
+# Author: CFSworks (17 Mar, 2019)
+#
+# Usage:
+#   find_package(FCollada [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   FCOLLADA_FOUND       - system has FCollada
+#   FCOLLADA_INCLUDE_DIR - the FCollada include directory
+#
+#   FCOLLADA_RELEASE_LIBRARY - the filepath of the FCollada release library
+#   FCOLLADA_DEBUG_LIBRARY   - the filepath of the FCollada debug library
+#
+#   FCollada::FCollada - The recommended FCollada library to link against
+#
+
+# Find the FCollada include files
+find_path(FCOLLADA_INCLUDE_DIR "FCollada.h" PATH_SUFFIXES "FCollada")
+
+# Find the library built for release
+find_library(FCOLLADA_RELEASE_LIBRARY
+  NAMES "FCollada" "libFCollada"
+  "FColladaS" "libFColladaS"
+  "FColladaU" "libFColladaU"
+  "FColladaSU" "libFColladaSU"
+)
+
+# Find the library built for debug
+find_library(FCOLLADA_DEBUG_LIBRARY
+  NAMES "FColladaD" "libFColladaD"
+  "FColladaSD" "libFColladaSD"
+  "FColladaUD" "libFColladaUD"
+  "FColladaSUD" "libFColladaSUD"
+)
+
+mark_as_advanced(FCOLLADA_INCLUDE_DIR)
+mark_as_advanced(FCOLLADA_RELEASE_LIBRARY)
+mark_as_advanced(FCOLLADA_DEBUG_LIBRARY)
+
+set(_defines)
+if(FCOLLADA_RELEASE_LIBRARY MATCHES "FCollada[^/]*U" OR
+    FCOLLADA_DEBUG_LIBRARY MATCHES "FCollada[^/]*U")
+  list(APPEND _defines "UNICODE")
+endif()
+if(NOT MSVC AND
+    NOT FCOLLADA_RELEASE_LIBRARY MATCHES "FCollada[^/]*S" AND
+    NOT FCOLLADA_DEBUG_LIBRARY MATCHES "FCollada[^/]*S")
+  list(APPEND _defines "FCOLLADA_DLL")
+endif()
+
+# Identify the configs which we have available
+set(_configs)
+if(FCOLLADA_INCLUDE_DIR)
+  if(FCOLLADA_RELEASE_LIBRARY)
+    list(APPEND _configs RELEASE)
+  endif()
+  if(FCOLLADA_DEBUG_LIBRARY)
+    list(APPEND _configs DEBUG)
+  endif()
+
+  if(_configs)
+    set(_HAS_FCOLLADA_LIBRARY ON)
+    add_library(FCollada::FCollada UNKNOWN IMPORTED GLOBAL)
+
+    set_target_properties(FCollada::FCollada PROPERTIES
+      INTERFACE_COMPILE_DEFINITIONS "${_defines}"
+      INTERFACE_INCLUDE_DIRECTORIES "${FCOLLADA_INCLUDE_DIR}")
+
+  endif()
+
+endif()
+
+foreach(_config ${_configs})
+  set_property(TARGET FCollada::FCollada
+    APPEND PROPERTY IMPORTED_CONFIGURATIONS "${_config}")
+
+  set_target_properties(FCollada::FCollada PROPERTIES
+    IMPORTED_LOCATION_${_config} "${FCOLLADA_${_config}_LIBRARY}")
+
+endforeach(_config)
+unset(_config)
+unset(_configs)
+unset(_defines)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FCollada DEFAULT_MSG FCOLLADA_INCLUDE_DIR _HAS_FCOLLADA_LIBRARY)
+
+unset(_HAS_FCOLLADA_LIBRARY)

+ 116 - 0
cmake/modules/FindFFMPEG.cmake

@@ -0,0 +1,116 @@
+# Filename: FindFFMPEG.cmake
+# Author: CFSworks (10 Apr, 2014)
+#
+# Usage:
+#   find_package(FFMPEG [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   FFMPEG_FOUND       - system has ffmpeg
+#   FFMPEG_INCLUDE_DIR - the ffmpeg include directory
+#   FFMPEG_LIBRARIES   - the path to the library binary
+#
+#   FFMPEG_LIBAVCODEC  - the path to the libavcodec library binary
+#   FFMPEG_LIBAVFORMAT - the path to the libavformat library binary
+#   FFMPEG_LIBAVUTIL   - the path to the libavutil library binary
+#
+
+# Find the libffmpeg include files
+find_path(FFMPEG_INCLUDE_DIR
+  NAMES "libavcodec/avcodec.h"
+  PATHS "/usr/include"
+        "/usr/local/include"
+        "/sw/include"
+        "/opt/include"
+        "/opt/local/include"
+        "/opt/csw/include"
+  PATH_SUFFIXES "libav" "ffmpeg"
+)
+
+# Find the libavcodec library
+find_library(FFMPEG_LIBAVCODEC
+  NAMES "avcodec"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/freeware"
+        "/sw"
+        "/opt"
+        "/opt/csw"
+  PATH_SUFFIXES "lib" "lib32" "lib64"
+)
+
+# Find the libavformat library
+find_library(FFMPEG_LIBAVFORMAT
+  NAMES "avformat"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/freeware"
+        "/sw"
+        "/opt"
+        "/opt/csw"
+  PATH_SUFFIXES "lib" "lib32" "lib64"
+)
+
+# Find the libavutil library
+find_library(FFMPEG_LIBAVUTIL
+  NAMES "avutil"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/freeware"
+        "/sw"
+        "/opt"
+        "/opt/csw"
+  PATH_SUFFIXES "lib" "lib32" "lib64"
+)
+
+mark_as_advanced(FFMPEG_INCLUDE_DIR)
+mark_as_advanced(FFMPEG_LIBAVCODEC)
+mark_as_advanced(FFMPEG_LIBAVFORMAT)
+mark_as_advanced(FFMPEG_LIBAVUTIL)
+
+# Translate library into library directory
+if(FFMPEG_LIBAVCODEC)
+  unset(FFMPEG_LIBRARY_DIR CACHE)
+  get_filename_component(FFMPEG_LIBRARY_DIR "${FFMPEG_LIBAVCODEC}" PATH)
+  set(FFMPEG_LIBRARY_DIR "${FFMPEG_LIBRARY_DIR}" CACHE PATH "The path to libffmpeg's library directory.") # Library path
+endif()
+
+set(FFMPEG_LIBRARIES)
+if(FFMPEG_LIBAVCODEC)
+  list(APPEND FFMPEG_LIBRARIES "${FFMPEG_LIBAVCODEC}")
+endif()
+if(FFMPEG_LIBAVFORMAT)
+  list(APPEND FFMPEG_LIBRARIES "${FFMPEG_LIBAVFORMAT}")
+endif()
+if(FFMPEG_LIBAVUTIL)
+  list(APPEND FFMPEG_LIBRARIES "${FFMPEG_LIBAVUTIL}")
+endif()
+
+if(APPLE)
+  # When statically built for Apple, FFMPEG may have dependencies on these
+  # additional frameworks and libraries.
+
+  find_library(APPLE_COREVIDEO_LIBRARY CoreVideo)
+  if(APPLE_COREVIDEO_LIBRARY)
+    list(APPEND FFMPEG_LIBRARIES "${APPLE_COREVIDEO_LIBRARY}")
+  endif()
+
+  find_library(APPLE_VDA_LIBRARY VideoDecodeAcceleration)
+  if(APPLE_VDA_LIBRARY)
+    list(APPEND FFMPEG_LIBRARIES "${APPLE_VDA_LIBRARY}")
+  endif()
+
+  find_library(APPLE_ICONV_LIBRARY iconv)
+  if(APPLE_ICONV_LIBRARY)
+    list(APPEND FFMPEG_LIBRARIES "${APPLE_ICONV_LIBRARY}")
+  endif()
+
+  find_library(APPLE_BZ2_LIBRARY bz2)
+  if(APPLE_BZ2_LIBRARY)
+    list(APPEND FFMPEG_LIBRARIES "${APPLE_BZ2_LIBRARY}")
+  endif()
+endif()
+
+mark_as_advanced(FFMPEG_LIBRARY_DIR)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FFMPEG DEFAULT_MSG FFMPEG_LIBRARIES FFMPEG_LIBAVCODEC FFMPEG_LIBAVFORMAT FFMPEG_LIBAVUTIL FFMPEG_INCLUDE_DIR FFMPEG_LIBRARY_DIR)

+ 107 - 0
cmake/modules/FindFFTW3.cmake

@@ -0,0 +1,107 @@
+# Filename: FindFFTW.cmake
+# Author: Unknown (???), kestred (29 Nov, 2013)
+#
+# Usage:
+#   find_package(FFTW [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   FFTW3_FOUND       - true if fftw is found on the system
+#   FFTW3_INCLUDE_DIR - the fftw include directory
+#   FFTW3_LIBRARY_DIR - the fftw library directory
+#   FFTW3_LIBRARY     - the path to the library binary
+#
+# The following variables will be checked by the function
+#   FFTW3_ROOT - if set, the libraries are exclusively searched under this path
+#
+
+# Check if we can use PkgConfig
+find_package(PkgConfig QUIET)
+
+#Determine from PKG
+if(PKG_CONFIG_FOUND AND NOT FFTW3_ROOT)
+  pkg_check_modules(PKG_FFTW QUIET "fftw3")
+endif()
+
+if(FFTW3_ROOT)
+  # Try to find headers under root
+  find_path(FFTW3_INCLUDE_DIR
+    NAMES "fftw3.h"
+    PATHS ${FFTW3_ROOT}
+    PATH_SUFFIXES "include"
+    NO_DEFAULT_PATH
+  )
+
+  # Try to find library under root
+  find_library(FFTW3_LIBRARY
+    NAMES "fftw3"
+    PATHS ${FFTW3_ROOT}
+    PATH_SUFFIXES "lib" "lib64"
+    NO_DEFAULT_PATH
+  )
+
+  find_library(FFTW3_FFTWF_LIBRARY
+    NAMES "fftw3f"
+    PATHS ${FFTW3_ROOT}
+    PATH_SUFFIXES "lib" "lib64"
+    NO_DEFAULT_PATH
+  )
+
+  find_library(FFTW3_FFTWL_LIBRARY
+    NAMES "fftw3l"
+    PATHS ${FFTW3_ROOT}
+    PATH_SUFFIXES "lib" "lib64"
+    NO_DEFAULT_PATH
+  )
+else()
+  # Find headers the normal way
+  find_path(FFTW3_INCLUDE_DIR
+    NAMES "fftw3.h"
+    PATHS ${PKG_FFTW3_INCLUDE_DIRS}
+          ${INCLUDE_INSTALL_DIR}
+          "/usr/include"
+          "/usr/local/include"
+    PATH_SUFFIXES "" "fftw"
+  )
+
+  # Find library the normal way
+  find_library(FFTW3_LIBRARY
+    NAMES "fftw3"
+    PATHS ${PKG_FFTW3_LIBRARY_DIRS}
+          ${LIB_INSTALL_DIR}
+          "/usr"
+          "/usr/local"
+    PATH_SUFFIXES "" "lib" "lib32" "lib64"
+  )
+
+  find_library(FFTW3_FFTWF_LIBRARY
+    NAMES "fftw3f"
+    PATHS ${PKG_FFTW3_LIBRARY_DIRS}
+          ${LIB_INSTALL_DIR}
+          "/usr"
+          "/usr/local"
+    PATH_SUFFIXES "" "lib" "lib32" "lib64"
+  )
+
+
+  find_library(FFTW3_FFTWL_LIBRARY
+    NAMES "fftw3l"
+    PATHS ${PKG_FFTW3_LIBRARY_DIRS}
+          ${LIB_INSTALL_DIR}
+          "/usr"
+          "/usr/local"
+    PATH_SUFFIXES "" "lib" "lib32" "lib64"
+  )
+endif()
+
+# Get the directory conaining FFTW3_LIBRARY
+get_filename_component(FFTW3_LIBRARY_DIR "${FFTW3_LIBRARY}" PATH)
+set(FFTW3_LIBRARY_DIR "${FFTW3_LIBRARY_DIR}" CACHE PATH "The path to fftw's library directory.") # Library path
+
+mark_as_advanced(FFTW3_INCLUDE_DIR)
+mark_as_advanced(FFTW3_LIBRARY_DIR)
+mark_as_advanced(FFTW3_LIBRARY)
+mark_as_advanced(FFTW3_FFTWF_LIBRARY)
+mark_as_advanced(FFTW3_FFTWL_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FFTW3 DEFAULT_MSG FFTW3_LIBRARY FFTW3_INCLUDE_DIR FFTW3_LIBRARY_DIR)

+ 83 - 0
cmake/modules/FindFMODEx.cmake

@@ -0,0 +1,83 @@
+# Filename: FindFMODEx.cmake
+# Author: kestred (8 Dec, 2013)
+#
+# Usage:
+#   find_pcackage(FMODEx [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   FMODEX_FOUND       - system has FMOD Ex
+#   FMODEX_INCLUDE_DIR - the FMOD Ex include directory
+#   FMODEX_LIBRARY_DIR - the FMOD Ex library directory
+#   FMODEX_LIBRARY     - the path to the library binary
+#
+#   FMODEX_32_LIBRARY - the filepath of the FMOD Ex SDK 32-bit library
+#   FMOXEX_64_LIBRARY - the filepath of the FMOD Ex SDK 64-bit library
+#
+
+# Find the include directory
+find_path(FMODEX_INCLUDE_DIR
+  NAMES "fmod.h"
+  PATHS "/usr/include"
+        "/usr/local/include"
+        "/sw/include"
+        "/opt/include"
+        "/opt/local/include"
+        "/opt/csw/include"
+        "/opt/fmodex/include"
+        "/opt/fmodex/api/inc"
+        "C:/Program Files (x86)/FMOD SoundSystem/FMOD Programmers API Win32/api/inc"
+  PATH_SUFFIXES "" "fmodex/fmod" "fmodex/fmod3" "fmod" "fmod3"
+  DOC "The path to FMOD Ex's include directory."
+)
+
+# Find the 32-bit library
+find_library(FMODEX_32_LIBRARY
+  NAMES "fmodex_vc" "fmodex_bc" "fmodex" "fmodexL" "libfmodex" "libfmodexL" "fmodex_vc" "fmodexL_vc"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/X11R6"
+        "/usr/local/X11R6"
+        "/sw"
+        "/opt"
+        "/opt/local"
+        "/opt/csw"
+        "/opt/fmodex"
+        "/opt/fmodex/api"
+        "C:/Program Files (x86)/FMOD SoundSystem/FMOD Programmers API Win32/api/lib"
+  PATH_SUFFIXES "" "lib" "lib32"
+)
+
+# Find the 64-bit library
+find_library(FMODEX_64_LIBRARY
+  NAMES "fmodex64" "libfmodex64" "fmodexL64" "libfmodexL64" "fmodex64_vc" "fmodexL64_vc"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/X11R6"
+        "/usr/local/X11R6"
+        "/sw"
+        "/opt"
+        "/opt/local"
+        "/opt/csw"
+        "/opt/fmodex"
+        "/opt/fmodex/api"
+        "/usr/freeware"
+  PATH_SUFFIXES "" "lib" "lib64"
+)
+
+if(FMODEX_32_LIBRARY)
+  set(FMODEX_LIBRARY ${FMODEX_32_LIBRARY} CACHE FILEPATH "The filepath to FMOD Ex's library binary.")
+elseif(FMODEX_64_LIBRARY)
+  set(FMODEX_LIBRARY ${FMODEX_64_LIBRARY} CACHE FILEPATH "The filepath to FMOD Ex's library binary.")
+endif()
+
+get_filename_component(FMODEX_LIBRARY_DIR "${FMODEX_LIBRARY}" PATH)
+set(FMODEX_LIBRARY_DIR "${FMODEX_LIBRARY_DIR}" CACHE PATH "The path to FMOD Ex's library directory.")
+
+mark_as_advanced(FMODEX_INCLUDE_DIR)
+mark_as_advanced(FMODEX_LIBRARY_DIR)
+mark_as_advanced(FMODEX_LIBRARY)
+mark_as_advanced(FMODEX_32_LIBRARY)
+mark_as_advanced(FMODEX_64_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FMODEx DEFAULT_MSG FMODEX_LIBRARY FMODEX_INCLUDE_DIR FMODEX_LIBRARY_DIR)

+ 23 - 0
cmake/modules/FindHarfBuzz.cmake

@@ -0,0 +1,23 @@
+# Filename: FindHarfBuzz.cmake
+# Authors: CFSworks (2 Nov, 2018)
+#
+# Usage:
+#   find_package(HarfBuzz [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   HARFBUZZ_FOUND       - system has HarfBuzz
+#   HARFBUZZ_INCLUDE_DIR - the include directory containing hb.h
+#   HARFBUZZ_LIBRARY     - the path to the HarfBuzz library
+#
+
+find_path(HARFBUZZ_INCLUDE_DIR
+  NAMES "hb.h"
+  PATH_SUFFIXES "harfbuzz")
+
+find_library(HARFBUZZ_LIBRARY
+  NAMES "harfbuzz")
+
+mark_as_advanced(HARFBUZZ_INCLUDE_DIR HARFBUZZ_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(HarfBuzz DEFAULT_MSG HARFBUZZ_INCLUDE_DIR HARFBUZZ_LIBRARY)

+ 78 - 0
cmake/modules/FindLibSquish.cmake

@@ -0,0 +1,78 @@
+# Filename: FindLibSquish.cmake
+# Author: kestred (7 Dec, 2013)
+#
+# Usage:
+#   find_package(LibSquish [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   LIBSQUISH_FOUND       - system has libsquish
+#   LIBSQUISH_INCLUDE_DIR - the libsquish include directory
+#   LIBSQUISH_LIBRARY_DIR - the libsquish library directory
+#   LIBSQUISH_LIBRARY     - the path to the library binary
+#
+#   LIBSQUISH_RELEASE_LIBRARY - the filepath of the libsquish release library
+#   LIBSQUISH_DEBUG_LIBRARY   - the filepath of the libsquish debug library
+#
+
+# Find the libsquish include files
+find_path(LIBSQUISH_INCLUDE_DIR
+  NAMES "squish.h"
+  PATHS "/usr/include"
+        "/usr/local/include"
+        "/sw/include"
+        "/opt/include"
+        "/opt/local/include"
+        "/opt/csw/include"
+  PATH_SUFFIXES "" "cppunit"
+)
+
+# Find the libsquish library built for release
+find_library(LIBSQUISH_RELEASE_LIBRARY
+  NAMES "squish" "libsquish"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/freeware"
+        "/sw"
+        "/opt"
+        "/opt/csw"
+  PATH_SUFFIXES "lib" "lib32" "lib64"
+)
+
+# Find the libsquish library built for debug
+find_library(LIBSQUISH_DEBUG_LIBRARY
+  NAMES "squishd" "libsquishd"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/freeware"
+        "/sw"
+        "/opt"
+        "/opt/csw"
+  PATH_SUFFIXES "lib" "lib32" "lib64"
+)
+
+
+mark_as_advanced(LIBSQUISH_INCLUDE_DIR)
+mark_as_advanced(LIBSQUISH_RELEASE_LIBRARY)
+mark_as_advanced(LIBSQUISH_DEBUG_LIBRARY)
+
+# Choose library
+if(CMAKE_BUILD_TYPE MATCHES "Debug" AND LIBSQUISH_DEBUG_LIBRARY)
+	set(LIBSQUISH_LIBRARY ${LIBSQUISH_DEBUG_LIBRARY} CACHE FILEPATH "The filepath to libsquish's library binary.")
+elseif(LIBSQUISH_RELEASE_LIBRARY)
+	set(LIBSQUISH_LIBRARY ${LIBSQUISH_RELEASE_LIBRARY} CACHE FILEPATH "The filepath to libsquish's library binary.")
+elseif(LIBSQUISH_DEBUG_LIBRARY)
+	set(LIBSQUISH_LIBRARY ${LIBSQUISH_DEBUG_LIBRARY} CACHE FILEPATH "The filepath to libsquish's library binary.")
+endif()
+
+# Translate library into library directory
+if(LIBSQUISH_LIBRARY)
+	unset(LIBSQUISH_LIBRARY_DIR CACHE)
+	get_filename_component(LIBSQUISH_LIBRARY_DIR "${LIBSQUISH_LIBRARY}" PATH)
+	set(LIBSQUISH_LIBRARY_DIR "${LIBSQUISH_LIBRARY_DIR}" CACHE PATH "The path to libsquish's library directory.") # Library path
+endif()
+
+mark_as_advanced(LIBSQUISH_LIBRARY)
+mark_as_advanced(LIBSQUISH_LIBRARY_DIR)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LibSquish DEFAULT_MSG LIBSQUISH_LIBRARY LIBSQUISH_INCLUDE_DIR LIBSQUISH_LIBRARY_DIR)

+ 157 - 0
cmake/modules/FindODE.cmake

@@ -0,0 +1,157 @@
+# Filename: FindODE.cmake
+# Author: CFSworks (7 Feb, 2014)
+#
+# Usage:
+#   find_package(ODE [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   ODE_FOUND       - system has ode
+#   ODE_INCLUDE_DIR - the ode include directory
+#
+#   ODE_RELEASE_LIBRARY - the filepath of the ode release library
+#   ODE_DEBUG_LIBRARY   - the filepath of the ode debug library
+#
+#   ODE_SINGLE_DEBUG_LIBRARY   - the filepath of the single-precision ode debug library
+#   ODE_SINGLE_RELEASE_LIBRARY   - the filepath of the single-precision ode release library
+#   ODE_DOUBLE_DEBUG_LIBRARY   - the filepath of the double-precision ode debug library
+#   ODE_DOUBLE_RELEASE_LIBRARY   - the filepath of the double-precision ode release library
+#
+#   ODE::ODE        - The recommended ODE library to link against
+#   ODE::ODE_single - If available, this links against single-precision ODE
+#   ODE::ODE_double - If available, this links against double-precision ODE
+#
+
+# Find the libode include files
+find_path(ODE_INCLUDE_DIR "ode/ode.h")
+
+# Find the libode library built for release
+find_library(ODE_RELEASE_LIBRARY
+  NAMES "ode" "libode")
+
+# Find the libode library built for debug
+find_library(ODE_DEBUG_LIBRARY
+  NAMES "oded" "liboded")
+
+# Find the single-precision library built for release
+find_library(ODE_SINGLE_RELEASE_LIBRARY
+  NAMES "ode_single" "libode_single")
+
+# Find the single-precision library built for debug
+find_library(ODE_SINGLE_DEBUG_LIBRARY
+  NAMES "ode_singled" "libode_singled")
+
+# Find the double-precision library built for release
+find_library(ODE_DOUBLE_RELEASE_LIBRARY
+  NAMES "ode_double" "libode_double")
+
+# Find the double-precision library built for debug
+find_library(ODE_DOUBLE_DEBUG_LIBRARY
+  NAMES "ode_doubled" "libode_doubled")
+
+# Find libccd, which ODE sometimes links against, so we want to let the linker
+# know about it if it's present.
+find_library(ODE_LIBCCD_LIBRARY
+  NAMES "ccd" "libccd")
+
+mark_as_advanced(ODE_INCLUDE_DIR)
+mark_as_advanced(ODE_RELEASE_LIBRARY)
+mark_as_advanced(ODE_DEBUG_LIBRARY)
+mark_as_advanced(ODE_SINGLE_RELEASE_LIBRARY)
+mark_as_advanced(ODE_SINGLE_DEBUG_LIBRARY)
+mark_as_advanced(ODE_DOUBLE_RELEASE_LIBRARY)
+mark_as_advanced(ODE_DOUBLE_DEBUG_LIBRARY)
+mark_as_advanced(ODE_LIBCCD_LIBRARY)
+
+# Define targets for both precisions (and unspecified)
+foreach(_precision _single _double "")
+  string(TOUPPER "${_precision}" _PRECISION)
+
+  if(EXISTS "${ODE${_PRECISION}_RELEASE_LIBRARY}" OR
+      EXISTS "${ODE${_PRECISION}_DEBUG_LIBRARY}")
+    if(NOT TARGET ODE::ODE${_precision})
+      add_library(ODE::ODE${_precision} UNKNOWN IMPORTED GLOBAL)
+
+      set_target_properties(ODE::ODE${_precision} PROPERTIES
+        INTERFACE_INCLUDE_DIRECTORIES "${ODE_INCLUDE_DIR}")
+
+      if(ODE_LIBCCD_LIBRARY)
+        set_target_properties(ODE::ODE${_precision} PROPERTIES
+          INTERFACE_LINK_LIBRARIES "${ODE_LIBCCD_LIBRARY}")
+      endif()
+
+      if(EXISTS "${ODE${_PRECISION}_RELEASE_LIBRARY}")
+        set_property(TARGET ODE::ODE${_precision} APPEND PROPERTY
+          IMPORTED_CONFIGURATIONS RELEASE)
+        set_target_properties(ODE::ODE${_precision} PROPERTIES
+          IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+          IMPORTED_LOCATION_RELEASE "${ODE${_PRECISION}_RELEASE_LIBRARY}")
+      endif()
+
+      if(EXISTS "${ODE${_PRECISION}_DEBUG_LIBRARY}")
+        set_property(TARGET ODE::ODE${_precision} APPEND PROPERTY
+          IMPORTED_CONFIGURATIONS DEBUG)
+        set_target_properties(ODE::ODE${_precision} PROPERTIES
+          IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+          IMPORTED_LOCATION_DEBUG "${ODE${_PRECISION}_DEBUG_LIBRARY}")
+      endif()
+
+      # If this has a precision, we should be sure to define
+      # dIDESINGLE/dIDEDOUBLE to keep it consistent
+      if(_precision)
+        string(REPLACE "_" "dIDE" _precision_symbol "${_PRECISION}")
+
+        set_target_properties(ODE::ODE${_precision} PROPERTIES
+          INTERFACE_COMPILE_DEFINITIONS "${_precision_symbol}")
+
+        unset(_precision_symbol)
+      endif()
+
+    endif()
+  endif()
+endforeach(_precision)
+unset(_precision)
+unset(_PRECISION)
+
+# OKAY.  If everything went well, we have ODE::ODE_single and/or
+# ODE::ODE_double.  We might even have an ODE::ODE, but if not, we need to
+# alias one of the other two to it.
+if(NOT TARGET ODE::ODE)
+  if(TARGET ODE::ODE_single)
+    set(_copy_from "ODE::ODE_single")
+  elseif(TARGET ODE::ODE_double)
+    set(_copy_from "ODE::ODE_double")
+  endif()
+
+  if(DEFINED _copy_from)
+    add_library(ODE::ODE UNKNOWN IMPORTED GLOBAL)
+
+    foreach(_prop
+        INTERFACE_INCLUDE_DIRECTORIES
+        INTERFACE_COMPILE_DEFINITIONS
+        INTERFACE_LINK_LIBRARIES
+        IMPORTED_CONFIGURATIONS
+        IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE
+        IMPORTED_LOCATION_RELEASE
+        IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG
+        IMPORTED_LOCATION_DEBUG)
+
+      get_target_property(_value "${_copy_from}" "${_prop}")
+      if(_value)
+        set_target_properties(ODE::ODE PROPERTIES "${_prop}" "${_value}")
+      endif()
+      unset(_value)
+    endforeach(_prop)
+    unset(_prop)
+  endif()
+
+  unset(_copy_from)
+endif()
+
+if(TARGET ODE::ODE)
+  set(_HAS_ODE_LIBRARY ON)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ODE DEFAULT_MSG ODE_INCLUDE_DIR _HAS_ODE_LIBRARY)
+
+unset(_HAS_ODE_LIBRARY)

+ 20 - 0
cmake/modules/FindOgg.cmake

@@ -0,0 +1,20 @@
+# Filename: FindOgg.cmake
+# Authors: CFSworks (13 Jan, 2019)
+#
+# Usage:
+#   find_package(Ogg [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   OGG_FOUND       - system has Ogg
+#   OGG_INCLUDE_DIR - the include directory containing ogg/
+#   OGG_LIBRARY     - the path to the ogg library
+#
+
+find_path(OGG_INCLUDE_DIR NAMES "ogg/ogg.h")
+
+find_library(OGG_LIBRARY NAMES "ogg" "libogg_static")
+
+mark_as_advanced(OGG_INCLUDE_DIR OGG_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Ogg DEFAULT_MSG OGG_INCLUDE_DIR OGG_LIBRARY)

+ 92 - 0
cmake/modules/FindOpenCV.cmake

@@ -0,0 +1,92 @@
+# Filename: FindOpenCV.cmake
+# Authors: CFSworks (3 Nov, 2018)
+#
+# Usage:
+#   find_package(OpenCV [REQUIRED] [QUIET])
+#
+# This supports the following components:
+#   calib3d
+#   contrib
+#   core
+#   features2d
+#   flann
+#   gpu
+#   highgui
+#   imgproc
+#   legacy
+#   ml
+#   nonfree
+#   objdetect
+#   photo
+#   stitching
+#   superres
+#   video
+#   videoio
+#   videostab
+#
+# Once done this will define:
+#   OPENCV_FOUND        - system has OpenCV
+#   OpenCV_INCLUDE_DIRS - the include dir(s) containing OpenCV header files
+#   OpenCV_comp_LIBRARY - the path to the OpenCV library for the particular
+#                         component
+#   OpenCV_LIBS         - the paths to the OpenCV libraries for the requested
+#                         component(s)
+#   OpenCV_VERSION_MAJOR- a "best guess" of the major version (X.x)
+#   OpenCV_VERSION_MINOR- a "best guess" of the minor version (x.X)
+#
+
+set(OpenCV_INCLUDE_DIRS)
+
+find_path(OpenCV_V1_INCLUDE_DIR
+  NAMES "cv.h"
+  PATH_SUFFIXES "opencv")
+mark_as_advanced(OpenCV_V1_INCLUDE_DIR)
+if(OpenCV_V1_INCLUDE_DIR)
+  list(APPEND OpenCV_INCLUDE_DIRS "${OpenCV_V1_INCLUDE_DIR}")
+
+  # This is a wild guess:
+  set(OpenCV_VERSION_MAJOR 1)
+  set(OpenCV_VERSION_MINOR 0)
+endif()
+
+find_path(OpenCV_V2_INCLUDE_DIR "opencv2/core/version.hpp")
+mark_as_advanced(OpenCV_V2_INCLUDE_DIR)
+if(OpenCV_V2_INCLUDE_DIR)
+  list(APPEND OpenCV_INCLUDE_DIRS "${OpenCV_V2_INCLUDE_DIR}")
+
+  file(STRINGS "${OpenCV_V2_INCLUDE_DIR}/opencv2/core/version.hpp"
+    _version_major REGEX "#define CV_VERSION_EPOCH")
+  file(STRINGS "${OpenCV_V2_INCLUDE_DIR}/opencv2/core/version.hpp"
+    _version_minor REGEX "#define CV_VERSION_MAJOR")
+
+  string(REGEX REPLACE "[^0-9]" "" OpenCV_VERSION_MAJOR "${_version_major}")
+  string(REGEX REPLACE "[^0-9]" "" OpenCV_VERSION_MINOR "${_version_minor}")
+  unset(_version_major)
+  unset(_version_minor)
+endif()
+
+set(OpenCV_LIBS)
+foreach(_component calib3d contrib core features2d flann gpu highgui imgproc
+                  legacy ml nonfree objdetect photo stitching superres video
+                  videoio videostab)
+
+  list(FIND OpenCV_FIND_COMPONENTS "${_component}" _index)
+  if(_index GREATER -1 OR _component STREQUAL "core")
+    if(NOT OpenCV_${_component}_LIBRARY)
+      find_library(OpenCV_${_component}_LIBRARY
+        NAMES "opencv_${_component}")
+    endif()
+
+    if(OpenCV_${_component}_LIBRARY)
+      list(APPEND OpenCV_LIBS "${OpenCV_${_component}_LIBRARY}")
+      set(OpenCV_${_component}_FOUND ON)
+    endif()
+  endif()
+  unset(_index)
+endforeach(_component)
+unset(_component)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OpenCV HANDLE_COMPONENTS
+  REQUIRED_VARS OpenCV_INCLUDE_DIRS OpenCV_LIBS
+  OpenCV_VERSION_MAJOR OpenCV_VERSION_MINOR)

+ 88 - 0
cmake/modules/FindOpenEXR.cmake

@@ -0,0 +1,88 @@
+# Filename: FindOpenEXR.cmake
+# Authors: CFSworks (5 Nov, 2018)
+#
+# Usage:
+#   find_package(OpenEXR [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   OPENEXR_FOUND       - system has OpenEXR
+#   OPENEXR_INCLUDE_DIR - the include directory containing OpenEXR header files
+#   OPENEXR_LIBRARIES   - the path to the OpenEXR libraries
+#
+
+find_path(OPENEXR_INCLUDE_DIR
+  "ImfVersion.h"
+  PATH_SUFFIXES "OpenEXR")
+
+mark_as_advanced(OPENEXR_INCLUDE_DIR)
+
+find_library(OPENEXR_imf_LIBRARY
+  NAMES "IlmImf")
+
+if(OPENEXR_imf_LIBRARY)
+  get_filename_component(_imf_dir "${OPENEXR_imf_LIBRARY}" DIRECTORY)
+  find_library(OPENEXR_imfutil_LIBRARY
+    NAMES "IlmImfUtil"
+    PATHS "${_imf_dir}"
+    NO_DEFAULT_PATH)
+
+  find_library(OPENEXR_ilmthread_LIBRARY
+    NAMES "IlmThread"
+    PATHS "${_imf_dir}"
+    NO_DEFAULT_PATH)
+
+  find_library(OPENEXR_iex_LIBRARY
+    NAMES "Iex"
+    PATHS "${_imf_dir}"
+    NO_DEFAULT_PATH)
+
+  find_library(OPENEXR_iexmath_LIBRARY
+    NAMES "IexMath"
+    PATHS "${_imf_dir}"
+    NO_DEFAULT_PATH)
+
+  find_library(OPENEXR_imath_LIBRARY
+    NAMES "Imath"
+    PATHS "${_imf_dir}"
+    NO_DEFAULT_PATH)
+
+  find_library(OPENEXR_half_LIBRARY
+    NAMES "Half"
+    PATHS "${_imf_dir}"
+    NO_DEFAULT_PATH)
+
+  unset(_imf_dir)
+endif()
+
+mark_as_advanced(
+  OPENEXR_imf_LIBRARY
+  OPENEXR_imfutil_LIBRARY
+  OPENEXR_ilmthread_LIBRARY
+  OPENEXR_iex_LIBRARY
+  OPENEXR_iexmath_LIBRARY
+  OPENEXR_imath_LIBRARY
+  OPENEXR_half_LIBRARY
+)
+
+set(OPENEXR_LIBRARIES
+  ${OPENEXR_imf_LIBRARY}
+  ${OPENEXR_imfutil_LIBRARY}
+  ${OPENEXR_ilmthread_LIBRARY}
+  ${OPENEXR_iex_LIBRARY}
+  ${OPENEXR_iexmath_LIBRARY}
+  ${OPENEXR_imath_LIBRARY}
+  ${OPENEXR_half_LIBRARY}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OpenEXR DEFAULT_MSG
+  OPENEXR_INCLUDE_DIR OPENEXR_LIBRARIES
+
+  OPENEXR_imf_LIBRARY
+  OPENEXR_imfutil_LIBRARY
+  OPENEXR_ilmthread_LIBRARY
+  OPENEXR_iex_LIBRARY
+  OPENEXR_iexmath_LIBRARY
+  OPENEXR_imath_LIBRARY
+  OPENEXR_half_LIBRARY
+)

+ 21 - 0
cmake/modules/FindOpenGLES1.cmake

@@ -0,0 +1,21 @@
+# Filename: FindOpenGLES1.cmake
+# Authors: CFSworks (21 Oct, 2018)
+#
+# Usage:
+#   find_package(OpenGLES1 [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   OPENGLES1_FOUND       - system has OpenGL ES 1.x
+#   OPENGLES1_INCLUDE_DIR - the include directory containing GLES/gl.h
+#   OPENGLES1_LIBRARY     - the library to link against for OpenGL ES 1.x
+#
+
+find_path(OPENGLES1_INCLUDE_DIR "GLES/gl.h")
+
+find_library(OPENGLES1_LIBRARY
+  NAMES "GLESv1" "GLESv1_CM" "GLES_CM")
+
+mark_as_advanced(OPENGLES1_INCLUDE_DIR OPENGLES1_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OpenGLES1 DEFAULT_MSG OPENGLES1_INCLUDE_DIR OPENGLES1_LIBRARY)

+ 21 - 0
cmake/modules/FindOpenGLES2.cmake

@@ -0,0 +1,21 @@
+# Filename: FindOpenGLES2.cmake
+# Authors: CFSworks (21 Oct, 2018)
+#
+# Usage:
+#   find_package(OpenGLES2 [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   OPENGLES2_FOUND        - system has OpenGL ES 2.x
+#   OPENGLES2_INCLUDE_DIR  - the include directory containing GLES2/gl2.h
+#   OPENGLES2_LIBRARY      - the library to link against for OpenGL ES 2.x
+#
+
+find_path(OPENGLES2_INCLUDE_DIR "GLES2/gl2.h")
+
+find_library(OPENGLES2_LIBRARY
+  NAMES "GLESv2")
+
+mark_as_advanced(OPENGLES2_INCLUDE_DIR OPENGLES2_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OpenGLES2 DEFAULT_MSG OPENGLES2_INCLUDE_DIR OPENGLES2_LIBRARY)

+ 34 - 0
cmake/modules/FindOpusFile.cmake

@@ -0,0 +1,34 @@
+# Filename: FindOpusFile.cmake
+# Authors: CFSworks (13 Jan, 2019)
+#
+# Usage:
+#   find_package(OpusFile [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   OPUSFILE_FOUND        - system has Ogg and opusfile
+#   OPUSFILE_INCLUDE_DIRS - the include directory/ies containing opus/ and ogg/
+#   OPUSFILE_LIBRARIES    - the paths to the opus and opusfile libraries
+#
+
+# Find Ogg
+find_package(Ogg QUIET)
+
+# Find Opus
+find_path(OPUS_INCLUDE_DIR NAMES "opus/opusfile.h")
+
+find_library(OPUS_opus_LIBRARY NAMES "opus")
+find_library(OPUS_opusfile_LIBRARY NAMES "opusfile")
+
+mark_as_advanced(OPUS_INCLUDE_DIR OPUS_opus_LIBRARY OPUS_opusfile_LIBRARY)
+
+# Define output variables
+set(OPUSFILE_INCLUDE_DIRS ${OPUS_INCLUDE_DIR} "${OPUS_INCLUDE_DIR}/opus")
+if(NOT OGG_INCLUDE_DIR STREQUAL OPUS_INCLUDE_DIR)
+  list(APPEND OPUSFILE_INCLUDE_DIRS ${OGG_INCLUDE_DIR})
+endif()
+set(OPUSFILE_LIBRARIES ${OPUS_opusfile_LIBRARY} ${OPUS_opus_LIBRARY} ${OGG_LIBRARY})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(OpusFile DEFAULT_MSG
+  Ogg_FOUND
+  OPUS_INCLUDE_DIR OPUS_opus_LIBRARY OPUS_opusfile_LIBRARY)

+ 50 - 0
cmake/modules/FindSWResample.cmake

@@ -0,0 +1,50 @@
+# Filename: FindSWResample.cmake
+# Author: CFSworks (10 Apr, 2014)
+#
+# Usage:
+#   find_package(SWResample [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   SWRESAMPLE_FOUND       - system has ffmpeg's libswresample
+#   SWRESAMPLE_INCLUDE_DIR - the libswresample include directory
+#   SWRESAMPLE_LIBRARY     - the path to the library binary
+#
+
+# Find the libswresample include files
+find_path(SWRESAMPLE_INCLUDE_DIR
+  NAMES "libswresample/swresample.h"
+  PATHS "/usr/include"
+        "/usr/local/include"
+        "/sw/include"
+        "/opt/include"
+        "/opt/local/include"
+        "/opt/csw/include"
+  PATH_SUFFIXES "libav" "ffmpeg"
+)
+
+# Find the libswresample library
+find_library(SWRESAMPLE_LIBRARY
+  NAMES "swresample"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/freeware"
+        "/sw"
+        "/opt"
+        "/opt/csw"
+  PATH_SUFFIXES "lib" "lib32" "lib64"
+)
+
+mark_as_advanced(SWRESAMPLE_INCLUDE_DIR)
+mark_as_advanced(SWRESAMPLE_LIBRARY)
+
+# Translate library into library directory
+if(SWRESAMPLE_LIBRARY)
+  unset(SWRESAMPLE_LIBRARY_DIR CACHE)
+  get_filename_component(SWRESAMPLE_LIBRARY_DIR "${SWRESAMPLE_LIBRARY}" PATH)
+  set(SWRESAMPLE_LIBRARY_DIR "${SWRESAMPLE_LIBRARY_DIR}" CACHE PATH "The path to libffmpeg's library directory.") # Library path
+endif()
+
+mark_as_advanced(SWRESAMPLE_LIBRARY_DIR)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SWResample DEFAULT_MSG SWRESAMPLE_LIBRARY SWRESAMPLE_INCLUDE_DIR SWRESAMPLE_LIBRARY_DIR)

+ 50 - 0
cmake/modules/FindSWScale.cmake

@@ -0,0 +1,50 @@
+# Filename: FindSWScale.cmake
+# Author: CFSworks (10 Apr, 2014)
+#
+# Usage:
+#   find_package(SWScale [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   SWSCALE_FOUND       - system has ffmpeg's libswscale
+#   SWSCALE_INCLUDE_DIR - the libswscale include directory
+#   SWSCALE_LIBRARY     - the path to the library binary
+#
+
+# Find the libswscale include files
+find_path(SWSCALE_INCLUDE_DIR
+  NAMES "libswscale/swscale.h"
+  PATHS "/usr/include"
+        "/usr/local/include"
+        "/sw/include"
+        "/opt/include"
+        "/opt/local/include"
+        "/opt/csw/include"
+  PATH_SUFFIXES "libav" "ffmpeg"
+)
+
+# Find the libswscale library
+find_library(SWSCALE_LIBRARY
+  NAMES "swscale"
+  PATHS "/usr"
+        "/usr/local"
+        "/usr/freeware"
+        "/sw"
+        "/opt"
+        "/opt/csw"
+  PATH_SUFFIXES "lib" "lib32" "lib64"
+)
+
+mark_as_advanced(SWSCALE_INCLUDE_DIR)
+mark_as_advanced(SWSCALE_LIBRARY)
+
+# Translate library into library directory
+if(SWSCALE_LIBRARY)
+  unset(SWSCALE_LIBRARY_DIR CACHE)
+  get_filename_component(SWSCALE_LIBRARY_DIR "${SWSCALE_LIBRARY}" PATH)
+  set(SWSCALE_LIBRARY_DIR "${SWSCALE_LIBRARY_DIR}" CACHE PATH "The path to libffmpeg's library directory.") # Library path
+endif()
+
+mark_as_advanced(SWSCALE_LIBRARY_DIR)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(SWScale DEFAULT_MSG SWSCALE_LIBRARY SWSCALE_INCLUDE_DIR SWSCALE_LIBRARY_DIR)

+ 40 - 0
cmake/modules/FindVRPN.cmake

@@ -0,0 +1,40 @@
+# Filename: FindVRPN.cmake
+# Authors: CFSworks (2 Nov, 2018)
+#
+# Usage:
+#   find_package(VRPN [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   VRPN_FOUND       - system has VRPN
+#   VRPN_INCLUDE_DIR - the include directory containing VRPN header files
+#   VRPN_LIBRARIES   - the path to the VRPN client libraries
+#
+
+find_path(VRPN_INCLUDE_DIR "vrpn_Connection.h")
+
+find_library(VRPN_vrpn_LIBRARY
+  NAMES "vrpn")
+
+mark_as_advanced(VRPN_INCLUDE_DIR VRPN_vrpn_LIBRARY)
+
+if(VRPN_vrpn_LIBRARY)
+  get_filename_component(_vrpn_dir "${VRPN_vrpn_LIBRARY}" DIRECTORY)
+  find_library(VRPN_quat_LIBRARY
+    NAMES "quat"
+    PATHS "${_vrpn_dir}"
+    NO_DEFAULT_PATH)
+
+  unset(_vrpn_dir)
+  mark_as_advanced(VRPN_quat_LIBRARY)
+endif()
+
+set(VRPN_LIBRARIES)
+if(VRPN_vrpn_LIBRARY)
+  list(APPEND VRPN_LIBRARIES "${VRPN_vrpn_LIBRARY}")
+endif()
+if(VRPN_quat_LIBRARY)
+  list(APPEND VRPN_LIBRARIES "${VRPN_quat_LIBRARY}")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(VRPN DEFAULT_MSG VRPN_INCLUDE_DIR VRPN_LIBRARIES)

+ 34 - 0
cmake/modules/FindVorbisFile.cmake

@@ -0,0 +1,34 @@
+# Filename: FindVorbisFile.cmake
+# Authors: CFSworks (13 Jan, 2019)
+#
+# Usage:
+#   find_package(VorbisFile [REQUIRED] [QUIET])
+#
+# Once done this will define:
+#   VORBISFILE_FOUND        - system has Ogg and vorbisfile
+#   VORBISFILE_INCLUDE_DIRS - the include directory/ies containing vorbis/ and ogg/
+#   VORBISFILE_LIBRARIES    - the paths to the vorbis and vorbisfile libraries
+#
+
+# Find Ogg
+find_package(Ogg QUIET)
+
+# Find Vorbis
+find_path(VORBIS_INCLUDE_DIR NAMES "vorbis/vorbisfile.h")
+
+find_library(VORBIS_vorbis_LIBRARY NAMES "vorbis" "libvorbis_static")
+find_library(VORBIS_vorbisfile_LIBRARY NAMES "vorbisfile" "libvorbisfile_static")
+
+mark_as_advanced(VORBIS_INCLUDE_DIR VORBIS_vorbis_LIBRARY VORBIS_vorbisfile_LIBRARY)
+
+# Define output variables
+set(VORBISFILE_INCLUDE_DIRS ${VORBIS_INCLUDE_DIR})
+if(NOT OGG_INCLUDE_DIR STREQUAL VORBIS_INCLUDE_DIR)
+  list(APPEND VORBISFILE_INCLUDE_DIRS ${OGG_INCLUDE_DIR})
+endif()
+set(VORBISFILE_LIBRARIES ${VORBIS_vorbisfile_LIBRARY} ${VORBIS_vorbis_LIBRARY} ${OGG_LIBRARY})
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(VorbisFile DEFAULT_MSG
+  Ogg_FOUND
+  VORBIS_INCLUDE_DIR VORBIS_vorbis_LIBRARY VORBIS_vorbisfile_LIBRARY)

+ 7 - 0
cmake/modules/README.md

@@ -0,0 +1,7 @@
+Directory Info
+--------------
+**Directory:** /cmake/modules
+**License:** Unlicense  
+**Description:** This directory is used for standard CMake modules which are safe
+to use outside of a Panda3D project.  This should be the normal location for
+most FindXYZZY packages that are written for Panda3D.

+ 70 - 0
cmake/scripts/ConcatenateToCXX.cmake

@@ -0,0 +1,70 @@
+# Filename: ConcatenateToCXX.cmake
+#
+# Description: When run, creates a single C++ file which includes a const char[]
+#   containing the bytes from one or more files.
+#
+#   There is a {SYMBOL_NAME}_size symbol defined as well, storing the total
+#   number of bytes in the concatenated input files.
+#
+#   A single null terminator byte is added for the benefit of programs that
+#   simply treat the data array as a string.
+#
+# Usage:
+#   This script is invoked via add_custom_target, like this:
+#   cmake -D OUTPUT_FILE="out.cxx" -D SYMBOL_NAME=data -D INPUT_FILES="a.bin b.bin" -P ConcatenateToCXX.cmake
+#
+
+if(NOT CMAKE_SCRIPT_MODE_FILE)
+  message(FATAL_ERROR "ConcatenateToCXX.cmake should not be included but run in script mode.")
+  return()
+endif()
+
+if(NOT DEFINED OUTPUT_FILE)
+  message(FATAL_ERROR "OUTPUT_FILE should be defined when running ConcatenateToCXX.cmake!")
+  return()
+endif()
+
+if(NOT DEFINED SYMBOL_NAME)
+  set(SYMBOL_NAME "data")
+endif()
+
+file(WRITE "${OUTPUT_FILE}" "/* Generated by CMake.  DO NOT EDIT. */
+
+extern const char ${SYMBOL_NAME}[];
+extern const int ${SYMBOL_NAME}_size;
+
+const char ${SYMBOL_NAME}[] = {\n")
+
+set(byte_count 0)
+separate_arguments(INPUT_FILES)
+foreach(infile ${INPUT_FILES})
+  file(APPEND "${OUTPUT_FILE}" "  /* ${infile} */\n")
+
+  set(offset 0)
+  while(1)
+    # Read up to 1024 bytes from the input file
+    file(READ "${infile}" data LIMIT 1024 OFFSET ${offset} HEX)
+    math(EXPR offset "${offset} + 1024")
+
+    # If 'data' is empty, we're done
+    if(NOT data)
+      break()
+    endif()
+
+    # Count the bytes we're adding
+    string(LENGTH "${data}" strlen)
+    math(EXPR byte_count "${byte_count} + (${strlen} / 2)")
+
+    # Format runs of up to 32 hex chars by indenting and giving a newline
+    string(REGEX REPLACE
+      "(...?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?.?)" " \\1\n"
+      data "${data}")
+    # Format each byte (2 hex chars) in each line with 0x prefix and comma suffix
+    string(REGEX REPLACE "([0-9a-fA-F][0-9a-fA-F])" " 0x\\1," data "${data}")
+    file(APPEND "${OUTPUT_FILE}" "${data}")
+  endwhile()
+endforeach(infile)
+
+file(APPEND "${OUTPUT_FILE}" "  0\n};
+
+extern const int ${SYMBOL_NAME}_size = ${byte_count};\n")

+ 27 - 0
cmake/scripts/CopyPattern.cmake

@@ -0,0 +1,27 @@
+# Filename: CopyPattern.cmake
+#
+# Description: This is a standalone version of CMake's file(COPY) command so we
+#              can use all of its features during build-time instead of
+#              config-time.
+#
+# Usage:
+#   This script is invoked via add_custom_target, like this:
+#   cmake -D SOURCE=[source directory]
+#         -D DESTINATION=[destination directory]
+#         -D FILES_MATCHING="[globbing patterns passed to file(COPY)]"
+#         -P CopyPattern.cmake
+if(NOT DEFINED SOURCE OR NOT DEFINED DESTINATION)
+    message(SEND_ERROR "CopyPattern.cmake requires SOURCE and DESTINATION to be
+defined.")
+endif()
+
+if(DEFINED FILES_MATCHING)
+  separate_arguments(FILES_MATCHING UNIX_COMMAND ${FILES_MATCHING})
+
+  file(COPY "${SOURCE}"
+       DESTINATION "${DESTINATION}"
+       FILES_MATCHING ${FILES_MATCHING})
+else()
+  file(COPY "${SOURCE}"
+       DESTINATION "${DESTINATION}")
+endif()

+ 78 - 0
cmake/scripts/CopyPython.cmake

@@ -0,0 +1,78 @@
+# Filename: CopyPython.cmake
+#
+# Description: When run, copies Python files from a source directory to a
+#   build directory located somewhere in the project's binary path. If
+#   PYTHON_EXECUTABLES is provided, it will also invoke compileall in the
+#   destination dir(s) to precache .pyc/.pyo files.
+#
+# Usage:
+#   This script is invoked via add_custom_target, like this:
+#   cmake -D OUTPUT_DIR="/out/dir/Release"
+#         -D SOURCE_DIR="/panda3d/direct/src/"
+#         -D PYTHON_EXECUTABLES="/usr/bin/python3.6"
+#         -P CopyPython.cmake
+#
+
+if(NOT CMAKE_SCRIPT_MODE_FILE)
+  message(FATAL_ERROR "CopyPython.cmake should not be included but run in script mode.")
+  return()
+endif()
+
+if(NOT DEFINED OUTPUT_DIR)
+  message(FATAL_ERROR "OUTPUT_DIR should be defined when running CopyPython.cmake!")
+  return()
+endif()
+
+# Ensure OUTPUT_DIR exists
+file(MAKE_DIRECTORY ${OUTPUT_DIR})
+
+# If there's a SOURCE_DIR, glob for .py files and copy
+# (this is done by hand to avoid the CMake bug where it creates empty dirs)
+if(DEFINED SOURCE_DIR)
+  file(GLOB_RECURSE py_files RELATIVE "${SOURCE_DIR}" "${SOURCE_DIR}/*.py")
+  foreach(py_file ${py_files})
+    get_filename_component(py_file_parent "${py_file}" DIRECTORY)
+    file(TIMESTAMP "${SOURCE_DIR}/${py_file}" src_stamp)
+    file(TIMESTAMP "${OUTPUT_DIR}/${py_file}" dst_stamp)
+
+    # The file is only copied if:
+    # - there's an __init__.py in its dir (or file is in the root) (i.e. file belongs to a package), and
+    # - the modification timestamp differs (i.e. file changed or never copied)
+    if((py_file_parent STREQUAL "." OR NOT py_file_parent
+        OR EXISTS "${SOURCE_DIR}/${py_file_parent}/__init__.py")
+       AND NOT src_stamp STREQUAL dst_stamp)
+
+      file(COPY "${SOURCE_DIR}/${py_file}" DESTINATION "${OUTPUT_DIR}/${py_file_parent}")
+      set(changed YES)
+    endif()
+
+  endforeach(py_file)
+
+else()
+  # No SOURCE_DIR; assume we're outdated since our caller might be populating
+  # the OUTPUT_DIR themselves
+  set(changed YES)
+
+endif()
+
+# Make sure Python recognizes OUTPUT_DIR as a package
+if(NOT EXISTS "${OUTPUT_DIR}/__init__.py")
+  file(WRITE "${OUTPUT_DIR}/__init__.py" "")
+  set(changed YES)
+endif()
+
+# Generate .pyc files for each Python version, if our caller wants
+if(changed AND DEFINED PYTHON_EXECUTABLES)
+  foreach(interp ${PYTHON_EXECUTABLES})
+    execute_process(
+      COMMAND "${interp}" -m compileall .
+      OUTPUT_QUIET
+      WORKING_DIRECTORY "${OUTPUT_DIR}")
+
+    execute_process(
+      COMMAND "${interp}" -O -m compileall .
+      OUTPUT_QUIET
+      WORKING_DIRECTORY "${OUTPUT_DIR}")
+
+  endforeach(interp)
+endif()

+ 28 - 0
cmake/scripts/MakeComposite.cmake

@@ -0,0 +1,28 @@
+# Filename: MakeComposite.cmake
+#
+# Description: When run, creates a single C++ file which includes multiple
+#   other C++ files, to help facilitate unity builds.
+#   Unity builds provide significantly increased compile speed.
+#
+# Usage:
+#   This script is invoked via add_custom_target, like this:
+#   cmake -P MakeComposite.cmake -D COMPOSITE_FILE="x_composite1.cxx" -D COMPOSITE_SOURCES="a.cxx b.cxx"
+#
+
+if(CMAKE_SCRIPT_MODE_FILE)
+  if(NOT DEFINED COMPOSITE_FILE)
+    message(FATAL_ERROR "COMPOSITE_FILE should be defined when running MakeComposite.cmake!")
+    return()
+  endif()
+
+  file(WRITE "${COMPOSITE_FILE}" "/* Generated by CMake.  DO NOT EDIT. */\n")
+
+  separate_arguments(COMPOSITE_SOURCES)
+  foreach(source ${COMPOSITE_SOURCES})
+    file(APPEND "${COMPOSITE_FILE}" "#include \"${source}\"\n")
+  endforeach()
+
+else()
+  message(SEND_ERROR "MakeComposite.cmake should not be included but run in script mode.")
+
+endif()

+ 10 - 0
cmake/scripts/README.md

@@ -0,0 +1,10 @@
+Directory Info
+--------------
+**Directory:** /cmake/scripts  
+**License:** Unlicense  
+**Description:** This directory is used for cmake files which are not meant to
+be included using CMake's normal include() directive.  Typically, files in this
+directory will be invoked as a custom command/target in the form of:
+```
+ cmake -P <CustomScriptName.cmake> [... other options ...]
+```

+ 9 - 0
cmake/templates/metalib_init.cxx.in

@@ -0,0 +1,9 @@
+#include "dtoolbase.h"
+
+@component_init_headers@
+
+EXPORT_CLASS void
+@init_func@() {
+@component_init_funcs@
+}
+@export_definitions@

+ 9 - 0
cmake/templates/metalib_init.h.in

@@ -0,0 +1,9 @@
+#ifndef _METALIB_INIT_@target_name@
+#define _METALIB_INIT_@target_name@
+
+#include "dtoolbase.h"
+
+IMPORT_CLASS void @init_func@();
+@export_declarations@
+
+#endif

+ 23 - 0
cmake/templates/win32_python/__init__.py

@@ -0,0 +1,23 @@
+def _fixup_dlls():
+    try:
+        path = __path__[0]
+    except (NameError, IndexError):
+        return # Not a package, or not on filesystem
+
+    import os
+
+    relpath = os.path.relpath(path, __path__[-1])
+    dll_path = os.path.abspath(os.path.join(__path__[-1], '../bin', relpath))
+    if not os.path.isdir(dll_path):
+        return
+
+    if hasattr(os, 'add_dll_directory'):
+        os.add_dll_directory(dll_path)
+    else:
+        os_path = os.environ.get('PATH', '')
+        os_path = os_path.split(os.pathsep) if os_path else []
+        os_path.insert(0, dll_path)
+        os.environ['PATH'] = os.pathsep.join(os_path)
+
+_fixup_dlls()
+del _fixup_dlls

+ 18 - 0
contrib/CMakeLists.txt

@@ -0,0 +1,18 @@
+if(NOT BUILD_PANDA)
+  message(FATAL_ERROR "Cannot build contrib without panda!  Please enable the BUILD_PANDA option.")
+endif()
+
+# Include source directories
+add_subdirectory(src/ai)
+add_subdirectory(src/contribbase)
+add_subdirectory(src/rplight)
+
+if(HAVE_PYTHON)
+  add_python_module(panda3d.ai p3ai
+    IMPORT panda3d.core COMPONENT ContribPython)
+
+  add_python_module(panda3d._rplight p3rplight
+    IMPORT panda3d.core COMPONENT ContribPython)
+endif()
+
+export_targets(Contrib COMPONENT ContribDevel)

+ 54 - 0
contrib/src/ai/CMakeLists.txt

@@ -0,0 +1,54 @@
+set(P3AI_HEADERS
+  aiBehaviors.h
+  aiCharacter.h
+  aiGlobals.h
+  aiNode.h
+  aiPathFinder.h
+  aiWorld.h
+  arrival.h
+  config_ai.h
+  evade.h
+  flee.h
+  flock.h
+  meshNode.h
+  obstacleAvoidance.h
+  pathFind.h
+  pathFollow.h
+  pursue.h
+  seek.h
+  wander.h
+)
+
+set(P3AI_SOURCES
+  aiBehaviors.cxx
+  aiCharacter.cxx
+  aiNode.cxx
+  aiPathFinder.cxx
+  aiWorld.cxx
+  arrival.cxx
+  config_ai.cxx
+  evade.cxx
+  flee.cxx
+  flock.cxx
+  meshNode.cxx
+  obstacleAvoidance.cxx
+  pathFind.cxx
+  pathFollow.cxx
+  pursue.cxx
+  seek.cxx
+  wander.cxx
+)
+
+composite_sources(p3ai P3AI_SOURCES)
+add_library(p3ai ${P3AI_HEADERS} ${P3AI_SOURCES})
+set_target_properties(p3ai PROPERTIES DEFINE_SYMBOL BUILDING_PANDAAI)
+target_link_libraries(p3ai p3contribbase)
+target_interrogate(p3ai ALL)
+
+install(TARGETS p3ai
+  EXPORT Contrib COMPONENT Contrib
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT ContribDevel)
+install(FILES ${P3AI_HEADERS} COMPONENT ContribDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 14 - 0
contrib/src/contribbase/CMakeLists.txt

@@ -0,0 +1,14 @@
+set(P3CONTRIBBASE_SOURCES
+  contribbase.cxx
+)
+
+set(P3CONTRIBBASE_HEADERS
+  contribbase.h contribsymbols.h
+)
+
+# Yes, INTERFACE: don't build it, there's no code!
+add_library(p3contribbase INTERFACE)
+target_link_libraries(p3contribbase INTERFACE panda)
+
+install(TARGETS p3contribbase EXPORT Contrib COMPONENT Contrib)
+install(FILES ${P3CONTRIBBASE_HEADERS} COMPONENT ContribDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 52 - 0
contrib/src/rplight/CMakeLists.txt

@@ -0,0 +1,52 @@
+set(P3RPLIGHT_HEADERS
+  config_rplight.h
+  gpuCommand.h gpuCommand.I
+  gpuCommandList.h
+  iesDataset.h
+  internalLightManager.h internalLightManager.I
+  pointerSlotStorage.h
+  pssmCameraRig.h pssmCameraRig.I
+  rpLight.h rpLight.I
+  rpPointLight.h rpPointLight.I
+  rpSpotLight.h rpSpotLight.I
+  shadowAtlas.h shadowAtlas.I
+  shadowManager.h shadowManager.I
+  shadowSource.h shadowSource.I
+  tagStateManager.h tagStateManager.I
+)
+
+set(P3RPLIGHT_SOURCES
+  config_rplight.cxx
+  gpuCommand.cxx
+  gpuCommandList.cxx
+  iesDataset.cxx
+  internalLightManager.cxx
+  pssmCameraRig.cxx
+  rpLight.cxx
+  rpPointLight.cxx
+  rpSpotLight.cxx
+  shadowAtlas.cxx
+  shadowManager.cxx
+  shadowSource.cxx
+  tagStateManager.cxx
+)
+
+composite_sources(p3rplight P3RPLIGHT_SOURCES)
+# STATIC, because it doesn't contain any EXPCL_ stuff
+add_library(p3rplight STATIC ${P3RPLIGHT_HEADERS} ${P3RPLIGHT_SOURCES})
+target_link_libraries(p3rplight p3contribbase)
+target_interrogate(p3rplight ALL)
+
+if(MODULE_TYPE STREQUAL "MODULE")
+  # Because it's STATIC (see above), we need to make it PIC so it can link into
+  # a Python module
+  set_target_properties(p3rplight PROPERTIES POSITION_INDEPENDENT_CODE ON)
+endif()
+
+install(TARGETS p3rplight
+  EXPORT Contrib COMPONENT Contrib
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT ContribDevel)
+install(FILES ${P3RPLIGHT_HEADERS} COMPONENT ContribDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 75 - 0
direct/CMakeLists.txt

@@ -0,0 +1,75 @@
+if(NOT BUILD_PANDA)
+  message(FATAL_ERROR "Cannot build direct without panda!  Please enable the BUILD_PANDA option.")
+endif()
+
+# Include source directories which have C++ components:
+add_subdirectory(src/dcparse)
+add_subdirectory(src/dcparser)
+add_subdirectory(src/deadrec)
+add_subdirectory(src/directbase)
+#add_subdirectory(src/directd)
+#add_subdirectory(src/directdServer)
+add_subdirectory(src/distributed)
+add_subdirectory(src/interval)
+add_subdirectory(src/motiontrail)
+add_subdirectory(src/showbase)
+
+set(P3DIRECT_COMPONENTS
+  p3dcparser p3deadrec
+  p3interval p3motiontrail p3showbase
+)
+if(HAVE_PYTHON)
+  list(APPEND P3DIRECT_COMPONENTS p3distributed)
+endif()
+
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "DirectDevel")
+add_metalib(p3direct INIT init_libdirect direct.h COMPONENTS ${P3DIRECT_COMPONENTS})
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+set_property(TARGET p3direct PROPERTY LINKER_LANGUAGE "CXX")
+
+# Installation:
+install(TARGETS p3direct
+  EXPORT Direct COMPONENT Direct
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  ARCHIVE COMPONENT DirectDevel)
+
+if(HAVE_PYTHON)
+  # Now for the Python side of everything
+
+  add_python_module(panda3d.direct
+    p3dcparser p3deadrec p3distributed p3interval
+    p3motiontrail p3showbase LINK p3direct IMPORT panda3d.core COMPONENT Direct)
+
+  # Copy Python source files into the build directory
+  install_python_package(direct SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/src" LIB COMPONENT Direct)
+
+  # This bit is to generate the 'pandac' compatibility shim. It's deprecated now,
+  # but in older versions of Panda3D, one would use
+  # from pandac.PandaModules import *
+  # instead of
+  # from panda3d.FOO import *
+  # Generate PandaModules:
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pandac/PandaModules.py"
+    "\"This module is deprecated.  Import from panda3d.core and other panda3d.* modules instead.\"
+
+print(\"Warning: pandac.PandaModules is deprecated, import from panda3d.core instead\")\n")
+
+  foreach(module ${ALL_INTERROGATE_MODULES})
+    string(REGEX REPLACE "^.*\\." "" module_name "${module}")
+    file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pandac/PandaModules.py" "
+try:
+    from ${module} import *
+except ImportError as err:
+    if not (\"No module named\" in str(err) and \"${module_name}\" in str(err)):
+        raise
+")
+  endforeach()
+
+  # Now install ourselves:
+  install_python_package(pandac SOURCE "${CMAKE_CURRENT_BINARY_DIR}/pandac" LIB COMPONENT Direct)
+endif()
+
+# "Direct" component contains both the Python stuff and the non-Python stuff,
+# because direct has a pretty solid dependency on Python.
+export_targets(Direct NAMESPACE "Panda3D::Direct::" COMPONENT DirectDevel)

+ 3 - 0
direct/src/dcparse/CMakeLists.txt

@@ -0,0 +1,3 @@
+add_executable(p3dcparse dcparse.cxx)
+target_link_libraries(p3dcparse p3direct)
+install(TARGETS p3dcparse EXPORT Direct COMPONENT Direct DESTINATION ${CMAKE_INSTALL_BINDIR})

+ 87 - 0
direct/src/dcparser/CMakeLists.txt

@@ -0,0 +1,87 @@
+set(P3DCPARSER_HEADERS
+  dcAtomicField.h dcAtomicField.I
+  dcClass.h dcClass.I
+  dcDeclaration.h
+  dcField.h dcField.I
+  dcFile.h dcFile.I
+  dcKeyword.h dcKeywordList.h
+  dcLexer.lxx dcLexerDefs.h
+  dcMolecularField.h
+  dcParser.yxx dcParserDefs.h
+  dcSubatomicType.h
+  dcPackData.h dcPackData.I
+  dcPacker.h dcPacker.I
+  dcPackerCatalog.h dcPackerCatalog.I
+  dcPackerInterface.h dcPackerInterface.I
+  dcParameter.h
+  dcClassParameter.h
+  dcArrayParameter.h
+  dcSimpleParameter.h
+  dcSwitchParameter.h
+  dcNumericRange.h dcNumericRange.I
+  dcSwitch.h
+  dcTypedef.h
+  dcbase.h
+  dcindent.h
+  dcmsgtypes.h
+  hashGenerator.h
+  primeNumberGenerator.h
+)
+
+set(P3DCPARSER_SOURCES
+  dcAtomicField.cxx
+  dcClass.cxx
+  dcDeclaration.cxx
+  dcField.cxx
+  dcFile.cxx
+  dcKeyword.cxx
+  dcKeywordList.cxx
+  dcMolecularField.cxx
+  dcSubatomicType.cxx
+  dcPackData.cxx
+  dcPacker.cxx
+  dcPackerCatalog.cxx
+  dcPackerInterface.cxx
+  dcParameter.cxx
+  dcClassParameter.cxx
+  dcArrayParameter.cxx
+  dcSimpleParameter.cxx
+  dcSwitchParameter.cxx
+  dcSwitch.cxx
+  dcTypedef.cxx
+  dcindent.cxx
+  hashGenerator.cxx
+  primeNumberGenerator.cxx
+)
+
+set(P3DCPARSER_IGATEEXT
+  dcClass_ext.cxx dcClass_ext.h
+  dcField_ext.cxx dcField_ext.h
+  dcPacker_ext.cxx dcPacker_ext.h
+)
+
+add_bison_target(dcParser.cxx dcParser.yxx DEFINES dcParser.h PREFIX dcyy)
+add_flex_target(dcLexer.cxx dcLexer.lxx CASE_INSENSITIVE PREFIX dcyy)
+
+# These cannot be interrogated, and are excluded from the composites.
+set(P3DCPARSER_PARSER_SOURCES
+    dcParser.cxx
+    dcLexer.cxx)
+
+composite_sources(p3dcparser P3DCPARSER_SOURCES)
+add_component_library(p3dcparser NOINIT SYMBOL BUILDING_DIRECT_DCPARSER
+  ${P3DCPARSER_HEADERS} ${P3DCPARSER_SOURCES} ${P3DCPARSER_PARSER_SOURCES})
+target_compile_definitions(p3dcparser PUBLIC WITHIN_PANDA)
+target_link_libraries(p3dcparser p3directbase panda)
+target_interrogate(p3dcparser ${P3DCPARSER_HEADERS} ${P3DCPARSER_SOURCES}
+  EXTENSIONS ${P3DCPARSER_IGATEEXT})
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3dcparser
+    EXPORT Direct COMPONENT Direct
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT DirectDevel)
+endif()
+install(FILES ${P3DCPARSER_HEADERS} COMPONENT DirectDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 24 - 0
direct/src/deadrec/CMakeLists.txt

@@ -0,0 +1,24 @@
+set(P3DEADREC_HEADERS
+  config_deadrec.h
+  smoothMover.h smoothMover.I
+)
+
+set(P3DEADREC_SOURCES
+  config_deadrec.cxx
+  smoothMover.cxx
+)
+
+add_component_library(p3deadrec SYMBOL BUILDING_DIRECT_DEADREC
+  ${P3DEADREC_HEADERS} ${P3DEADREC_SOURCES})
+target_link_libraries(p3deadrec p3directbase panda)
+target_interrogate(p3deadrec ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3deadrec
+    EXPORT Direct COMPONENT Direct
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT DirectDevel)
+endif()
+install(FILES ${P3DEADREC_HEADERS} COMPONENT DirectDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 14 - 0
direct/src/directbase/CMakeLists.txt

@@ -0,0 +1,14 @@
+set(P3DIRECTBASE_SOURCES
+  directbase.cxx
+)
+
+set(P3DIRECTBASE_HEADERS
+  directbase.h directsymbols.h
+)
+
+# Yes, INTERFACE: don't build it, there's no code!
+add_library(p3directbase INTERFACE)
+target_link_libraries(p3directbase INTERFACE panda)
+
+install(TARGETS p3directbase EXPORT Direct COMPONENT Direct)
+install(FILES ${P3DIRECTBASE_HEADERS} COMPONENT DirectDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 35 - 0
direct/src/distributed/CMakeLists.txt

@@ -0,0 +1,35 @@
+if(NOT HAVE_PYTHON)
+  return()
+endif()
+
+set(P3DISTRIBUTED_HEADERS
+  config_distributed.h
+  cConnectionRepository.h
+  cConnectionRepository.I
+  cDistributedSmoothNodeBase.h
+  cDistributedSmoothNodeBase.I
+)
+
+set(P3DISTRIBUTED_SOURCES
+  config_distributed.cxx
+)
+
+set(P3DISTRIBUTED_IGATEEXT
+  cConnectionRepository.cxx
+  cDistributedSmoothNodeBase.cxx
+)
+
+add_component_library(p3distributed NOINIT SYMBOL BUILDING_DIRECT_DISTRIBUTED
+  ${P3DISTRIBUTED_HEADERS} ${P3DISTRIBUTED_SOURCES})
+target_link_libraries(p3distributed p3directbase p3dcparser panda)
+target_interrogate(p3distributed ALL EXTENSIONS ${P3DISTRIBUTED_IGATEEXT})
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3distributed
+    EXPORT Direct COMPONENT Direct
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT DirectDevel)
+endif()
+install(FILES ${P3DISTRIBUTED_HEADERS} COMPONENT DirectDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 54 - 0
direct/src/interval/CMakeLists.txt

@@ -0,0 +1,54 @@
+set(P3INTERVAL_HEADERS
+  config_interval.h
+  cInterval.I cInterval.h
+  cIntervalManager.I cIntervalManager.h
+  cConstraintInterval.I cConstraintInterval.h
+  cConstrainTransformInterval.I cConstrainTransformInterval.h
+  cConstrainPosInterval.I cConstrainPosInterval.h
+  cConstrainHprInterval.I cConstrainHprInterval.h
+  cConstrainPosHprInterval.I cConstrainPosHprInterval.h
+  cLerpInterval.I cLerpInterval.h
+  cLerpNodePathInterval.I cLerpNodePathInterval.h
+  cLerpAnimEffectInterval.I cLerpAnimEffectInterval.h
+  cMetaInterval.I cMetaInterval.h
+  hideInterval.I hideInterval.h
+  lerpblend.h
+  showInterval.I showInterval.h
+  waitInterval.I waitInterval.h
+  lerp_helpers.h
+)
+
+set(P3INTERVAL_SOURCES
+  config_interval.cxx
+  cInterval.cxx
+  cIntervalManager.cxx
+  cConstraintInterval.cxx
+  cConstrainTransformInterval.cxx
+  cConstrainPosInterval.cxx
+  cConstrainHprInterval.cxx
+  cConstrainPosHprInterval.cxx
+  cLerpInterval.cxx
+  cLerpNodePathInterval.cxx
+  cLerpAnimEffectInterval.cxx
+  cMetaInterval.cxx
+  hideInterval.cxx
+  lerpblend.cxx
+  showInterval.cxx
+  waitInterval.cxx
+)
+
+composite_sources(p3interval P3INTERVAL_SOURCES)
+add_component_library(p3interval SYMBOL BUILDING_DIRECT_INTERVAL
+  ${P3INTERVAL_HEADERS} ${P3INTERVAL_SOURCES})
+target_link_libraries(p3interval p3directbase panda)
+target_interrogate(p3interval ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3interval
+    EXPORT Direct COMPONENT Direct
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT DirectDevel)
+endif()
+install(FILES ${P3INTERVAL_HEADERS} COMPONENT DirectDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 24 - 0
direct/src/motiontrail/CMakeLists.txt

@@ -0,0 +1,24 @@
+set(P3MOTIONTRAIL_HEADERS
+  config_motiontrail.h
+  cMotionTrail.h
+)
+
+set(P3MOTIONTRAIL_SOURCES
+  config_motiontrail.cxx
+  cMotionTrail.cxx
+)
+
+add_component_library(p3motiontrail SYMBOL BUILDING_DIRECT_MOTIONTRAIL
+  ${P3MOTIONTRAIL_HEADERS} ${P3MOTIONTRAIL_SOURCES})
+target_link_libraries(p3motiontrail p3directbase panda)
+target_interrogate(p3motiontrail ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3motiontrail
+    EXPORT Direct COMPONENT Direct
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT DirectDevel)
+endif()
+install(FILES ${P3MOTIONTRAIL_HEADERS} COMPONENT DirectDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 32 - 0
direct/src/showbase/CMakeLists.txt

@@ -0,0 +1,32 @@
+set(P3SHOWBASE_HEADERS
+  showBase.h
+)
+
+set(P3SHOWBASE_SOURCES
+  showBase.cxx
+)
+
+if(APPLE)
+  list(APPEND P3SHOWBASE_SOURCES showBase_assist.mm)
+
+  # Bug in CMake 3.16.2: it tries to put .mm with the .cxx
+  set_source_files_properties(showBase_assist.mm PROPERTIES
+    SKIP_UNITY_BUILD_INCLUSION YES)
+
+endif()
+
+add_component_library(p3showbase NOINIT SYMBOL BUILDING_DIRECT_SHOWBASE
+  ${P3SHOWBASE_HEADERS} ${P3SHOWBASE_SOURCES})
+
+target_link_libraries(p3showbase p3directbase panda)
+target_interrogate(p3showbase ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3showbase
+    EXPORT Direct COMPONENT Direct
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT DirectDevel)
+endif()
+install(FILES ${P3SHOWBASE_HEADERS} COMPONENT DirectDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 14 - 0
dtool/CMakeLists.txt

@@ -0,0 +1,14 @@
+# Generate dtool_config.h
+include(LocalSetup.cmake)
+
+# Include dtool source directories
+add_subdirectory(src/cppparser)
+add_subdirectory(src/dconfig)
+add_subdirectory(src/dtoolbase)
+add_subdirectory(src/dtoolutil)
+add_subdirectory(src/interrogate)
+add_subdirectory(src/interrogatedb)
+add_subdirectory(src/prc)
+
+# Include dtool metalib
+add_subdirectory(metalibs/dtool)

+ 247 - 0
dtool/CompilerFlags.cmake

@@ -0,0 +1,247 @@
+#
+# CompilerFlags.cmake
+#
+# This file sets up various compiler flags (warning levels, turning off options
+# we don't need, etc.)  It must be included directly from the root
+# CMakeLists.txt, due to its use of set(...)
+#
+
+include(CheckCXXCompilerFlag)
+
+# These are flags for the custom configurations we add
+# Standard
+if(MSVC)
+  set(CMAKE_C_FLAGS_STANDARD "/Ox")
+  set(CMAKE_CXX_FLAGS_STANDARD "/Ox")
+else()
+  set(CMAKE_C_FLAGS_STANDARD "-O3")
+  set(CMAKE_CXX_FLAGS_STANDARD "-O3")
+endif()
+set(CMAKE_SHARED_LINKER_FLAGS_STANDARD "")
+set(CMAKE_MODULE_LINKER_FLAGS_STANDARD "")
+set(CMAKE_EXE_LINKER_FLAGS_STANDARD "")
+
+# Coverage (when we know how to support it)
+if(CMAKE_CXX_COMPILER_ID MATCHES "(AppleClang|Clang)")
+  set(CMAKE_C_FLAGS_COVERAGE
+    "${CMAKE_C_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping")
+  set(CMAKE_CXX_FLAGS_COVERAGE
+    "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-instr-generate -fcoverage-mapping")
+
+  set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+    "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fprofile-instr-generate")
+  set(CMAKE_MODULE_LINKER_FLAGS_COVERAGE
+    "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} -fprofile-instr-generate")
+  set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+    "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fprofile-instr-generate")
+
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GCC")
+  set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_DEBUG} --coverage")
+  set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} --coverage")
+
+  set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+    "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} --coverage")
+  set(CMAKE_MODULE_LINKER_FLAGS_COVERAGE
+    "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} --coverage")
+  set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+    "${CMAKE_EXE_LINKER_FLAGS_DEBUG} --coverage")
+
+endif()
+
+# Panda3D is now a C++11 project. Newer versions of CMake support this out of
+# the box; for older versions we take a shot in the dark:
+if(CMAKE_VERSION VERSION_LESS "3.1")
+  check_cxx_compiler_flag("-std=gnu++11" COMPILER_SUPPORTS_CXX11)
+  if(COMPILER_SUPPORTS_CXX11)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
+  else()
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x")
+  endif()
+
+else()
+  set(CMAKE_CXX_STANDARD 11)
+  set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+endif()
+
+# Set certain CMake flags we expect
+set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
+
+# Set up the output directory structure, mimicking that of makepanda
+set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/cmake")
+
+if(CMAKE_CFG_INTDIR STREQUAL ".")
+  # Single-configuration generator; output goes straight in the binary dir
+  set(PANDA_OUTPUT_DIR "${PROJECT_BINARY_DIR}")
+
+else()
+  # Multi-configuration generator; add a per-configuration path prefix
+  set(PANDA_OUTPUT_DIR "${PROJECT_BINARY_DIR}/$<CONFIG>")
+
+endif()
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PANDA_OUTPUT_DIR}/bin")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PANDA_OUTPUT_DIR}/lib")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PANDA_OUTPUT_DIR}/lib")
+
+set(MODULE_DESTINATION "${CMAKE_INSTALL_LIBDIR}")
+
+# Runtime code assumes that dynamic modules have a "lib" prefix; Windows
+# assumes that debug libraries have a _d suffix.
+set(CMAKE_SHARED_MODULE_PREFIX "lib")
+if(WIN32)
+  set(CMAKE_DEBUG_POSTFIX "_d")
+
+  # Windows uses libfoo.lib for static libraries and foo.lib/dll for dynamic.
+  set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
+
+  # On Windows, modules (DLLs) are located in bin; lib is just for .lib files
+  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PANDA_OUTPUT_DIR}/bin")
+  if(BUILD_SHARED_LIBS)
+    set(MODULE_DESTINATION "bin")
+  endif()
+endif()
+
+# Though not technically correct, we'll still want MODULE type libraries
+# (used for display and audio plugins) to use a .dylib extension.
+if(APPLE)
+  set(CMAKE_SHARED_MODULE_SUFFIX ".dylib")
+endif()
+
+# We want the output structured like build/CONFIG/bin, not build/bin/CONFIG per
+# the default for multi-configuration generators. In CMake 3.4+, it switches
+# automatically if the *_OUTPUT_DIRECTORY property contains a generator
+# expresssion, but as of this writing we support as early as CMake 3.0.2.
+#
+# So, let's just do this:
+if(CMAKE_VERSION VERSION_LESS "3.4")
+  foreach(_type RUNTIME ARCHIVE LIBRARY)
+    foreach(_config ${CMAKE_CONFIGURATION_TYPES})
+      string(TOUPPER "${_config}" _config)
+      set(CMAKE_${_type}_OUTPUT_DIRECTORY_${_config} "${CMAKE_${_type}_OUTPUT_DIRECTORY}")
+    endforeach(_config)
+  endforeach(_type)
+endif()
+
+# Set warning levels
+if(MSVC)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3")
+  set(CMAKE_CCXX_FLAGS "${CMAKE_CXX_FLAGS} /W3")
+
+else()
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+
+endif()
+
+if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
+  set(global_flags
+    "-Wno-unused-function -Wno-unused-parameter -fno-strict-aliasing")
+  set(release_flags "-Wno-unused-variable")
+
+  if(NOT MSVC)
+    # These flags upset Clang when it's in MSVC mode
+    set(release_flags "${release_flags} -fno-stack-protector -ffast-math -fno-unsafe-math-optimizations")
+
+    # Allow NaN to occur in the public SDK
+    set(standard_flags "${release_flags} -fno-finite-math-only")
+
+  else()
+    set(standard_flags "${release_flags}")
+
+  endif()
+
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${global_flags}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${global_flags} -Wno-reorder")
+  set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${release_flags}")
+  set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${release_flags}")
+  set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${release_flags}")
+  set(CMAKE_CXX_FLAGS_STANDARD "${CMAKE_CXX_FLAGS_STANDARD} ${standard_flags}")
+
+  if(MSVC)
+    # Clang behaving as MSVC
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-command-line-argument")
+    set(CMAKE_CXX_FLAGS
+      "${CMAKE_CXX_FLAGS} -Wno-microsoft-template -Wno-unused-command-line-argument")
+  endif()
+endif()
+
+if(WIN32)
+  add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+endif()
+
+# CMake will often pass -rdynamic when linking executables as a convenience for
+# projects that might forget when to use ENABLE_EXPORTS.  This is preposterous,
+# since it prevents the linker from removing symbols unneeded by the executable
+# and stops us from identifying cases where ENABLE_EXPORTS is needed.
+set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+
+# As long as we're figuring out compiler flags, figure out the flags for
+# turning C++ exception support on and off
+if(MSVC)
+  set(cxx_exceptions_on "/EHsc")
+  set(cxx_exceptions_off "/D_HAS_EXCEPTIONS=0")
+
+  set(cxx_rtti_on "/GR")
+  set(cxx_rtti_off "/GR-")
+
+else()
+  check_cxx_compiler_flag("-fno-exceptions" COMPILER_SUPPORTS_FEXCEPTIONS)
+  if(COMPILER_SUPPORTS_FEXCEPTIONS)
+    set(cxx_exceptions_on "-fexceptions")
+    set(cxx_exceptions_off "-fno-exceptions")
+
+  else()
+    set(cxx_exceptions_on)
+    set(cxx_exceptions_off)
+
+  endif()
+
+  check_cxx_compiler_flag("-fno-rtti" COMPILER_SUPPORTS_FRTTI)
+  if(COMPILER_SUPPORTS_FRTTI)
+    set(cxx_rtti_on "-frtti")
+    set(cxx_rtti_off "-fno-rtti")
+
+  else()
+    set(cxx_rtti_on)
+    set(cxx_rtti_off)
+
+  endif()
+
+endif()
+
+set(cxx_exceptions_property "$<BOOL:$<TARGET_PROPERTY:CXX_EXCEPTIONS>>")
+add_compile_options(
+  "$<${cxx_exceptions_property}:${cxx_exceptions_on}>"
+  "$<$<NOT:${cxx_exceptions_property}>:${cxx_exceptions_off}>")
+
+set(cxx_rtti_property "$<BOOL:$<TARGET_PROPERTY:CXX_RTTI>>")
+if(NOT ANDROID)
+  # Normally, our Debug build defaults RTTI on. This is not the case on
+  # Android, where we don't use it even on Debug, to save space.
+
+  set(cxx_rtti_property "$<OR:$<CONFIG:Debug>,${cxx_rtti_property}>")
+endif()
+add_compile_options(
+  "$<${cxx_rtti_property}:${cxx_rtti_on}>"
+  "$<$<NOT:${cxx_rtti_property}>:${cxx_rtti_off}>")
+set_property(DIRECTORY "${PROJECT_SOURCE_DIR}" APPEND PROPERTY
+  COMPILE_DEFINITIONS "$<${cxx_rtti_property}:HAVE_RTTI>")
+
+if(MSVC)
+  set(msvc_bigobj_property "$<BOOL:$<TARGET_PROPERTY:MSVC_BIGOBJ>>")
+  add_compile_options("$<${msvc_bigobj_property}:/bigobj>")
+endif()
+
+# We should use -fvisibility=hidden everywhere, as it makes sure we think
+# about what symbols really should be exposed externally.  For more info, see:
+# https://gcc.gnu.org/wiki/Visibility
+if(NOT MSVC)
+  check_cxx_compiler_flag("-fvisibility=hidden" COMPILER_SUPPORTS_FVISIBILITY_HIDDEN)
+  if(COMPILER_SUPPORTS_FVISIBILITY_HIDDEN)
+    add_compile_options("-fvisibility=hidden")
+  endif()
+endif()

+ 600 - 0
dtool/Config.cmake

@@ -0,0 +1,600 @@
+#
+# dtool/Config.cmake
+#
+# This file defines certain configuration variables that are written
+# into the various make scripts.  It is processed by CMake to
+# generate build scripts appropriate to each environment.
+#
+
+include(CMakeDependentOption)
+
+# Define our target platform.
+# The values "UNIX", "WIN32", "MINGW", "MSYS", and "CYGWIN"
+# are automatically provided by CMAKE.  "APPLE" is also provided by
+# CMAKE but may be True on systems that are not OS X.
+if(CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Android")
+  set(IS_LINUX 1)
+endif()
+if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
+  set(IS_OSX 1)
+endif()
+if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+  set(IS_FREEBSD 1)
+endif()
+
+if(CMAKE_VERSION VERSION_GREATER "3.8")
+  get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+else()
+  message(WARNING "Multi-configuration builds may not work properly when using
+a CMake < 3.9. Making a guess if this is a multi-config generator.")
+  if(DEFINED CMAKE_CONFIGURATION_TYPES)
+    set(IS_MULTICONFIG ON)
+  else()
+    set(IS_MULTICONFIG OFF)
+  endif()
+endif()
+
+# Define the type of build we are setting up.
+
+set(_configs Standard Release RelWithDebInfo Debug MinSizeRel)
+if(DEFINED CMAKE_CXX_FLAGS_COVERAGE)
+  list(APPEND _configs Coverage)
+endif()
+
+if(IS_MULTICONFIG)
+  set(CMAKE_CONFIGURATION_TYPES ${_configs})
+else()
+  # CMAKE_BUILD_TYPE can't just be set using the usual set(CACHE) method since
+  # it's an empty string by default.
+  if(NOT CMAKE_BUILD_TYPE)
+    set(CMAKE_BUILD_TYPE Standard)
+  endif()
+  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${_configs})
+endif()
+
+set(PER_CONFIG_OPTIONS)
+
+# Are we building with static or dynamic linking?
+option(BUILD_SHARED_LIBS
+  "Causes subpackages to be built separately -- setup for dynamic linking.
+Utilities/tools/binaries/etc are then dynamically linked to the
+libraries instead of being statically linked." ON)
+
+option(BUILD_METALIBS
+  "Should we build 'metalibs' -- fewer, larger libraries that contain the bulk
+of the code instead of many smaller components.  Note that turning this off
+will still result in the 'metalibs' being built, but they will instead be many
+smaller stub libraries and not 'meta' libraries." ON)
+
+# The character used to separate components of an OS-specific
+# directory name depends on the platform (it is '/' on Unix, '\' on
+# Windows).  That character selection is hardcoded into Panda and
+# cannot be changed here.  (Note that an internal Panda filename
+# always uses the forward slash, '/', to separate the components of a
+# directory name.)
+
+# There's a different character used to separate the complete
+# directory names in a search path specification.  On Unix, the
+# normal convention is ':', on Windows, it has to be ';', because the
+# colon is already used to mark the drive letter.  This character is
+# selectable here.  Most users won't want to change this.  If
+# multiple characters are placed in this string, any one of them may
+# be used as a separator character.
+if(WIN32)
+  set(DEFAULT_PATHSEP ";")
+else()
+  set(DEFAULT_PATHSEP ":")
+endif()
+
+
+# Panda uses prc files for runtime configuration.  There are many
+# compiled-in options to customize the behavior of the prc config
+# system; most users won't need to change any of them.  Feel free to
+# skip over all of the PRC_* variables defined here.
+
+# The default behavior is to search for files names *.prc in the
+# directory specified by the PRC_DIR environment variable, and then
+# to search along all of the directories named by the PRC_PATH
+# environment variable.  Either of these variables might be
+# undefined; if both of them are undefined, the default is to search
+# in the directory named here by DEFAULT_PRC_DIR.
+
+# By default, we specify the <auto>/etc dir, which is a special
+# syntax that causes it to automatically search up the directory
+# tree starting at the location of libpandaexpress.dll for any
+# directories called 'etc'.
+
+if(UNIX)
+  set(_default_prc "<auto>etc/panda3d")
+else()
+  set(_default_prc "<auto>etc")
+endif()
+set(DEFAULT_PRC_DIR "${_default_prc}" CACHE STRING
+  "The compiled-in default directory to look for the Config.prc file,
+in the absence of the PRC_DIR environment variable set, and in
+the absence of anything specified via the configpath directive.")
+
+# You can specify the names of the environment variables that are
+# used to specify the search location(s) for prc files at runtime.
+# These are space-separated lists of environment variable names.
+# Specify empty string for either one of these to disable the
+# feature.  For instance, redefining PRC_DIR_ENVVARS here to
+# PRC_DIR would cause the environment variable $PRC_DIR
+# to be consulted at startup instead of the default value of
+# $PANDA_PRC_DIR.
+
+set(PRC_DIR_ENVVARS "PANDA_PRC_DIR" CACHE STRING
+  "The compiled-in name of the environment variable(s) that contain
+the name of a single directory in which to search for prc files.")
+
+set(PRC_PATH_ENVVARS "PANDA_PRC_PATH" CACHE STRING
+  "The compiled-in name of the environment variable(s) that contain
+the name of multiple directories, separated by DEFAULT_PATHSEP, in
+which to search for prc files.")
+
+# You can specify the name of the file(s) to search for in the above
+# paths to be considered a config file.  This should be a
+# space-separated list of filename patterns.  This is *.prc by
+# default; normally there's no reason to change this.
+
+set(PRC_PATTERNS "*.prc" CACHE STRING
+  "The filename(s) to search for in the above paths.  Normally this is
+*.prc.")
+
+# You can optionally encrypt your prc file(s) to help protect them
+# from curious eyes.  You have to specify the encryption key, which
+# gets hard-coded into the executable.  (This feature provides mere
+# obfuscation, not real security, since the encryption key can
+# potentially be extracted by a hacker.)  This requires building with
+# OpenSSL.
+
+set(PRC_ENCRYPTED_PATTERNS "*.prc.pe" CACHE STRING
+  "The filename(s) for encrypted prc files.")
+
+set(PRC_ENCRYPTION_KEY "" CACHE STRING
+  "The encryption key used to decrypt any encrypted prc files
+identified by PRC_ENCRYPTED_PATTERNS.")
+
+# One unusual feature of config is the ability to execute one or more
+# of the files it discovers as if it were a program, and then treat
+# the output of this program as a prc file.  If you want to use this
+# feature, define this variable to the filename pattern or patterns
+# for such executable-style config programs (e.g. *prc.exe).  This
+# can be the same as the above if you like this sort of ambiguity; in
+# that case, config will execute the file if it appears to be
+# executable; otherwise, it will simply read it.
+
+set(PRC_EXECUTABLE_PATTERNS "" CACHE STRING 
+  "The filename(s) to search for, and execute, in the above paths.
+Normally this is empty.")
+
+# If you do use the above feature, you'll need another environment
+# variable that specifies additional arguments to pass to the
+# executable programs.  The default definition, given here, makes
+# that variable be $PANDA_PRC_XARGS.  Sorry, the same arguments
+# must be supplied to all executables in a given runtime session.
+
+set(PRC_EXECUTABLE_ARGS_ENVVAR "PANDA_PRC_XARGS" CACHE STRING
+  "The environment variable that defines optional args to pass to
+executables found that match one of the above patterns.")
+
+# You can implement signed prc files, if you require this advanced
+# feature.  This allows certain config variables to be set only by a
+# prc file that has been provided by a trusted source.  To do this,
+# first install and compile Dtool with OpenSSL and run the program
+# make-prc-key, and then specify here the output filename generated
+# by that program, and then recompile Dtool.
+
+set(PRC_PUBLIC_KEYS_FILENAME "" CACHE STRING "")
+
+# By default, the signed-prc feature, above, is enabled only for a
+# release build.  In a normal development environment, any prc file
+# can set any config variable, whether  or not it is signed.  Set
+# this variable true or false to explicitly enable or disable this
+# feature.
+#XXX For which build types should this be enabled?
+if(CMAKE_BUILD_TYPE STREQUAL "Release")
+  set(DEFAULT_PRC_RESPECT_TRUST_LEVEL ON)
+else()
+  set(DEFAULT_PRC_RESPECT_TRUST_LEVEL OFF)
+endif()
+
+option(PRC_RESPECT_TRUST_LEVEL
+  "Define if we want to enable the trust_level feature of prc config
+variables.  This requires OpenSSL and PRC_PUBLIC_KEYS_FILENAME,
+above." ${DEFAULT_PRC_RESPECT_TRUST_LEVEL})
+
+# If trust level is in effect, this specifies the default trust level
+# for any legacy (Dconfig) config variables (that is, variables
+# created using the config.GetBool(), etc. interface, rather than the
+# newer ConfigVariableBool interface).
+
+set(PRC_DCONFIG_TRUST_LEVEL "0" CACHE STRING
+  "The trust level value for any legacy (DConfig) variables.")
+
+# If trust level is in effect, you may globally increment the
+# (mis)trust level of all variables by the specified amount.
+# Incrementing this value by 1 will cause all variables to require at
+# least a level 1 signature.
+
+set(PRC_INC_TRUST_LEVEL "0" CACHE STRING
+  "The amount by which we globally increment the trust level.")
+
+# Similarly, the descriptions are normally saved only in a
+# development build, not in a release build.  Set this value true to
+# explicitly save them anyway.
+#XXX only for release-release builds
+option(PRC_SAVE_DESCRIPTIONS
+  "Define if you want to save the descriptions for ConfigVariables."
+  ON)
+
+mark_as_advanced(DEFAULT_PRC_DIR PRC_DIR_ENVVARS PRC_PATH_ENVVARS
+  PRC_PATTERNS PRC_ENCRYPTED_PATTERNS PRC_ENCRYPTION_KEY
+  PRC_EXECUTABLE_PATTERNS PRC_EXECUTABLE_ARGS_ENVVAR
+  PRC_PUBLIC_KEYS_FILENAME PRC_RESPECT_TRUST_LEVEL
+  PRC_DCONFIG_TRUST_LEVEL PRC_INC_TRUST_LEVEL PRC_SAVE_DESCRIPTIONS)
+
+#
+# This is the end of the PRC variable customization section.  The
+# remaining variables are of general interest to everyone.
+#
+
+# The following options relate to interrogate, the tool that is
+# used to generate bindings for non-C++ languages.
+
+option(WANT_INTERROGATE
+  "Do you want to include Interrogate in the installation? This
+program reads C++ source files and generates bindings for another
+language.  If you won't be building interfaces for other languages,
+you don't need the program." ON)
+
+cmake_dependent_option(INTERROGATE_PYTHON_INTERFACE
+  "Do you want to generate a Python-callable interrogate interface?
+This is only necessary if you plan to make calls into Panda from a
+program written in Python.  This is done only if HAVE_PYTHON is also
+true." ON "HAVE_PYTHON" OFF)
+
+set(INTERROGATE_C_INTERFACE
+  "Do you want to generate a C-callable interrogate interface?  This
+generates an interface similar to the Python interface above, with
+a C calling convention.  It should be useful for most other kinds
+of scripting language; the VR Studio used to use this to make calls
+into Panda from Squeak." OFF)
+
+set(INTERROGATE_OPTIONS "-fnames;-string;-refcount;-assert" CACHE STRING
+  "What additional options should be passed to interrogate when
+generating either of the above two interfaces?  Generally, you
+probably don't want to mess with this.")
+
+option(INTERROGATE_VERBOSE
+  "Set this if you would like interrogate to generate advanced
+debugging information." OFF)
+
+mark_as_advanced(INTERROGATE_OPTIONS)
+
+#
+# The following options have to do with the memory allocation system
+# that will be used by Panda3D.
+#
+
+option(DO_MEMORY_USAGE
+  "Do you want to compile in support for tracking memory usage?  This
+enables you to define the variable 'track-memory-usage' at runtime
+to help track memory leaks, and also report total memory usage on
+PStats.  There is some small overhead for having this ability
+available, even if it is unused." OFF)
+list(APPEND PER_CONFIG_OPTIONS DO_MEMORY_USAGE)
+set(DO_MEMORY_USAGE_Debug ON CACHE BOOL "")
+
+option(SIMULATE_NETWORK_DELAY
+  "This option compiles in support for simulating network delay via
+the min-lag and max-lag prc variables.  It adds a tiny bit of
+overhead even when it is not activated, so it is typically enabled
+only in a development build." OFF)
+list(APPEND PER_CONFIG_OPTIONS SIMULATE_NETWORK_DELAY)
+set(SIMULATE_NETWORK_DELAY_Debug ON CACHE BOOL "")
+
+option(SUPPORT_IMMEDIATE_MODE
+  "This option compiles in support for immediate-mode OpenGL
+rendering.  Since this is normally useful only for researching
+buggy drivers, and since there is a tiny bit of per-primitive
+overhead to have this option available even if it is unused, it is
+by default enabled only in a development build.  This has no effect
+on DirectX rendering." OFF)
+list(APPEND PER_CONFIG_OPTIONS SUPPORT_IMMEDIATE_MODE)
+set(SUPPORT_IMMEDIATE_MODE_Debug ON CACHE BOOL "")
+
+option(NOTIFY_DEBUG
+  "Do you want to include the 'debug' and 'spam' Notify messages?
+Normally, these are stripped out when we build for release, but sometimes it's
+useful to keep them around. Turn this setting on to achieve that." OFF)
+list(APPEND PER_CONFIG_OPTIONS NOTIFY_DEBUG)
+set(NOTIFY_DEBUG_Debug ON CACHE BOOL "")
+
+option(SUPPORT_FIXED_FUNCTION
+  "This option compiles in support for the fixed-function OpenGL
+pipeline.  It is only really useful to turn this off if you are targeting
+an OpenGL ES 2 system." ON)
+
+option(USE_MEMORY_DLMALLOC
+  "This is an optional alternative memory-allocation scheme
+available within Panda.  You can experiment with it to see
+if it gives better performance than the system malloc(), but
+at the time of this writing, it doesn't appear that it does." OFF)
+
+option(USE_MEMORY_PTMALLOC2
+  "This is an optional alternative memory-allocation scheme
+available within Panda.  You can experiment with it to see
+if it gives better performance than the system malloc(), but
+at the time of this writing, it doesn't appear that it does." OFF)
+
+option(MEMORY_HOOK_DO_ALIGN
+  "Set this true if you prefer to use the system malloc library even
+if 16-byte alignment must be performed on top of it, wasting up to
+30% of memory usage.  If you do not set this, and 16-byte alignment
+is required and not provided by the system malloc library, then an
+alternative malloc system (above) will be used instead." OFF)
+
+option(USE_DELETED_CHAIN
+  "Define this true to use the DELETED_CHAIN macros, which support
+fast re-use of existing allocated blocks, minimizing the low-level
+calls to malloc() and free() for frequently-created and -deleted
+objects.  There's usually no reason to set this false, unless you
+suspect a bug in Panda's memory management code." ON)
+
+mark_as_advanced(DO_MEMORY_USAGE SIMULATE_NETWORK_DELAY
+  SUPPORT_IMMEDIATE_MODE USE_MEMORY_DLMALLOC USE_MEMORY_PTMALLOC2
+  MEMORY_HOOK_DO_ALIGN USE_DELETED_CHAIN)
+
+
+#
+# This section relates to mobile-device/phone support and options
+#
+
+# iPhone support
+set(BUILD_IPHONE "" CACHE STRING
+  "Panda contains some experimental code to compile for IPhone.  This
+requires the Apple IPhone SDK, which is currently only available
+for OS X platforms.  Set this to either 'iPhoneSimulator' or
+'iPhoneOS'.  Note that this is still *experimental* and incomplete!
+Don't enable this unless you know what you're doing!")
+set_property(CACHE BUILD_IPHONE PROPERTY STRINGS "" iPhoneSimulator iPhoneOS)
+
+
+# Android support
+option(BUILD_ANDROID
+  "Panda contains some experimental code to compile for Android.
+This requires the Google Android NDK. Besides BUILD_ANDROID, you'll
+also have to set ANDROID_NDK_HOME." OFF)
+
+set(ANDROID_NDK_HOME "" CACHE STRING
+  "The location of the Android NDK directory. ANDROID_NDK_HOME may
+not contain any spaces.")
+
+set(ANDROID_ABI "armeabi-v7a" CACHE STRING
+  "Can be be set to armeabi-v7a, arm64-v8a, x86, or x86_64,
+depending on which architecture should be targeted.")
+set_property(CACHE ANDROID_ABI PROPERTY STRINGS
+  armeabi-v7a arm64-v8a x86 x86_64)
+
+set(ANDROID_STL "c++_shared" CACHE STRING "")
+set(ANDROID_PLATFORM "android-14" CACHE STRING "")
+set(ANDROID_ARCH "arm" CACHE STRING "")
+if(ANDROID_ARCH STREQUAL "arm")
+  set(ANDROID_TOOLCHAIN "arm-linux-androideabi")
+else()
+  set(ANDROID_TOOLCHAIN "")
+endif()
+
+mark_as_advanced(ANDROID_NDK_HOME ANDROID_ABI ANDROID_STL
+  ANDROID_PLATFORM ANDROID_ARCH)
+
+
+#
+# Now let's check for the presence of various thirdparty libraries.
+#
+
+
+# By default, we'll assume the user only wants to run with Debug
+# python if he has to--that is, on Windows when building a debug build.
+set(USE_DEBUG_PYTHON OFF)
+if(WIN32)
+  set(USE_DEBUG_PYTHON_Debug ON)
+endif()
+list(APPEND PER_CONFIG_OPTIONS USE_DEBUG_PYTHON)
+
+cmake_dependent_option(HAVE_VIDEO4LINUX
+  "Set this to enable webcam support on Linux." ON
+  "IS_LINUX" OFF)
+
+
+# If you are having trouble linking in OpenGL extension functions at
+# runtime for some reason, you can set this variable. It also,
+# requires you to install the OpenGL header files and compile-time
+# libraries appropriate to the version you want to compile against.
+set(MIN_GL_VERSION "1 1" CACHE STRING
+  "The variable is the major, minor version of OpenGL, separated by a
+space (instead of a dot).  Thus, \"1 1\" means OpenGL version 1.1.
+
+This defines the minimum runtime version of OpenGL that Panda will
+require. Setting it to a higher version will compile in hard
+references to the extension functions provided by that OpenGL
+version and below, which may reduce runtime portability to other
+systems, but it will avoid issues with getting extension function
+pointers.")
+
+
+# Should build tinydisplay?
+#option(HAVE_TINYDISPLAY
+#  "Builds TinyDisplay, a light software renderer based on TinyGL,
+#that is built into Panda. TinyDisplay is not as full-featured as Mesa
+#but is many times faster." ON)
+#option(HAVE_TINYDISPLAY_MinSizeRel "" OFF)
+#list(APPEND PER_CONFIG_OPTIONS HAVE_TINYDISPLAY)
+
+
+# Is SDL installed, and where?
+set(Threads_FIND_QUIETLY TRUE) # Fix for builtin FindSDL
+set(Eigen3_FIND_QUIETLY TRUE) # Fix for builtin FindSDL
+set(PythonLibs_FIND_QUIETLY TRUE) # Fix for builtin FindSDL
+set(PythonInterp_FIND_QUIETLY TRUE) # Fix for builtin FindSDL
+
+find_package(SDL QUIET)
+
+package_option(SDL
+  "The SDL library is useful only for tinydisplay, and is not even
+required for that, as tinydisplay is also supported natively on
+each supported platform.")
+
+# Cleanup after builtin FindSDL
+mark_as_advanced(SDLMAIN_LIBRARY)
+mark_as_advanced(SDL_INCLUDE_DIR)
+mark_as_advanced(SDL_LIBRARY)
+mark_as_advanced(SDL_LIBRARY_TEMP)
+
+
+if(HAVE_GL AND HAVE_X11 AND NOT APPLE)
+  option(HAVE_GLX "Enables GLX. Requires OpenGL and X11." ON)
+else()
+  option(HAVE_GLX "Enables GLX. Requires OpenGL and X11." OFF)
+endif()
+
+option(LINK_IN_GLXGETPROCADDRESS
+  "Define this to compile in a reference to the glXGetProcAddress().
+This is only relevant from platforms using OpenGL under X."
+  OFF)
+
+if(WIN32 AND HAVE_GL)
+  option(HAVE_WGL "Enable WGL.  Requires OpenGL on Windows." ON)
+else()
+  option(HAVE_WGL "Enable WGL.  Requires OpenGL on Windows." OFF)
+endif()
+
+cmake_dependent_option(HAVE_COCOA "Enable Cocoa. Requires Mac OS X." ON
+  "APPLE" OFF)
+
+#
+# Miscellaneous settings
+#
+
+option(WANT_NATIVE_NET
+  "Define this true to build the low-level native network
+implementation.  Normally this should be set true." ON)
+
+option(HAVE_NET
+  "Do you want to build the high-level network interface?  This layers
+on top of the low-level native_net interface, specified above.
+Normally, if you build NATIVE_NET, you will also build NET."
+  ${WANT_NATIVE_NET})
+
+option(HAVE_EGG
+  "Do you want to build the egg loader?  Usually there's no reason to
+avoid building this, unless you really want to make a low-footprint
+build (such as, for instance, for the iPhone)." ON)
+
+option(HAVE_AUDIO
+  "Do you want to build the audio interface?" ON)
+
+option(DO_PSTATS
+  "Enable the pstats client?" ON)
+
+option(USE_PANDAFILESTREAM
+  "Enable the PandaFileStream implementation of pfstream etc.?" ON)
+
+# These image formats don't require the assistance of a third-party
+# library to read and write, so there's normally no reason to disable
+# them int he build, unless you are looking to reduce the memory footprint.
+option(HAVE_SGI_RGB "Enable support for loading SGI RGB images." ON)
+option(HAVE_TGA "Enable support for loading TGA images." ON)
+option(HAVE_IMG "Enable support for loading IMG images." ON)
+option(HAVE_SOFTIMAGE_PIC "Enable support for loading SOFTIMAGE PIC images." ON)
+option(HAVE_BMP "Enable support for loading BMP images." ON)
+option(HAVE_PNM "Enable support for loading PNM images." ON)
+
+foreach(adv_image_format
+  HAVE_SGI_RGB HAVE_TGA HAVE_IMG HAVE_SOFTIMAGE_PIC HAVE_BMP HAVE_PNM)
+
+  option(${adv_image_format}_MinSizeRel "" OFF)
+  list(APPEND PER_CONFIG_OPTIONS ${adv_image_format})
+
+  mark_as_advanced(${adv_image_format} ${adv_image_format}_MinSizeRel)
+
+endforeach(adv_image_format)
+
+# How to invoke bison and flex.  Panda takes advantage of some
+# bison/flex features, and therefore specifically requires bison and
+# flex, not some other versions of yacc and lex.  However, you only
+# need to have these programs if you need to make changes to the
+# bison or flex sources (see the next point, below).
+
+find_package(BISON QUIET)
+find_package(FLEX QUIET)
+
+# You may not even have bison and flex installed.  If you don't, no
+# sweat; Panda ships with the pre-generated output of these programs,
+# so you don't need them unless you want to make changes to the
+# grammars themselves (files named *.yxx or *.lxx).
+
+set(HAVE_BISON ${BISON_FOUND})
+set(HAVE_FLEX ${FLEX_FOUND})
+
+
+### Configure threading support ###
+set(CMAKE_THREAD_PREFER_PTHREAD ON)
+set(THREADS_PREFER_PTHREAD_FLAG ON)
+find_package(Threads QUIET)
+
+set(THREADS_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}")
+set(HAVE_POSIX_THREADS ${CMAKE_USE_PTHREADS_INIT})
+
+# Add basic use flag for threading
+package_option(THREADS
+  "If on, compile Panda3D with threading support.
+Building in support for threading will enable Panda to take
+advantage of multiple CPU's if you have them (and if the OS
+supports kernel threads running on different CPU's), but it will
+slightly slow down Panda for the single CPU case."
+  IMPORTED_AS Threads::Threads)
+
+# Configure debug threads
+option(DEBUG_THREADS "If on, enables debugging of thread and sync operations (i.e. mutexes, deadlocks)" OFF)
+list(APPEND PER_CONFIG_OPTIONS DEBUG_THREADS)
+set(DEBUG_THREADS_Debug ON CACHE BOOL "")
+
+option(SIMPLE_THREADS
+  "If on, compile with simulated threads.  Threads, by default, use
+OS-provided threading constructs, which usually allows for full
+multithreading support (i.e. the program can use multiple CPU's).
+On the other hand, compiling in this full OS-provided support can
+impose some substantial runtime overhead, making the application
+run slower on a single-CPU machine. This settings avoid the overhead,
+but still gain some of the basic functionality of threads." OFF)
+list(APPEND PER_CONFIG_OPTIONS SIMPLE_THREADS)
+
+option(OS_SIMPLE_THREADS
+  "If on, OS threading constructs will be used to perform context switches.
+A mutex is used to ensure that only one thread runs at a time, so the
+normal SIMPLE_THREADS optimizations still apply, and the normal
+SIMPLE_THREADS scheduler is used to switch between threads (instead
+of the OS scheduler).  This may be more portable and more reliable,
+but it is a hybrid between user-space threads and os-provided threads." ON)
+list(APPEND PER_CONFIG_OPTIONS OS_SIMPLE_THREADS)
+
+### Configure pipelining ###
+option(DO_PIPELINING "If on, compile with pipelined rendering." ON)
+
+### Miscellaneous configuration
+option(COMPILE_IN_DEFAULT_FONT
+  "If on, compiles in a default font, so that every TextNode will always
+have a font available without requiring the user to specify one.
+When turned off, the generated library will save a few kilobytes." ON)
+list(APPEND PER_CONFIG_OPTIONS COMPILE_IN_DEFAULT_FONT)
+set(COMPILE_IN_DEFAULT_FONT_MinSizeRel OFF CACHE BOOL "")
+
+option(STDFLOAT_DOUBLE
+  "Define this true to compile a special version of Panda to use a
+'double' floating-precision type for most internal values, such as
+positions and transforms, instead of the standard single-precision
+'float' type.  This does not affect the default numeric type of
+vertices, which is controlled by the runtime config variable
+vertices-float64." OFF)

+ 219 - 0
dtool/LocalSetup.cmake

@@ -0,0 +1,219 @@
+#
+# LocalSetup.cmake
+#
+# This file contains further instructions to set up the DTOOL package
+# when using CMake. In particular, it creates the dtool_config.h
+# file based on the user's selected configure variables.
+#
+
+include(CheckCXXSourceCompiles)
+include(CheckCSourceRuns)
+include(CheckIncludeFileCXX)
+include(CheckFunctionExists)
+include(CheckTypeSize)
+include(TestBigEndian)
+include(TestForSTDNamespace)
+
+# Check if this is a big-endian system.
+test_big_endian(WORDS_BIGENDIAN)
+
+# Define if we have lockf().
+check_cxx_source_compiles("
+#include <unistd.h>
+int main(int argc, char *argv[]) { lockf(0, F_LOCK, 0); return 0; }
+" PHAVE_LOCKF)
+
+# Define if we can trust the compiler not to insert extra bytes in
+# structs between base structs and derived structs.
+check_c_source_runs("
+struct A { int a; };
+struct B : public A { int b; };
+int main(int argc, char *argv[]) {
+  struct B i;
+  if ((size_t) &(i.b) == ((size_t) &(i.a)) + sizeof(struct A)) {
+    return 0;
+  } else {
+    return 1;
+  }
+}" SIMPLE_STRUCT_POINTERS)
+
+# Define if we have STL hash_map etc. available.
+# We're not using this functionality at the moment, it seems.
+set(HAVE_STL_HASH OFF)
+
+# Check if we have a gettimeofday() function.
+check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
+
+# Define if gettimeofday() takes only one parameter.
+check_cxx_source_compiles("
+#include <sys/time.h>
+int main(int argc, char *argv[]) {
+  struct timeval tv;
+  int result;
+  result = gettimeofday(&tv);
+  return 0;
+}" GETTIMEOFDAY_ONE_PARAM)
+
+# Check if we have getopt.
+check_function_exists(getopt HAVE_GETOPT)
+check_function_exists(getopt_long_only HAVE_GETOPT_LONG_ONLY)
+check_include_file_cxx(getopt.h PHAVE_GETOPT_H)
+
+# Define if you have ioctl(TIOCGWINSZ) to determine terminal width.
+#XXX can we make a test case for this that isn't dependent on
+# the current terminal?  It might also be useful for Cygwin users.
+if(UNIX)
+  set(IOCTL_TERMINAL_WIDTH 1)
+endif()
+
+# Do the system headers define key ios typedefs like ios::openmode
+# and ios::fmtflags?
+check_cxx_source_compiles("
+#include <ios>
+std::ios::openmode foo;
+std::ios::fmtflags bar;
+int main(int argc, char *argv[]) { return 0; }
+" HAVE_IOS_TYPEDEFS)
+
+# Define if the C++ iostream library defines ios::binary.
+check_cxx_source_compiles("
+#include <ios>
+std::ios::openmode binary = std::ios::binary;
+int main(int argc, char *argv[]) { return 0; }
+" HAVE_IOS_BINARY)
+
+# Can we safely call getenv() at static init time?
+if(WIN32 OR UNIX)
+  set(STATIC_INIT_GETENV 1)
+endif()
+
+# Can we read the file /proc/self/[*] to determine our
+# environment variables at static init time?
+if(IS_LINUX)
+  set(HAVE_PROC_SELF_EXE 1)
+  set(HAVE_PROC_SELF_MAPS 1)
+  set(HAVE_PROC_SELF_ENVIRON 1)
+  set(HAVE_PROC_SELF_CMDLINE 1)
+endif()
+
+if(IS_FREEBSD)
+  set(HAVE_PROC_CURPROC_FILE 1)
+  set(HAVE_PROC_CURPROC_MAP 1)
+  set(HAVE_PROC_CURPROC_CMDLINE 1)
+endif()
+
+# Do we have a global pair of argc/argv variables that we can read at
+# static init time? Should we prototype them? What are they called?
+if(WIN32)
+  set(HAVE_GLOBAL_ARGV ON)
+  set(PROTOTYPE_GLOBAL_ARGV OFF)
+  set(GLOBAL_ARGV __argv)
+  set(GLOBAL_ARGC __argc)
+endif()
+
+# Do we have all these header files?
+check_include_file_cxx(io.h PHAVE_IO_H)
+check_include_file_cxx(iostream PHAVE_IOSTREAM)
+check_include_file_cxx(malloc.h PHAVE_MALLOC_H)
+check_include_file_cxx(sys/malloc.h PHAVE_SYS_MALLOC_H)
+check_include_file_cxx(alloca.h PHAVE_ALLOCA_H)
+check_include_file_cxx(locale.h PHAVE_LOCALE_H)
+check_include_file_cxx(string.h PHAVE_STRING_H)
+check_include_file_cxx(stdlib.h PHAVE_STDLIB_H)
+check_include_file_cxx(limits.h PHAVE_LIMITS_H)
+check_include_file_cxx(sstream PHAVE_SSTREAM)
+check_include_file_cxx(new PHAVE_NEW)
+check_include_file_cxx(sys/types.h PHAVE_SYS_TYPES_H)
+check_include_file_cxx(sys/time.h PHAVE_SYS_TIME_H)
+check_include_file_cxx(unistd.h PHAVE_UNISTD_H)
+check_include_file_cxx(utime.h PHAVE_UTIME_H)
+check_include_file_cxx(glob.h PHAVE_GLOB_H)
+check_include_file_cxx(dirent.h PHAVE_DIRENT_H)
+check_include_file_cxx(ucontext.h PHAVE_UCONTEXT_H) #TODO doesn't work on OSX, use sys/ucontext.h
+check_include_file_cxx(linux/input.h PHAVE_LINUX_INPUT_H)
+check_include_file_cxx(stdint.h PHAVE_STDINT_H)
+
+# Do we have Posix threads?
+#set(HAVE_POSIX_THREADS ${CMAKE_USE_PTHREADS_INIT})
+
+# Do we have SSE2 support?
+include(CheckCXXCompilerFlag)
+check_cxx_compiler_flag(-msse2 HAVE_SSE2)
+
+# Set LINK_ALL_STATIC if we're building everything as static libraries.
+# Also set the library type used for "modules" appropriately.
+if(BUILD_SHARED_LIBS)
+  set(LINK_ALL_STATIC OFF)
+  set(MODULE_TYPE "MODULE"
+    CACHE INTERNAL "" FORCE)
+
+else()
+  set(LINK_ALL_STATIC ON)
+  set(MODULE_TYPE "STATIC"
+    CACHE INTERNAL "" FORCE)
+
+endif()
+
+# Now go through all the packages and report whether we have them.
+show_packages()
+
+message("")
+if(INTERROGATE_PYTHON_INTERFACE)
+  message("Compilation will generate Python interfaces for Python ${PYTHON_VERSION_STRING}.")
+else()
+  message("Configuring Panda WITHOUT Python interfaces.")
+endif()
+
+if(HAVE_THREADS)
+  if(SIMPLE_THREADS)
+    message("Compilation will include simulated threading support.")
+  elseif(DO_PIPELINING)
+    message("Compilation will include full, pipelined threading support.")
+  else()
+    message("Compilation will include nonpipelined threading support.")
+  endif()
+
+else()
+  message("Configuring Panda without threading support.")
+
+endif()
+
+message("")
+message("See dtool_config.h for more details about the specified configuration.")
+
+message("")
+
+# Generate dtool_config.h
+if(IS_MULTICONFIG)
+  foreach(config ${CMAKE_CONFIGURATION_TYPES})
+    foreach(option ${PER_CONFIG_OPTIONS})
+      # Check for the presence of a config-specific option, and override what's
+      # in the cache if there is.
+      if(DEFINED ${option}_${config})
+        set(${option} ${${option}_${config}})
+      endif()
+    endforeach(option)
+
+    # Generate a dtool_config.h for this specific config
+    configure_file(dtool_config.h.in "${PROJECT_BINARY_DIR}/${config}/include/dtool_config.h")
+
+    # unset() does not unset CACHE variables by default, just normal variables.
+    # By doing this we're reverting back to what was in the cache.
+    foreach(option ${PER_CONFIG_OPTIONS})
+      unset(${option})
+    endforeach(option)
+  endforeach(config)
+else()
+  # Just configure things like normal.
+  configure_file(dtool_config.h.in "${PROJECT_BINARY_DIR}/include/dtool_config.h")
+endif()
+
+install(FILES "${PANDA_OUTPUT_DIR}/include/dtool_config.h"
+  COMPONENT CoreDevel
+  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+
+# Generate the package configuration file
+export_packages("${PROJECT_BINARY_DIR}/Panda3DPackages.cmake")
+install(FILES "${PROJECT_BINARY_DIR}/Panda3DPackages.cmake"
+  COMPONENT CoreDevel
+  DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Panda3D")

+ 765 - 0
dtool/Package.cmake

@@ -0,0 +1,765 @@
+set(_thirdparty_dir_default "${PROJECT_SOURCE_DIR}/thirdparty")
+if(NOT (APPLE OR WIN32) OR NOT IS_DIRECTORY "${_thirdparty_dir_default}")
+  set(_thirdparty_dir_default "")
+endif()
+
+set(THIRDPARTY_DIRECTORY "${_thirdparty_dir_default}" CACHE PATH
+  "Optional location of a makepanda-style thirdparty directory. All libraries
+   located here will be prioritized over system libraries. Useful for
+   cross-compiling.")
+
+set(THIRDPARTY_DLLS)
+
+if(THIRDPARTY_DIRECTORY)
+  # This policy is necessary for PackageName_ROOT variables to be respected
+  if(POLICY CMP0074)
+    cmake_policy(GET CMP0074 _policy_cmp0074)
+  endif()
+
+  if(NOT _policy_cmp0074 STREQUAL "NEW")
+    message(FATAL_ERROR
+      "Your version of CMake is too old; please upgrade or unset THIRDPARTY_DIRECTORY to continue.")
+  endif()
+
+  # Dig up the actual "libs" directory
+  if(APPLE)
+    set(_package_dir "${THIRDPARTY_DIRECTORY}/darwin-libs-a")
+
+    # Make sure thirdparty has the first shot, not system frameworks
+    set(CMAKE_FIND_FRAMEWORK LAST)
+
+  elseif(WIN32)
+    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+      set(_package_dir "${THIRDPARTY_DIRECTORY}/win-libs-vc14-x64")
+
+      file(GLOB _python_dirs "${THIRDPARTY_DIRECTORY}/win-python*-x64")
+    else()
+      set(_package_dir "${THIRDPARTY_DIRECTORY}/win-libs-vc14")
+
+      file(GLOB _python_dirs "${THIRDPARTY_DIRECTORY}/win-python*")
+    endif()
+
+    list(REVERSE _python_dirs) # Descending order of version
+    if(NOT DEFINED Python_ROOT)
+      set(Python_ROOT "${_python_dirs}")
+    endif()
+
+    set(BISON_ROOT "${THIRDPARTY_DIRECTORY}/win-util")
+    set(FLEX_ROOT "${THIRDPARTY_DIRECTORY}/win-util")
+
+  else()
+    message(FATAL_ERROR
+      "You can't use THIRDPARTY_DIRECTORY on this platform. Unset it to continue.")
+
+  endif()
+
+  if(NOT EXISTS "${_package_dir}")
+    message(FATAL_ERROR
+      "Either your THIRDPARTY_DIRECTORY path does not exist, or it is for the wrong platform.")
+
+  endif()
+
+  foreach(_Package
+    ARToolKit
+    Assimp
+    Bullet
+    Cg
+    Eigen3
+    FCollada
+    FFMPEG
+    FMODEx
+    Freetype
+    HarfBuzz
+    JPEG
+    LibSquish
+    ODE
+    Ogg
+    OpenAL
+    OpenEXR
+    OpenSSL
+    OpusFile
+    PNG
+    SWResample
+    SWScale
+    TIFF
+    VorbisFile
+    VRPN
+    ZLIB
+  )
+
+    string(TOLOWER "${_Package}" _package)
+    string(TOUPPER "${_Package}" _PACKAGE)
+
+    # Some packages in the thirdparty dir have different subdirectory names from
+    # the name of the CMake package
+    if(_package STREQUAL "cg")
+      set(_package "nvidiacg")
+    elseif(_package STREQUAL "eigen3")
+      set(_package "eigen")
+    elseif(_package STREQUAL "ogg")
+      set(_package "vorbis") # It's in the same install dir here
+    elseif(_package STREQUAL "opusfile")
+      set(_package "opus")
+    elseif(_package STREQUAL "libsquish")
+      set(_package "squish")
+    elseif(_package STREQUAL "swresample" OR _package STREQUAL "swscale")
+      set(_package "ffmpeg") # These are also part of FFmpeg
+    elseif(_package STREQUAL "vorbisfile")
+      set(_package "vorbis")
+    endif()
+
+    # Set search path
+    set(${_Package}_ROOT "${_package_dir}/${_package}")
+
+    # Set up copying DLLs, if necessary
+    file(GLOB _dlls "${${_Package}_ROOT}/bin/*.dll")
+    if(_dlls)
+      set(_havevar "HAVE_${_PACKAGE}")
+      set(THIRDPARTY_DLLS_${_havevar} "${_dlls}")
+      list(APPEND THIRDPARTY_DLLS "${_havevar}")
+
+    endif()
+
+  endforeach(_Package)
+
+endif()
+
+# This is used to copy the DLLs alongside the output of `package`
+function(thirdparty_copy_alongside package)
+  set(_dlls)
+
+  foreach(_havevar ${THIRDPARTY_DLLS})
+    if(${_havevar})
+      list(APPEND _dlls ${THIRDPARTY_DLLS_${_havevar}})
+    endif()
+  endforeach(_havevar)
+
+  if(NOT _dlls)
+    # Don't try to copy/install nothingness
+    return()
+  endif()
+
+  add_custom_command(TARGET ${package} POST_BUILD
+    COMMAND ${CMAKE_COMMAND} -E copy_if_different
+      ${_dlls} $<TARGET_FILE_DIR:${package}>
+  )
+
+  # Also install the DLLs
+  install(FILES ${_dlls} DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+endfunction(thirdparty_copy_alongside)
+
+#
+# ------------ Python ------------
+#
+
+set(WANT_PYTHON_VERSION ""
+  CACHE STRING "Which Python version to seek out for building Panda3D against.")
+
+if(DEFINED _PREV_WANT_PYTHON_VERSION
+    AND NOT _PREV_WANT_PYTHON_VERSION STREQUAL WANT_PYTHON_VERSION)
+  # The user changed WANT_PYTHON_VERSION. We need to force FindPython to start
+  # anew, deleting any variable that was autodetected last time
+  foreach(_prev_var ${_PREV_PYTHON_VALUES})
+    string(REPLACE "=" ";" _prev_var "${_prev_var}")
+    list(GET _prev_var 0 _prev_var_name)
+    list(GET _prev_var 1 _prev_var_sha1)
+    string(SHA1 _current_var_sha1 "${${_prev_var_name}}")
+
+    if(_prev_var_sha1 STREQUAL _current_var_sha1)
+      unset(${_prev_var_name} CACHE)
+    endif()
+
+  endforeach(_prev_var)
+
+  unset(_PREV_PYTHON_VALUES CACHE)
+
+endif()
+
+if(WANT_PYTHON_VERSION)
+  # A specific version is requested; ensure we get that specific version
+  list(APPEND WANT_PYTHON_VERSION "EXACT")
+endif()
+
+get_directory_property(_old_cache_vars CACHE_VARIABLES)
+find_package(Python ${WANT_PYTHON_VERSION} QUIET COMPONENTS Interpreter Development)
+
+if(Python_FOUND)
+  set(PYTHON_FOUND ON)
+  set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
+  set(PYTHON_INCLUDE_DIRS ${Python_INCLUDE_DIRS})
+  set(PYTHON_LIBRARY_DIRS ${Python_LIBRARY_DIRS})
+  set(PYTHON_VERSION_STRING ${Python_VERSION})
+
+elseif(CMAKE_VERSION VERSION_LESS "3.12")
+  find_package(PythonInterp ${WANT_PYTHON_VERSION} QUIET)
+  find_package(PythonLibs ${PYTHON_VERSION_STRING} QUIET)
+
+  if(PYTHONLIBS_FOUND)
+    set(PYTHON_FOUND ON)
+
+    if(NOT PYTHON_VERSION_STRING)
+      set(PYTHON_VERSION_STRING ${PYTHONLIBS_VERSION_STRING})
+    endif()
+  endif()
+
+endif()
+
+if(CMAKE_VERSION VERSION_LESS "3.15")
+  # CMake versions this old don't provide Python::Module, so we need to hack up
+  # the variables to ensure no explicit linkage against libpython occurs
+
+  if(WIN32)
+    # Nothing needed here; explicit linkage is appropriate
+    set(PYTHON_LIBRARY "${Python_LIBRARY}")
+    set(PYTHON_LIBRARIES ${Python_LIBRARIES})
+
+  elseif(APPLE OR UNIX)
+    # Just unset and let the implicit linkage take over
+    set(PYTHON_LIBRARY "")
+    set(PYTHON_LIBRARIES "")
+
+    if(APPLE)
+      # macOS requires this explicit flag on the linker command line to allow the
+      # references to the Python symbols to resolve at dynamic link time
+      string(APPEND CMAKE_MODULE_LINKER_FLAGS " -undefined dynamic_lookup")
+
+    endif()
+
+  else()
+    # On every other platform, guessing is a bad idea - insist the user upgrade
+    # their CMake instead.
+    message(WARNING "For Python support on this platform, please use CMake >= 3.15!")
+    set(PYTHON_FOUND OFF)
+
+  endif()
+
+endif()
+
+package_option(Python
+  DEFAULT ON
+  "Enables support for Python.  If INTERROGATE_PYTHON_INTERFACE
+is also enabled, Python bindings will be generated."
+  IMPORTED_AS Python::Module)
+
+# Also detect the optimal install paths:
+if(HAVE_PYTHON)
+  if(WIN32 AND NOT CYGWIN)
+    set(_LIB_DIR ".")
+    set(_ARCH_DIR ".")
+
+  elseif(PYTHON_EXECUTABLE)
+    execute_process(
+      COMMAND ${PYTHON_EXECUTABLE}
+        -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(False))"
+      OUTPUT_VARIABLE _LIB_DIR
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+    execute_process(
+      COMMAND ${PYTHON_EXECUTABLE}
+        -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))"
+      OUTPUT_VARIABLE _ARCH_DIR
+      OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  else()
+    set(_LIB_DIR "")
+    set(_ARCH_DIR "")
+
+  endif()
+
+  execute_process(
+    COMMAND ${PYTHON_EXECUTABLE}
+      -c "from sysconfig import get_config_var as g; print((g('EXT_SUFFIX') or g('SO'))[:])"
+    OUTPUT_VARIABLE _EXT_SUFFIX
+    ERROR_QUIET
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(NOT _EXT_SUFFIX)
+    if(CYGWIN)
+      set(_EXT_SUFFIX ".dll")
+    elseif(WIN32)
+      set(_EXT_SUFFIX ".pyd")
+    else()
+      set(_EXT_SUFFIX ".so")
+    endif()
+  endif()
+
+  set(PYTHON_LIB_INSTALL_DIR "${_LIB_DIR}" CACHE STRING
+    "Path to the Python architecture-independent package directory.")
+
+  set(PYTHON_ARCH_INSTALL_DIR "${_ARCH_DIR}" CACHE STRING
+    "Path to the Python architecture-dependent package directory.")
+
+  set(PYTHON_EXTENSION_SUFFIX "${_EXT_SUFFIX}" CACHE STRING
+    "Suffix for Python binary extension modules.")
+
+endif()
+
+if(NOT DEFINED _PREV_PYTHON_VALUES)
+  # We need to make note of all auto-defined Python variables
+  set(_prev_python_values)
+
+  get_directory_property(_new_cache_vars CACHE_VARIABLES)
+  foreach(_cache_var ${_new_cache_vars})
+    if(_cache_var MATCHES "^(Python|PYTHON)_" AND NOT _old_cache_vars MATCHES ";${_cache_var};")
+      string(SHA1 _cache_var_sha1 "${${_cache_var}}")
+      list(APPEND _prev_python_values "${_cache_var}=${_cache_var_sha1}")
+    endif()
+  endforeach(_cache_var)
+
+  set(_PREV_PYTHON_VALUES "${_prev_python_values}" CACHE INTERNAL "Internal." FORCE)
+endif()
+
+set(_PREV_WANT_PYTHON_VERSION "${WANT_PYTHON_VERSION}" CACHE INTERNAL "Internal." FORCE)
+
+
+#
+# ------------ Data handling libraries ------------
+#
+
+# OpenSSL
+find_package(OpenSSL COMPONENTS SSL Crypto QUIET)
+
+package_option(OpenSSL
+  DEFAULT ON
+  "Enable OpenSSL support"
+  IMPORTED_AS OpenSSL::SSL OpenSSL::Crypto)
+
+option(REPORT_OPENSSL_ERRORS
+  "Define this true to include the OpenSSL code to report verbose
+error messages when they occur." OFF)
+option(REPORT_OPENSSL_ERRORS_Debug "" ON)
+
+package_status(OpenSSL "OpenSSL")
+
+# zlib
+find_package(ZLIB QUIET)
+
+package_option(ZLIB
+  "Enables support for compression of Panda assets."
+  IMPORTED_AS ZLIB::ZLIB)
+
+package_status(ZLIB "zlib")
+
+
+#
+# ------------ Image formats ------------
+#
+
+# JPEG
+find_package(JPEG QUIET)
+
+package_option(JPEG "Enable support for loading .jpg images.")
+
+package_status(JPEG "libjpeg")
+
+# PNG
+find_package(PNG QUIET)
+
+package_option(PNG
+  "Enable support for loading .png images."
+  IMPORTED_AS PNG::PNG)
+
+package_status(PNG "libpng")
+
+# TIFF
+find_package(TIFF QUIET)
+
+package_option(TIFF "Enable support for loading .tif images.")
+
+package_status(TIFF "libtiff")
+
+# OpenEXR
+find_package(OpenEXR QUIET)
+
+package_option(OpenEXR "Enable support for loading .exr images.")
+
+package_status(OpenEXR "OpenEXR")
+
+# libsquish
+find_package(LibSquish QUIET)
+
+package_option(SQUISH
+  "Enables support for automatic compression of DXT textures."
+  FOUND_AS LibSquish)
+
+package_status(SQUISH "libsquish")
+
+
+#
+# ------------ Asset formats ------------
+#
+
+# Assimp
+find_package(Assimp QUIET)
+
+package_option(Assimp
+  "Build pandatool with support for loading 3D assets supported by Assimp.")
+
+package_status(Assimp "Assimp")
+
+# FCollada
+find_package(FCollada QUIET)
+
+package_option(FCollada
+  "Build pandatool with support for loading Collada files using FCollada."
+  IMPORTED_AS FCollada::FCollada)
+
+package_status(FCollada "FCollada")
+
+
+#
+# ------------ Math libraries ------------
+#
+
+# Eigen
+find_package(Eigen3 QUIET)
+
+package_option(EIGEN
+  "Enables use of the Eigen linear algebra library.
+If this is provided, Panda will use this library as the fundamental
+implementation of its own linmath library; otherwise, it will use
+its own internal implementation.  The primary advantage of using
+Eigen is SSE2 support, which is only activated if LINMATH_ALIGN
+is also enabled."
+  FOUND_AS Eigen3
+  LICENSE "MPL-2")
+
+option(LINMATH_ALIGN
+  "This is required for activating SSE2 support using Eigen.
+Activating this does constrain most objects in Panda to 16-byte
+alignment, which could impact memory usage on very-low-memory
+platforms.  Currently experimental." ON)
+
+if(LINMATH_ALIGN)
+  package_status(EIGEN "Eigen linear algebra library" "vectorization enabled in build")
+else()
+  package_status(EIGEN "Eigen linear algebra library" "vectorization NOT enabled in build")
+endif()
+
+# FFTW
+# FFTW 3.3.7, when built with autotools, doesn't install
+# FFTW3LibraryDepends.cmake, which will crash us if we use CONFIG mode.  BAH!
+# Force MODULE mode to fix that.
+find_package(FFTW3 MODULE QUIET)
+
+package_option(FFTW
+  "This enables support for compression of animations in .bam files.
+  This is only necessary for creating or reading .bam files containing
+  compressed animations."
+  FOUND_AS "FFTW3"
+  LICENSE "GPL")
+
+package_status(FFTW "FFTW")
+
+
+#
+# ------------ Multimedia formats ------------
+#
+
+# FFmpeg
+find_package(FFMPEG QUIET)
+find_package(SWScale QUIET)
+find_package(SWResample QUIET)
+
+package_option(FFMPEG
+  "Enables support for audio- and video-decoding using the FFmpeg library.")
+package_option(SWScale
+  "Enables support for FFmpeg's libswscale for video rescaling.")
+package_option(SWResample
+  "Enables support for FFmpeg's libresample for audio resampling.")
+
+if(HAVE_SWSCALE AND HAVE_SWRESAMPLE)
+  set(ffmpeg_features "with swscale and swresample")
+elseif(HAVE_SWSCALE)
+  set(ffmpeg_features "with swscale")
+elseif(HAVE_SWRESAMPLE)
+  set(ffmpeg_features "with swresample")
+else()
+  set(ffmpeg_features "without resampling/rescaling support")
+endif()
+package_status(FFMPEG "FFmpeg" "${ffmpeg_features}")
+
+# Vorbis
+find_package(VorbisFile QUIET)
+
+package_option(VORBIS
+  FOUND_AS VorbisFile
+  "Enables support for decoding Vorbis-encoded .ogg audio files via libvorbisfile.")
+
+package_status(VORBIS "Vorbis")
+
+# Opus
+find_package(OpusFile QUIET)
+
+package_option(OPUS
+  FOUND_AS OpusFile
+  "Enables support for decoding .opus audio files via libopusfile.")
+
+package_status(OPUS "Opus")
+
+#
+# ------------ Audio libraries ------------
+#
+
+# FMOD Ex
+find_package(FMODEx QUIET)
+
+package_option(FMODEx
+  "This enables support for the FMOD Ex sound library,
+  from Firelight Technologies. This audio library is free for non-commercial
+  use."
+  LICENSE "FMOD")
+
+package_status(FMODEx "FMOD Ex sound library")
+
+# OpenAL
+find_package(OpenAL QUIET)
+
+package_option(OpenAL
+  "This enables support for audio output via OpenAL. Some platforms, such as
+  macOS, provide their own OpenAL implementation, which Panda3D can use. But,
+  on most platforms this will imply OpenAL Soft, which is LGPL licensed."
+  IMPORTED_AS OpenAL::OpenAL
+  LICENSE "LGPL")
+
+package_status(OpenAL "OpenAL sound library")
+
+if(OpenAL_FOUND AND APPLE OR OPENAL_FOUND AND APPLE)
+  set(HAVE_OPENAL_FRAMEWORK YES)
+endif()
+
+
+#
+# ------------ UI libraries ------------
+#
+
+# Freetype
+
+find_package(Freetype QUIET)
+
+package_option(Freetype
+  "This enables support for the FreeType font-rendering library.  If disabled,
+  Panda3D will only be able to read fonts specially made with egg-mkfont."
+  IMPORTED_AS freetype)
+
+package_status(Freetype "FreeType")
+
+# HarfBuzz
+
+# Some versions of harfbuzz-config.cmake contain an endless while loop, so we
+# force MODULE mode here.
+find_package(HarfBuzz MODULE QUIET)
+
+package_option(HarfBuzz
+  "This enables support for the HarfBuzz text shaping library."
+  IMPORTED_AS harfbuzz::harfbuzz)
+
+package_status(HarfBuzz "HarfBuzz")
+
+# GTK2
+
+set(Freetype_FIND_QUIETLY TRUE) # Fix for builtin FindGTK2
+set(GTK2_GTK_FIND_QUIETLY TRUE) # Fix for builtin FindGTK2
+find_package(GTK2 QUIET COMPONENTS gtk)
+
+package_option(GTK2)
+
+package_status(GTK2 "gtk+-2")
+
+
+#
+# ------------ Physics engines ------------
+#
+
+# Bullet
+find_package(Bullet MODULE QUIET)
+
+package_option(Bullet
+  "Enable this option to support game dynamics with the Bullet physics library.")
+
+package_status(Bullet "Bullet physics")
+
+# ODE
+find_package(ODE QUIET)
+
+package_option(ODE
+  "Enable this option to support game dynamics with the Open Dynamics Engine (ODE)."
+  LICENSE "BSD-3"
+  IMPORTED_AS ODE::ODE)
+
+package_status(ODE "Open Dynamics Engine")
+
+
+#
+# ------------ SpeedTree ------------
+#
+
+# SpeedTree
+find_package(SpeedTree QUIET)
+
+package_option(SpeedTree
+  "Enable this option to include scenegraph support for SpeedTree trees."
+  LICENSE "SpeedTree")
+
+package_status(SpeedTree "SpeedTree")
+
+
+#
+# ------------ Rendering APIs ------------
+#
+
+# OpenGL
+find_package(OpenGL QUIET)
+
+package_option(GL
+  "Enable OpenGL support."
+  FOUND_AS OPENGL
+  IMPORTED_AS OpenGL::GL)
+
+package_status(GL "OpenGL")
+
+# OpenGL ES 1
+if(NOT APPLE) # Apple X11 ships the GLES headers but they're broken
+  find_package(OpenGLES1 QUIET)
+endif()
+
+package_option(GLES1
+  "Enable support for OpenGL ES 1.x rendering APIs."
+  FOUND_AS OPENGLES1)
+
+package_status(GLES1 "OpenGL ES 1.x")
+
+# OpenGL ES 2
+if(NOT APPLE) # Apple X11 ships the GLES headers but they're broken
+  find_package(OpenGLES2 QUIET)
+endif()
+
+package_option(GLES2
+  "Enable support for OpenGL ES 2.x rendering APIs."
+  FOUND_AS OPENGLES2)
+
+package_status(GLES2 "OpenGL ES 2.x")
+
+# Direct3D 9
+find_package(Direct3D9 QUIET COMPONENTS dxguid dxerr d3dx9)
+
+package_option(DX9
+  "Enable support for DirectX 9.  This is typically only viable on Windows."
+  FOUND_AS Direct3D9)
+
+package_status(DX9 "Direct3D 9.x")
+
+# Nvidia Cg
+find_package(Cg QUIET)
+
+package_option(CG
+  "Enable support for Nvidia Cg Shading Language"
+  LICENSE "Nvidia")
+package_option(CGGL
+  "Enable support for Nvidia Cg's OpenGL API."
+  LICENSE "Nvidia")
+package_option(CGD3D9
+  "Enable support for Nvidia Cg's Direct3D 9 API."
+  LICENSE "Nvidia")
+
+if(HAVE_CGGL AND HAVE_CGD3D9)
+  set(cg_apis "supporting OpenGL and Direct3D 9")
+elseif(HAVE_CGGL)
+  set(cg_apis "supporting OpenGL")
+elseif(HAVE_CGDX9)
+  set(cg_apis "supporting Direct3D 9")
+else()
+  set(cg_apis "WITHOUT rendering backend support")
+endif()
+package_status(CG "Nvidia Cg Shading Language" "${cg_apis}")
+
+
+#
+# ------------ Display APIs ------------
+#
+
+# X11 (and GLX)
+
+if(NOT APPLE)
+  find_package(X11 QUIET)
+endif()
+
+if(NOT X11_Xkb_FOUND OR NOT X11_Xutil_FOUND)
+  # Panda implicitly requires these supplementary X11 libs; if we can't find
+  # them, we just say we didn't find X11 at all.
+  set(X11_FOUND OFF)
+endif()
+
+package_option(X11
+  "Provides X-server support on Unix platforms. X11 may need to be linked
+against for tinydisplay, but probably only on a Linux platform.")
+
+set(HAVE_GLX_AVAILABLE OFF)
+if(HAVE_GL AND HAVE_X11 AND NOT APPLE)
+  set(HAVE_GLX_AVAILABLE ON)
+endif()
+
+option(HAVE_GLX "Enables GLX. Requires OpenGL and X11." ${HAVE_GLX_AVAILABLE})
+if(HAVE_GLX AND NOT HAVE_GLX_AVAILABLE)
+  message(SEND_ERROR "HAVE_GLX manually set to ON but it is not available!")
+endif()
+
+if(HAVE_GLX)
+  package_status(X11 "X11" "with GLX")
+else()
+  package_status(X11 "X11" "without GLX")
+endif()
+
+# EGL
+find_package(EGL QUIET)
+
+package_option(EGL
+  "Enable support for the Khronos EGL context management interface for
+  OpenGL ES.  This is necessary to support OpenGL ES under X11.")
+
+package_status(EGL "EGL")
+
+#
+# ------------ Vision tools ------------
+#
+
+# OpenCV
+find_package(OpenCV QUIET COMPONENTS core highgui OPTIONAL_COMPONENTS videoio)
+
+package_option(OpenCV
+  "Enable support for OpenCV.  This will be built into the 'vision' package."
+  FOUND_AS OpenCV)
+
+package_status(OpenCV "OpenCV")
+
+# CMake <3.7 doesn't support GREATER_EQUAL, so this uses NOT LESS instead.
+if(NOT OpenCV_VERSION_MAJOR LESS 3)
+  set(OPENCV_VER_3 ON)
+
+elseif(NOT OpenCV_VERSION_MAJOR LESS 2 AND
+       NOT OpenCV_VERSION_MINOR LESS 3)
+  set(OPENCV_VER_23 ON)
+
+endif()
+
+# ARToolKit
+find_package(ARToolKit QUIET)
+
+package_option(ARToolKit
+  "Enable support for ARToolKit.  This will be built into the 'vision' package.")
+
+package_status(ARToolKit "ARToolKit")
+
+
+#
+# ------------ VR integration ------------
+#
+
+# VRPN
+find_package(VRPN QUIET)
+
+package_option(VRPN
+  "Enables support for connecting to VRPN servers.  This is only needed if you
+  are building Panda3D for a fixed VRPN-based VR installation.")
+
+package_status(VRPN "VRPN")

+ 103 - 0
dtool/PandaVersion.cmake

@@ -0,0 +1,103 @@
+# This file defines the current version number for Panda. It is read
+# by the top CMakeLists.txt, which puts it in the global namespace for
+# all CMake scripts for Panda.
+
+option(PANDA_OFFICIAL_VERSION
+  "This variable will be defined to false in the CVS repository, but
+scripts that generate source tarballs and/or binary releases for
+distribution, by checking out Panda from an official CVS tag,
+should explictly set this to true.  When false, it indicates that
+the current version of Panda was checked out from CVS, so it may
+not be a complete representation of the indicated version."
+  OFF)
+
+set(PANDA_DISTRIBUTOR homebuilt CACHE STRING
+  "This string is reported verbatim by PandaSystem::get_distributor().
+It should be set by whoever provides a particular distribution of
+Panda.  If you build your own Panda, leave this unchanged.")
+
+set(PANDA_DIST_USE_LICENSES "BSD-3;BSD-2;MIT" CACHE STRING
+  "This is a list of allowed licenses for 3rd-party packages to build
+support for when performing a Distribution build of Panda3d.
+Note: This only is checked for packages that CMake has declared with a
+particular license. Some packages don't have a listed license because
+they are almost always required/used, or because they are only used in
+plugins that can be easily removed (eg. directx, ffmpeg, fmod, ...).")
+
+set(PANDA_PACKAGE_VERSION CACHE STRING
+  "This string is used to describe the Panda3D \"package\" associated
+with this current build of Panda. It should increment with major
+and minor version changes, but not sequence (or \"bugfix\") changes.
+It should be unique for each unique distributor. The default is
+the empty string, which means this build does not precisely match
+any distributable Panda3D packages. If you are making a Panda3D
+build which you will be using to produce a distributable Panda3D
+package, you should set this string appropriately.")
+
+set(P3D_PLUGIN_VERSION "1.0.4" CACHE STRING
+  "We also define a version for the Panda3D plugin/runtime,
+i.e. nppanda3d.dll, p3dactivex.ocx, and panda3d.exe. This is an
+independent version number from PANDA_VERSION or
+PANDA_PACKAGE_VERSION, because it is anticipated that this plugin
+code, once settled, will need to be updated much less frequently
+than Panda itself.")
+
+set(P3D_COREAPI_VERSION "${P3D_PLUGIN_VERSION}.1" CACHE STRING
+  "Finally, there's a separate version number for the Core API. At
+first, we didn't believe we needed a Core API version number, but
+in this belief we were naive.  This version number is a little less
+strict in its format requirements than P3D_PLUGIN_VERSION, above,
+and it doesn't necessarily consist of a specific number of
+integers, but by convention it will consist of four integers, with
+the first three matching the plugin version, and the fourth integer
+being incremented with each new Core API revision.")
+
+mark_as_advanced(PANDA_VERSION PANDA_OFFICIAL_VERSION
+  PANDA_PACKAGE_VERSION P3D_PLUGIN_VERSION P3D_COREAPI_VERSION
+  PANDA_DIST_USE_LICENSES)
+
+# The version gets a "c" at the end if it's not an official one.
+if(PANDA_OFFICIAL_VERSION)
+  set(VERSION_SUFFIX "")
+else()
+  set(VERSION_SUFFIX "c")
+endif()
+
+set(PANDA_VERSION_STR "${PROJECT_VERSION}${VERSION_SUFFIX}")
+
+# This symbol is used to enforce ABI incompatibility between
+# major versions of Panda3D.
+set(PANDA_VERSION_SYMBOL panda_version_${PROJECT_VERSION_MAJOR}_${PROJECT_VERSION_MINOR})
+
+# The Panda version as a number, with three digits reserved
+# for each component.
+math(EXPR PANDA_NUMERIC_VERSION "${PROJECT_VERSION_MAJOR}*1000000 + ${PROJECT_VERSION_MINOR}*1000 + ${PROJECT_VERSION_PATCH}")
+
+# The Panda Git SHA1 refspec, for PandaSystem::get_git_commit()
+find_package(Git QUIET)
+if(GIT_EXECUTABLE)
+  execute_process(
+    COMMAND "${GIT_EXECUTABLE}" rev-parse HEAD
+    WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+    OUTPUT_VARIABLE PANDA_GIT_COMMIT_STR
+    ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
+endif()
+
+# Separate the plugin version into its three components.
+string(REPLACE "." ";" P3D_PLUGIN_VERSION_LIST "${P3D_PLUGIN_VERSION}")
+list(GET P3D_PLUGIN_VERSION_LIST 0 P3D_PLUGIN_MAJOR_VERSION)
+list(GET P3D_PLUGIN_VERSION_LIST 1 P3D_PLUGIN_MINOR_VERSION)
+list(GET P3D_PLUGIN_VERSION_LIST 2 P3D_PLUGIN_SEQUENCE_VERSION)
+
+set(P3D_PLUGIN_VERSION_STR "${P3D_PLUGIN_VERSION}${VERSION_SUFFIX}")
+
+# The plugin version as dot-delimited integer quad, according to MS
+# conventions for DLL version numbers.
+if(PANDA_OFFICIAL_VERSION)
+  set(P3D_PLUGIN_DLL_DOT_VERSION "${P3D_PLUGIN_VERSION}.1000")
+else()
+  set(P3D_PLUGIN_DLL_DOT_VERSION "${P3D_PLUGIN_VERSION}.0")
+endif()
+
+# The same thing as a comma-delimited quad.
+string(REPLACE "." "," P3D_PLUGIN_DLL_COMMA_VERSION "${P3D_PLUGIN_DLL_DOT_VERSION}")

+ 251 - 0
dtool/dtool_config.h.in

@@ -0,0 +1,251 @@
+/* dtool_config.h.  Generated automatically by CMake. */
+#ifndef DTOOL_CONFIG_H
+#define DTOOL_CONFIG_H
+
+/* Define if we have Eigen available. */
+#cmakedefine HAVE_EIGEN
+#cmakedefine LINMATH_ALIGN
+
+/* Define if we have Python installed.  */
+#cmakedefine HAVE_PYTHON
+#cmakedefine USE_DEBUG_PYTHON
+/* Define if we have Python as a framework (Mac OS X).  */
+#cmakedefine PYTHON_FRAMEWORK
+
+/* Define if we have OpenAL installed as a framework. */
+#cmakedefine HAVE_OPENAL_FRAMEWORK
+
+/* Define if we have Freetype 2.0 or better available. */
+#cmakedefine HAVE_FREETYPE
+
+/* Define if we want to compile in a default font. */
+#cmakedefine COMPILE_IN_DEFAULT_FONT
+
+/* Define to use doubles for most numbers, intead of single-precision floats. */
+#cmakedefine STDFLOAT_DOUBLE
+
+/* Define if we have built libRocket available and built with Python support. */
+#cmakedefine HAVE_ROCKET_PYTHON
+
+/* Define if we have ARToolKit available. */
+#cmakedefine HAVE_ARTOOLKIT
+
+/* Define if we have libvorbisfile available. */
+#cmakedefine HAVE_VORBIS
+
+/* Define if we have libopus available. */
+#cmakedefine HAVE_OPUS
+
+/* Define if we have OpenSSL installed.  */
+#cmakedefine HAVE_OPENSSL
+
+/* Define if we have libjpeg installed.  */
+#cmakedefine HAVE_JPEG
+
+/* Define to build video-for-linux. */
+#cmakedefine HAVE_VIDEO4LINUX
+
+/* Define if we have libpng installed.  */
+#cmakedefine HAVE_PNG
+
+/* Define if we have libtiff installed.  */
+#cmakedefine HAVE_TIFF
+
+/* Define if we have OpenEXR installed.  */
+#cmakedefine HAVE_OPENEXR
+
+/* Define if we want to build these other image file formats. */
+#cmakedefine HAVE_SGI_RGB
+#cmakedefine HAVE_TGA
+#cmakedefine HAVE_IMG
+#cmakedefine HAVE_SOFTIMAGE_PIC
+#cmakedefine HAVE_BMP
+#cmakedefine HAVE_PNM
+
+/* Define if we have CG installed.  */
+#cmakedefine HAVE_CG
+
+/* Define if we have zlib installed.  */
+#cmakedefine HAVE_ZLIB
+
+/* Define if we have OpenGL installed and want to build for GL.  */
+#cmakedefine MIN_GL_VERSION_MAJOR
+#cmakedefine MIN_GL_VERSION_MINOR
+
+/* Define if we have OpenCV installed and want to build for OpenCV.  */
+#cmakedefine HAVE_OPENCV
+
+/* The choice of generic vs. the specific dxerr library largely
+   depends on which SDK you have installed. */
+#cmakedefine USE_GENERIC_DXERR_LIBRARY
+
+/* Define if we have the SDL library. */
+#cmakedefine HAVE_SDL
+
+/* Define if we have X11. */
+#cmakedefine HAVE_X11
+
+/* Define if we want to compile the threading code.  */
+#cmakedefine HAVE_THREADS
+
+/* Define if we want to use fast, user-space simulated threads.  */
+#cmakedefine SIMPLE_THREADS
+
+/* Define to enable deadlock detection, mutex recursion checks, etc. */
+#cmakedefine DEBUG_THREADS
+
+/* Define to implement mutexes and condition variables via a user-space spinlock. */
+#cmakedefine MUTEX_SPINLOCK
+
+/* Define to enable the PandaFileStream implementation of pfstream etc. */
+#cmakedefine USE_PANDAFILESTREAM
+
+/* Define if we want to compile the net code.  */
+#cmakedefine HAVE_NET
+
+/* Define if we want to compile the audio code.  */
+#cmakedefine HAVE_AUDIO
+
+/* Define if we want to use PStats.  */
+#cmakedefine DO_PSTATS
+
+/* Define if we want to type-check downcasts.  */
+#cmakedefine DO_DCAST
+
+/* Define if we want to provide collision system recording and
+   visualization tools. */
+#cmakedefine DO_COLLISION_RECORDING
+
+/* Define if we want to enable track-memory-usage.  */
+#cmakedefine DO_MEMORY_USAGE
+
+/* Define if we want to enable min-lag and max-lag.  */
+#cmakedefine SIMULATE_NETWORK_DELAY
+
+/* Define if we want to allow immediate mode OpenGL rendering.  */
+#cmakedefine SUPPORT_IMMEDIATE_MODE
+
+/* Define if we want to support fixed-function OpenGL rendering. */
+#cmakedefine SUPPORT_FIXED_FUNCTION
+
+/* Define for either of the alternative malloc schemes. */
+#cmakedefine USE_MEMORY_DLMALLOC
+#cmakedefine USE_MEMORY_PTMALLOC2
+
+/* Define if we want to compile in support for pipelining.  */
+#cmakedefine DO_PIPELINING
+
+/* Define if we want to keep Notify debug messages around, or undefine
+   to compile them out.  */
+#cmakedefine NOTIFY_DEBUG
+
+/* The compiled-in character(s) to expect to separate different
+   components of a path list (e.g. $PRC_PATH). */
+#define DEFAULT_PATHSEP "@DEFAULT_PATHSEP@"
+
+/* Many of the prc variables are exported by
+   dtool/src/prc/prc_parameters.h.pp, instead of here.  Only those prc
+   variables that must be visible outside of the prc directory are
+   exported here. */
+
+/* Define if you want to save the descriptions for ConfigVariables. */
+#cmakedefine PRC_SAVE_DESCRIPTIONS
+
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#cmakedefine WORDS_BIGENDIAN
+
+/* Define if we can trust the compiler not to insert extra bytes in
+   structs between base structs and derived structs. */
+#cmakedefine SIMPLE_STRUCT_POINTERS
+
+/* Define if we have Dinkumware STL installed.  */
+#cmakedefine HAVE_DINKUM
+
+/* Define if we have STL hash_map etc. available  */
+#cmakedefine HAVE_STL_HASH
+
+/* Define if you have the getopt function.  */
+#cmakedefine HAVE_GETOPT
+
+/* Define if you have the getopt_long_only function.  */
+#cmakedefine HAVE_GETOPT_LONG_ONLY
+
+/* Define if getopt appears in getopt.h.  */
+#cmakedefine PHAVE_GETOPT_H
+
+/* Do the system headers define key ios typedefs like ios::openmode
+   and ios::fmtflags? */
+#cmakedefine HAVE_IOS_TYPEDEFS
+
+/* Define if you have the <io.h> header file.  */
+#cmakedefine PHAVE_IO_H
+
+/* Define if you have the <iostream> header file.  */
+#cmakedefine PHAVE_IOSTREAM
+
+/* Define if you have the <malloc.h> header file.  */
+#cmakedefine PHAVE_MALLOC_H
+
+/* Define if you have the <sys/malloc.h> header file.  */
+#cmakedefine PHAVE_SYS_MALLOC_H
+
+/* Define if you have the <alloca.h> header file.  */
+#cmakedefine PHAVE_ALLOCA_H
+
+/* Define if you have the <locale.h> header file.  */
+#cmakedefine PHAVE_LOCALE_H
+
+/* Define if you have the <string.h> header file.  */
+#cmakedefine PHAVE_STRING_H
+
+/* Define if you have the <stdlib.h> header file.  */
+#cmakedefine PHAVE_STDLIB_H
+
+/* Define if you have the <limits.h> header file.  */
+#cmakedefine PHAVE_LIMITS_H
+
+/* Define if you have the <sstream> header file.  */
+#cmakedefine PHAVE_SSTREAM
+
+/* Define if you have the <new> header file.  */
+#cmakedefine PHAVE_NEW
+
+/* Define if you have the <sys/types.h> header file.  */
+#cmakedefine PHAVE_SYS_TYPES_H
+
+/* Define if you have the <sys/time.h> header file.  */
+#cmakedefine PHAVE_SYS_TIME_H
+
+/* Define if you have the <unistd.h> header file.  */
+#cmakedefine PHAVE_UNISTD_H
+
+/* Do we have <linux/input.h> ? This enables us to use raw mouse input. */
+#cmakedefine PHAVE_LINUX_INPUT_H
+
+/* Do we have <stdint.h>? */
+#cmakedefine PHAVE_STDINT_H
+
+/* Do we have Posix threads? */
+#cmakedefine HAVE_POSIX_THREADS
+
+/* Is the code being compiled with the Tau profiler's instrumentor? */
+#cmakedefine USE_TAU
+
+// To activate the DELETED_CHAIN macros.
+#cmakedefine USE_DELETED_CHAIN
+
+// If we are to build the native net interfaces.
+#cmakedefine WANT_NATIVE_NET
+
+/* Static linkage instead of the normal dynamic linkage? */
+#cmakedefine LINK_ALL_STATIC
+
+/* Platform-identifying defines. */
+#cmakedefine IS_OSX
+#cmakedefine IS_LINUX
+#cmakedefine IS_FREEBSD
+#cmakedefine BUILD_IPHONE
+
+#endif

+ 13 - 0
dtool/metalibs/dtool/CMakeLists.txt

@@ -0,0 +1,13 @@
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "CoreDevel")
+add_metalib(p3dtool INIT init_libdtool dtool.h COMPONENTS p3dtoolutil p3dtoolbase)
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS p3dtool
+  EXPORT Core COMPONENT Core
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT CoreDevel)
+
+# Also handle thirdparty DLLs
+thirdparty_copy_alongside(p3dtool)

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

@@ -0,0 +1,44 @@
+set(P3CPPPARSER_HEADERS
+  cppArrayType.h cppBison.yxx cppBisonDefs.h
+  cppClassTemplateParameter.h cppCommentBlock.h
+  cppClosureType.h cppConstType.h
+  cppDeclaration.h cppEnumType.h cppExpression.h
+  cppExpressionParser.h cppExtensionType.h cppFile.h
+  cppFunctionGroup.h cppFunctionType.h cppGlobals.h
+  cppIdentifier.h cppInstance.h cppInstanceIdentifier.h
+  cppMakeProperty.h cppMakeSeq.h cppManifest.h
+  cppNameComponent.h cppNamespace.h
+  cppParameterList.h cppParser.h cppPointerType.h
+  cppPreprocessor.h cppReferenceType.h cppScope.h
+  cppSimpleType.h cppStructType.h cppTBDType.h
+  cppTemplateParameterList.h cppTemplateScope.h cppToken.h
+  cppType.h cppTypeDeclaration.h cppTypeParser.h
+  cppTypeProxy.h cppTypedefType.h cppUsing.h cppVisibility.h
+)
+
+set(P3CPPPARSER_SOURCES
+  cppArrayType.cxx ${CMAKE_CURRENT_BINARY_DIR}/cppBison.cxx
+  cppClassTemplateParameter.cxx
+  cppCommentBlock.cxx cppClosureType.cxx cppConstType.cxx cppDeclaration.cxx
+  cppEnumType.cxx cppExpression.cxx cppExpressionParser.cxx
+  cppExtensionType.cxx cppFile.cxx cppFunctionGroup.cxx
+  cppFunctionType.cxx cppGlobals.cxx cppIdentifier.cxx
+  cppInstance.cxx cppInstanceIdentifier.cxx
+  cppMakeProperty.cxx cppMakeSeq.cxx cppManifest.cxx
+  cppNameComponent.cxx cppNamespace.cxx cppParameterList.cxx
+  cppParser.cxx cppPointerType.cxx cppPreprocessor.cxx
+  cppReferenceType.cxx cppScope.cxx cppSimpleType.cxx
+  cppStructType.cxx cppTBDType.cxx
+  cppTemplateParameterList.cxx cppTemplateScope.cxx
+  cppToken.cxx cppType.cxx cppTypeDeclaration.cxx
+  cppTypeParser.cxx cppTypeProxy.cxx cppTypedefType.cxx
+  cppUsing.cxx cppVisibility.cxx
+)
+
+add_bison_target(cppBison.cxx cppBison.yxx DEFINES cppBison.h PREFIX cppyy)
+
+composite_sources(p3cppParser P3CPPPARSER_SOURCES)
+add_library(p3cppParser STATIC ${P3CPPPARSER_HEADERS} ${P3CPPPARSER_SOURCES})
+target_link_libraries(p3cppParser p3dtool)
+
+install(TARGETS p3cppParser EXPORT Core COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_LIBDIR})

+ 6 - 0
dtool/src/dconfig/CMakeLists.txt

@@ -0,0 +1,6 @@
+# Yes, INTERFACE: don't build it, there's no code!
+# We're only doing this to put the .h file on the path.
+add_library(p3dconfig INTERFACE)
+
+install(FILES dconfig.h COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+install(TARGETS p3dconfig EXPORT Core COMPONENT Core)

+ 106 - 0
dtool/src/dtoolbase/CMakeLists.txt

@@ -0,0 +1,106 @@
+configure_file(pandaVersion.h.in pandaVersion.h)
+configure_file(checkPandaVersion.h.in checkPandaVersion.h)
+configure_file(checkPandaVersion.cxx.in checkPandaVersion.cxx)
+
+if(CMAKE_CXX_STANDARD GREATER 16)
+  # This serves as a reminder to update checkPandaVersion.h.in when we upgrade
+  # to C++17, which supports inline variables - a cleaner way of depending on
+  # the Panda version symbol from a header than what we're currently doing.
+  message(FATAL_ERROR "Developer notice: Update checkPandaVersion.h.in for C++17!")
+endif()
+
+set(P3DTOOLBASE_HEADERS
+  ${CMAKE_CURRENT_BINARY_DIR}/checkPandaVersion.h
+  ${CMAKE_CURRENT_BINARY_DIR}/pandaVersion.h
+  addHash.I addHash.h
+  atomicAdjust.h
+  atomicAdjustDummyImpl.h atomicAdjustDummyImpl.I
+  atomicAdjustGccImpl.h atomicAdjustGccImpl.I
+  atomicAdjustI386Impl.h atomicAdjustI386Impl.I
+  atomicAdjustPosixImpl.h atomicAdjustPosixImpl.I
+  atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I
+  cmath.I cmath.h
+  deletedBufferChain.h deletedBufferChain.I
+  deletedChain.h deletedChain.T
+  dtoolbase.h dtoolbase_cc.h dtoolsymbols.h
+  dtool_platform.h
+  fakestringstream.h
+  indent.I indent.h
+  memoryBase.h
+  memoryHook.h memoryHook.I
+  mutexImpl.h
+  mutexDummyImpl.h mutexDummyImpl.I
+  mutexPosixImpl.h mutexPosixImpl.I
+  mutexWin32Impl.h mutexWin32Impl.I
+  mutexSpinlockImpl.h mutexSpinlockImpl.I
+  nearly_zero.h
+  neverFreeMemory.h neverFreeMemory.I
+  numeric_types.h
+  pdtoa.h
+  pstrtod.h
+  register_type.I register_type.h
+  selectThreadImpl.h
+  stl_compares.I stl_compares.h
+  typeHandle.I typeHandle.h
+  typeRegistry.I typeRegistry.h
+  typeRegistryNode.I typeRegistryNode.h
+  typedObject.I typedObject.h
+  pallocator.T pallocator.h
+  pdeque.h plist.h pmap.h pset.h
+  pvector.h epvector.h
+  lookup3.h
+  version.h
+)
+
+set(P3DTOOLBASE_SOURCES
+  ${CMAKE_CURRENT_BINARY_DIR}/checkPandaVersion.cxx
+  addHash.cxx
+  atomicAdjustDummyImpl.cxx
+  atomicAdjustI386Impl.cxx
+  atomicAdjustPosixImpl.cxx
+  atomicAdjustWin32Impl.cxx
+  deletedBufferChain.cxx
+  dtoolbase.cxx
+  indent.cxx
+  lookup3.c
+  memoryBase.cxx
+  memoryHook.cxx
+  mutexDummyImpl.cxx
+  mutexPosixImpl.cxx
+  mutexWin32Impl.cxx
+  mutexSpinlockImpl.cxx
+  neverFreeMemory.cxx
+  pdtoa.cxx
+  pstrtod.cxx
+  register_type.cxx
+  typeHandle.cxx
+  typeRegistry.cxx typeRegistryNode.cxx
+  typedObject.cxx
+)
+
+set(P3DTOOLBASE_IGATEEXT
+  typeHandle_ext.cxx
+  typeHandle_ext.h
+)
+
+set_source_files_properties(indent.cxx PROPERTIES SKIP_UNITY_BUILD_INCLUSION YES)
+
+composite_sources(p3dtoolbase P3DTOOLBASE_SOURCES)
+add_component_library(p3dtoolbase NOINIT SYMBOL BUILDING_DTOOL_DTOOLBASE
+  ${P3DTOOLBASE_HEADERS} ${P3DTOOLBASE_SOURCES})
+# Help other libraries find the autogenerated headers
+target_include_directories(p3dtoolbase PUBLIC
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
+  $<BUILD_INTERFACE:${PANDA_OUTPUT_DIR}/include>)
+target_link_libraries(p3dtoolbase PKG::EIGEN PKG::THREADS)
+target_interrogate(p3dtoolbase ${P3DTOOLBASE_SOURCES} EXTENSIONS ${P3DTOOLBASE_IGATEEXT})
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3dtoolbase
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3DTOOLBASE_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 21 - 0
dtool/src/dtoolbase/checkPandaVersion.cxx.in

@@ -0,0 +1,21 @@
+/* Filename: checkPandaVersion.cxx
+ * Created by:  drose (26Jan05)
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * 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."
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*******************************************************************
+ *  Generated automatically by CMake.
+ ***************************** DO NOT EDIT *************************/
+
+#include "dtoolbase.h"
+
+EXPCL_DTOOL_DTOOLBASE int @PANDA_VERSION_SYMBOL@ = 0;

+ 64 - 0
dtool/src/dtoolbase/checkPandaVersion.h.in

@@ -0,0 +1,64 @@
+/* Filename: checkPandaVersion.h
+ * Created by:  drose (26Jan05)
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * 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."
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*******************************************************************
+ *  Generated automatically by CMake.
+ ***************************** DO NOT EDIT *************************/
+
+/* Include this file in code that compiles with Panda to guarantee
+   that it is linking with the same version of the Panda DLL's that it
+   was compiled with. */
+
+/* We guarantee this by defining an external symbol which is based on
+   the version number.  If that symbol is defined, then our DLL's
+   (probably) match.  Otherwise, we must be running with the wrong
+   DLL; but the system linker will prevent the DLL from loading with
+   an undefined symbol. */
+
+#ifndef CHECKPANDAVERSION_H
+#define CHECKPANDAVERSION_H
+
+#include "dtoolbase.h"
+
+extern EXPCL_DTOOL_DTOOLBASE int @PANDA_VERSION_SYMBOL@;
+
+/* Just declaring the symbol isn't good enough.  We need to force the
+   compiler and linker to preserve the external reference long enough
+   to end up in the output DLL.  Therefore, we have to reference that
+   symbol somehow.
+
+   Forcing the compiler to include a reference in its output object
+   file is easy enough: just define a function that makes use of it
+   in some way.  The problem is the linker, which will enforce the
+   C++ One-Definition Rule and get upset about said definition
+   appearing in multiple places in the program.  We can appease the
+   linker by forcing the compiler to emit a weak symbol.  Many
+   compilers have syntax to request this explicitly, but since it
+   varies from compiler to compiler, that wouldn't be very portable.
+
+   Fortunately, the C++ ODR itself has some exceptions, where a
+   definition can occur in multiple translation units *if and only if*
+   it's the same definition each time.  In these cases, the compiler
+   must emit a weak symbol, because the ODR does not guarantee that
+   the same definition isn't repeated in any other translation units.
+   One such exception is template instantiation, which we use thus: */
+template<typename T>
+class CheckPandaVersion {
+public:
+  int check_version() { return @PANDA_VERSION_SYMBOL@; }
+};
+
+template class CheckPandaVersion<void>;
+
+#endif

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

@@ -0,0 +1,73 @@
+/* Filename: pandaVersion.h
+ * Created by:  drose (26Jan05)
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * 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."
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*******************************************************************
+ *  Generated automatically by CMake.
+ ***************************** DO NOT EDIT *************************
+
+   Do NOT attempt to edit the version number in this file.  This is a
+   generated file, and your changes to this file will not persist.  To
+   increment the version number, modify dtool/PandaVersion.cmake and
+   re-run ppremake.
+
+ ***************************** DO NOT EDIT *************************/
+
+/* Include this file anywhere you need to determine the Panda version
+   number at compile time.  If you need the runtime Panda version, use
+   pandaSystem.h instead. */
+
+/* Try to avoid including this file from another .h file; include it
+   only from .cxx instead.  This helps prevent unnecessarily long
+   rebuilds just because the version number changes; if this file is
+   included in a .h file, then any other files which also include that
+   .h file will need to be rebuilt when the version number changes. */
+
+#define PANDA_MAJOR_VERSION @PROJECT_VERSION_MAJOR@
+#define PANDA_MINOR_VERSION @PROJECT_VERSION_MINOR@
+#define PANDA_SEQUENCE_VERSION @PROJECT_VERSION_PATCH@
+
+/* Define if this is an "official" version, undefine otherwise. */
+#cmakedefine PANDA_OFFICIAL_VERSION
+
+/* This is the panda numeric version as a single number, with three
+   digits reserved for each component. */
+#define PANDA_NUMERIC_VERSION @PANDA_NUMERIC_VERSION@
+
+/* This is the panda version expressed as a string.  It ends in the
+   letter "c" if this is not an "official" version (e.g. it was checked
+   out from CVS by the builder). */
+#define PANDA_VERSION_STR "@PANDA_VERSION_STR@"
+
+/* This is the Git commit we built Panda from, or an empty string if this isn't
+   known. */
+#define PANDA_GIT_COMMIT_STR "@PANDA_GIT_COMMIT_STR@"
+
+/* This is the version of the Panda3D ABI expressed as a string.
+   This usually means the major and minor version. It should be the
+   same for Panda3D versions that are supposed to be backward
+   ABI compatible with each other. */
+#define PANDA_ABI_VERSION_STR "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@"
+
+/* This is a string indicating who has provided this distribution. */
+#define PANDA_DISTRIBUTOR "@PANDA_DISTRIBUTOR@"
+
+/* The string indicating the version number of the associated Panda3D
+   distributable package, or empty string if there is no associated
+   package. */
+#define PANDA_PACKAGE_VERSION_STR "@PANDA_PACKAGE_VERSION@"
+
+/* The string indicating the URL from which the associated Panda3D
+   distributable package may be downloaded, or empty string if there
+   is no associated package. */
+#define PANDA_PACKAGE_HOST_URL "@PANDA_PACKAGE_HOST_URL@"

+ 153 - 0
dtool/src/dtoolutil/CMakeLists.txt

@@ -0,0 +1,153 @@
+set(P3DTOOLUTIL_HEADERS
+  config_dtoolutil.h
+  dSearchPath.I dSearchPath.h
+  executionEnvironment.I executionEnvironment.h filename.I
+  filename.h
+  globPattern.I globPattern.h
+  lineStream.I lineStream.h
+  lineStreamBuf.I lineStreamBuf.h
+  load_dso.h
+  pandaFileStream.h pandaFileStream.I
+  pandaFileStreamBuf.h
+  pandaSystem.h
+  panda_getopt.h panda_getopt_long.h panda_getopt_impl.h
+  pfstream.h pfstream.I pfstreamBuf.h
+  preprocess_argv.h
+  string_utils.h string_utils.I
+  stringDecoder.h stringDecoder.I
+  textEncoder.h textEncoder.I
+  unicodeLatinMap.h
+  vector_double.h
+  vector_float.h
+  vector_int.h
+  vector_stdfloat.h
+  vector_string.h
+  vector_uchar.h
+  vector_src.h
+  win32ArgParser.h
+)
+
+if(APPLE)
+  set(P3DTOOLUTIL_HEADERS ${P3DTOOLUTIL_HEADERS}
+    filename_assist.mm filename_assist.h)
+
+  set_source_files_properties(
+    filename_assist.mm filename_assist.h PROPERTIES
+    WRAP_EXCLUDE YES
+    SKIP_UNITY_BUILD_INCLUSION YES)
+endif()
+
+set(P3DTOOLUTIL_SOURCES
+  config_dtoolutil.cxx
+  dSearchPath.cxx
+  executionEnvironment.cxx filename.cxx
+  globPattern.cxx
+  lineStream.cxx lineStreamBuf.cxx
+  load_dso.cxx
+  pandaFileStream.cxx pandaFileStreamBuf.cxx
+  pandaSystem.cxx
+  panda_getopt_impl.cxx
+  pfstreamBuf.cxx pfstream.cxx
+  preprocess_argv.cxx
+  string_utils.cxx
+  stringDecoder.cxx
+  textEncoder.cxx
+  unicodeLatinMap.cxx
+  vector_double.cxx
+  vector_float.cxx
+  vector_int.cxx
+  vector_string.cxx
+  vector_uchar.cxx
+  win32ArgParser.cxx
+)
+
+set(P3DTOOLUTIL_IGATEEXT
+  filename_ext.cxx
+  filename_ext.h
+  globPattern_ext.cxx
+  globPattern_ext.h
+  iostream_ext.cxx
+  iostream_ext.h
+  textEncoder_ext.cxx
+  textEncoder_ext.h
+)
+
+composite_sources(p3dtoolutil P3DTOOLUTIL_SOURCES)
+add_component_library(p3dtoolutil SYMBOL BUILDING_DTOOL_DTOOLUTIL
+  ${P3DTOOLUTIL_HEADERS} ${P3DTOOLUTIL_SOURCES})
+target_link_libraries(p3dtoolutil p3dtoolbase ${CMAKE_DL_LIBS})
+target_interrogate(p3dtoolutil ALL EXTENSIONS ${P3DTOOLUTIL_IGATEEXT})
+
+if(APPLE)
+  find_library(FOUNDATION_LIBRARY Foundation)
+  find_library(APPKIT_LIBRARY AppKit)
+  target_link_libraries(p3dtoolutil ${FOUNDATION_LIBRARY} ${APPKIT_LIBRARY})
+endif()
+
+# These are all used by executionEnvironment.cxx/filename.cxx
+foreach(var
+    # executionEnvironment.cxx:
+    HAVE_GLOBAL_ARGV
+    PROTOTYPE_GLOBAL_ARGV
+    GLOBAL_ARGV
+    GLOBAL_ARGC
+
+    HAVE_PROC_CURPROC_CMDLINE
+    HAVE_PROC_CURPROC_FILE
+    HAVE_PROC_CURPROC_MAP
+    HAVE_PROC_SELF_CMDLINE
+    HAVE_PROC_SELF_ENVIRON
+    HAVE_PROC_SELF_EXE
+    HAVE_PROC_SELF_MAPS
+
+    STATIC_INIT_GETENV
+
+    # filename.cxx:
+    HAVE_IOS_BINARY
+    PHAVE_DIRENT_H
+    PHAVE_GLOB_H
+    PHAVE_LOCKF
+    PHAVE_UTIME_H
+)
+
+  if(${var})
+    target_compile_definitions(p3dtoolutil PRIVATE "${var}=${${var}}")
+  endif()
+
+endforeach(var)
+
+if(BUILD_SHARED_LIBS)
+  # executionEnvironment.cxx needs to know the name(s) of the library file it
+  # will be linked into
+  if(BUILD_METALIBS)
+    set(library "p3dtool")
+  else()
+    set(library "p3dtoolutil")
+  endif()
+
+  set(filenames)
+  foreach(prop TARGET_FILE_NAME TARGET_SONAME_FILE_NAME TARGET_LINKER_FILE_NAME)
+    list(APPEND filenames "$<${prop}:${library}>")
+
+    if(CMAKE_IMPORT_LIBRARY_SUFFIX)
+      # Only the first property is valid/relevant on DLL platforms; bail out
+      # now and skip the others.
+      # (Yes, CMAKE_IMPORT_LIBRARY_SUFFIX being non-empty is how CMake defines
+      #  a DLL platform where TARGET_SONAME_FILE_NAME is invalid.)
+      break()
+    endif()
+  endforeach(prop)
+
+  target_compile_definitions(p3dtoolutil
+    PRIVATE "LIBP3DTOOL_FILENAMES=\"$<JOIN:${filenames},\"$<COMMA>\">\"")
+endif()
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3dtoolutil
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3DTOOLUTIL_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 128 - 0
dtool/src/interrogate/CMakeLists.txt

@@ -0,0 +1,128 @@
+set(INTERROGATE_HEADERS
+  functionRemap.h
+  functionWriter.h
+  functionWriterPtrFromPython.h functionWriterPtrToPython.h
+  functionWriters.h
+  interfaceMaker.h
+  interfaceMakerC.h
+  interfaceMakerPython.h interfaceMakerPythonObj.h
+  interfaceMakerPythonSimple.h
+  interfaceMakerPythonNative.h
+  interrogate.h interrogateBuilder.h parameterRemap.I
+  parameterRemap.h
+  parameterRemapBasicStringPtrToString.h
+  parameterRemapBasicStringRefToString.h
+  parameterRemapBasicStringToString.h
+  parameterRemapCharStarToString.h
+  parameterRemapConcreteToPointer.h
+  parameterRemapConstToNonConst.h parameterRemapEnumToInt.h
+  parameterRemapPTToPointer.h
+  parameterRemapReferenceToConcrete.h
+  parameterRemapReferenceToPointer.h parameterRemapThis.h
+  parameterRemapToString.h
+  parameterRemapHandleToInt.h
+  parameterRemapUnchanged.h
+  typeManager.h
+)
+
+set(INTERROGATE_SOURCES
+  functionRemap.cxx
+  functionWriter.cxx
+  functionWriterPtrFromPython.cxx functionWriterPtrToPython.cxx
+  functionWriters.cxx
+  interfaceMaker.cxx
+  interfaceMakerC.cxx
+  interfaceMakerPython.cxx interfaceMakerPythonObj.cxx
+  interfaceMakerPythonSimple.cxx
+  interfaceMakerPythonNative.cxx
+  interrogate.cxx interrogateBuilder.cxx parameterRemap.cxx
+  parameterRemapBasicStringPtrToString.cxx
+  parameterRemapBasicStringRefToString.cxx
+  parameterRemapBasicStringToString.cxx
+  parameterRemapCharStarToString.cxx
+  parameterRemapConcreteToPointer.cxx
+  parameterRemapConstToNonConst.cxx
+  parameterRemapEnumToInt.cxx parameterRemapPTToPointer.cxx
+  parameterRemapReferenceToConcrete.cxx
+  parameterRemapReferenceToPointer.cxx parameterRemapThis.cxx
+  parameterRemapToString.cxx
+  parameterRemapHandleToInt.cxx
+  parameterRemapUnchanged.cxx
+  typeManager.cxx
+)
+
+set(INTERROGATE_PREAMBLE_PYTHON_NATIVE
+  ../interrogatedb/py_panda.cxx
+  ../interrogatedb/py_compat.cxx
+  ../interrogatedb/py_wrappers.cxx
+  ../interrogatedb/dtool_super_base.cxx
+)
+
+composite_sources(interrogate INTERROGATE_SOURCES)
+add_executable(interrogate ${INTERROGATE_HEADERS} ${INTERROGATE_SOURCES})
+target_link_libraries(interrogate p3cppParser p3interrogatedb
+  PKG::OPENSSL)
+
+# Python preamble for interrogate_module
+set(_preamble_files)
+foreach(_file ${INTERROGATE_PREAMBLE_PYTHON_NATIVE})
+  # Resolve symlinks, use absolute path, and add a `#line 1 ...` directive
+  get_filename_component(_file "${_file}" REALPATH)
+
+  string(SHA1 _hash "${_file}")
+  set(_line_file "${CMAKE_CURRENT_BINARY_DIR}/.${_hash}.h")
+  file(WRITE "${_line_file}" "#line 1 \"${_file}\"\n")
+
+  list(APPEND _preamble_files "${_line_file}")
+  list(APPEND _preamble_files "${_file}")
+endforeach(_file)
+
+add_custom_command(
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/interrogate_preamble_python_native.cxx
+  COMMAND ${CMAKE_COMMAND}
+    -D OUTPUT_FILE="${CMAKE_CURRENT_BINARY_DIR}/interrogate_preamble_python_native.cxx"
+    -D INPUT_FILES="${_preamble_files}"
+    -D SYMBOL_NAME="interrogate_preamble_python_native"
+    -P ${PROJECT_SOURCE_DIR}/cmake/scripts/ConcatenateToCXX.cmake
+  DEPENDS ${INTERROGATE_PREAMBLE_PYTHON_NATIVE}
+  WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
+
+add_executable(interrogate_module interrogate_module.cxx
+  ${CMAKE_CURRENT_BINARY_DIR}/interrogate_preamble_python_native.cxx)
+target_link_libraries(interrogate_module p3cppParser p3interrogatedb
+  PKG::OPENSSL)
+
+if(NOT CMAKE_CROSSCOMPILING)
+  add_executable(host_interrogate ALIAS interrogate)
+  add_executable(host_interrogate_module ALIAS interrogate_module)
+
+else()
+  # When cross-compiling, we must find the host Interrogate.
+  # TODO: We should also try to find_package(Panda3D ...) before falling back
+  # to searching manually.
+  find_program(HOST_PATH_INTERROGATE interrogate)
+  find_program(HOST_PATH_INTERROGATE_MODULE interrogate_module)
+
+  add_executable(host_interrogate IMPORTED GLOBAL)
+  if(HOST_PATH_INTERROGATE)
+    set_target_properties(host_interrogate PROPERTIES
+      IMPORTED_LOCATION "${HOST_PATH_INTERROGATE}")
+  endif()
+
+  add_executable(host_interrogate_module IMPORTED GLOBAL)
+  if(HOST_PATH_INTERROGATE_MODULE)
+    set_target_properties(host_interrogate_module PROPERTIES
+      IMPORTED_LOCATION "${HOST_PATH_INTERROGATE_MODULE}")
+  endif()
+
+endif()
+
+if(WANT_INTERROGATE)
+  install(TARGETS interrogate interrogate_module EXPORT Core COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_BINDIR})
+  install(FILES ${INTERROGATE_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+
+else()
+  set_target_properties(interrogate interrogate_module
+    PROPERTIES EXCLUDE_FROM_ALL ON)
+
+endif()

+ 76 - 0
dtool/src/interrogatedb/CMakeLists.txt

@@ -0,0 +1,76 @@
+set(P3INTERROGATEDB_HEADERS
+  config_interrogatedb.h indexRemapper.h interrogateComponent.I
+  interrogateComponent.h interrogateDatabase.I
+  interrogateDatabase.h interrogateElement.I
+  interrogateElement.h interrogateFunction.I
+  interrogateFunction.h interrogateFunctionWrapper.I
+  interrogateFunctionWrapper.h
+  interrogateMakeSeq.I interrogateMakeSeq.h
+  interrogateManifest.I interrogateManifest.h
+  interrogateType.I interrogateType.h
+  interrogate_datafile.I interrogate_datafile.h
+  interrogate_interface.h interrogate_request.h
+)
+
+set(P3INTERROGATEDB_SOURCES
+  config_interrogatedb.cxx
+  indexRemapper.cxx
+  interrogateComponent.cxx interrogateDatabase.cxx
+  interrogateElement.cxx interrogateFunction.cxx
+  interrogateFunctionWrapper.cxx
+  interrogateMakeSeq.cxx
+  interrogateManifest.cxx
+  interrogateType.cxx interrogate_datafile.cxx
+  interrogate_interface.cxx interrogate_request.cxx
+)
+
+set(P3INTERROGATEDB_IGATE
+  interrogate_interface.h
+  interrogate_request.h
+)
+
+set(P3IGATERUNTIME_HEADERS
+  extension.h py_compat.h py_panda.h py_panda.I py_wrappers.h
+)
+
+composite_sources(p3interrogatedb P3INTERROGATEDB_SOURCES)
+add_library(p3interrogatedb
+  ${P3INTERROGATEDB_HEADERS} ${P3INTERROGATEDB_SOURCES})
+set_target_properties(p3interrogatedb PROPERTIES DEFINE_SYMBOL BUILDING_INTERROGATEDB)
+target_link_libraries(p3interrogatedb p3dconfig p3prc)
+
+install(TARGETS p3interrogatedb
+  EXPORT Core COMPONENT Core
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT CoreDevel)
+install(FILES ${P3INTERROGATEDB_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+install(FILES ${P3IGATERUNTIME_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+
+# ALSO: This has an Interrogate binding! Take care of that if we want it.
+# Note we don't use the regular Interrogate macros; this has some custom flags
+# that would make it not worthwhile.
+
+if(NOT INTERROGATE_PYTHON_INTERFACE)
+  return()
+endif()
+
+add_custom_command(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/interrogatedb_module.cxx"
+  COMMAND host_interrogate
+    -D EXPCL_INTERROGATEDB=
+    -nodb -python -promiscuous
+    -module panda3d.interrogatedb
+    -library interrogatedb
+    -string -true-names -do-module
+    -srcdir "${CMAKE_CURRENT_SOURCE_DIR}"
+    -oc "${CMAKE_CURRENT_BINARY_DIR}/interrogatedb_module.cxx"
+    ${P3INTERROGATEDB_IGATE}
+
+  DEPENDS host_interrogate ${P3INTERROGATEDB_IGATE}
+  COMMENT "Interrogating interrogatedb")
+
+add_python_target(panda3d.interrogatedb
+  "${CMAKE_CURRENT_BINARY_DIR}/interrogatedb_module.cxx")
+target_link_libraries(panda3d.interrogatedb p3interrogatedb)

+ 157 - 0
dtool/src/prc/CMakeLists.txt

@@ -0,0 +1,157 @@
+set(P3PRC_HEADERS
+  androidLogStream.h
+  bigEndian.h
+  config_prc.h
+  configDeclaration.I configDeclaration.h
+  configFlags.I configFlags.h
+  configPage.I configPage.h
+  configPageManager.I configPageManager.h
+  configVariable.I configVariable.h
+  configVariableBase.I configVariableBase.h
+  configVariableBool.I configVariableBool.h
+  configVariableCore.I configVariableCore.h
+  configVariableDouble.I configVariableDouble.h
+  configVariableEnum.I configVariableEnum.h
+  configVariableFilename.I configVariableFilename.h
+  configVariableInt.I configVariableInt.h
+  configVariableInt64.I configVariableInt64.h
+  configVariableList.I configVariableList.h
+  configVariableManager.I configVariableManager.h
+  configVariableSearchPath.I configVariableSearchPath.h
+  configVariableString.I configVariableString.h
+  encryptStreamBuf.h encryptStreamBuf.I encryptStream.h encryptStream.I
+  littleEndian.h
+  nativeNumericData.I nativeNumericData.h
+  pnotify.I pnotify.h
+  notifyCategory.I notifyCategory.h
+  notifyCategoryProxy.I notifyCategoryProxy.h
+  notifySeverity.h
+  prcKeyRegistry.h prcKeyRegistry.I
+  reversedNumericData.I reversedNumericData.h
+  streamReader.I streamReader.h
+  streamWrapper.I streamWrapper.h
+  streamWriter.I streamWriter.h
+  ${CMAKE_CURRENT_BINARY_DIR}/prc_parameters.h
+)
+
+set(P3PRC_SOURCES
+  config_prc.cxx
+  configDeclaration.cxx
+  configFlags.cxx
+  configPage.cxx
+  configPageManager.cxx
+  configVariable.cxx
+  configVariableBase.cxx
+  configVariableBool.cxx
+  configVariableCore.cxx
+  configVariableDouble.cxx
+  configVariableEnum.cxx
+  configVariableFilename.cxx
+  configVariableInt.cxx
+  configVariableInt64.cxx
+  configVariableList.cxx
+  configVariableManager.cxx
+  configVariableSearchPath.cxx
+  configVariableString.cxx
+  nativeNumericData.cxx
+  notify.cxx
+  notifyCategory.cxx
+  notifySeverity.cxx
+  prcKeyRegistry.cxx
+  reversedNumericData.cxx
+  streamReader.cxx streamWrapper.cxx streamWriter.cxx
+)
+
+configure_file(prc_parameters.h.in prc_parameters.h)
+
+if(ANDROID)
+  set(P3PRC_SOURCES ${P3PRC_SOURCES}
+    androidLogStream.cxx)
+endif()
+
+if(HAVE_OPENSSL)
+  list(APPEND P3PRC_SOURCES encryptStreamBuf.cxx encryptStream.cxx)
+endif()
+
+set(P3PRC_IGATEEXT
+  streamReader_ext.cxx
+  streamReader_ext.h
+  streamWriter_ext.cxx
+  streamWriter_ext.h
+)
+
+composite_sources(p3prc P3PRC_SOURCES)
+add_library(p3prc
+  ${P3PRC_HEADERS} ${P3PRC_SOURCES})
+set_target_properties(p3prc PROPERTIES DEFINE_SYMBOL BUILDING_DTOOL_PRC)
+target_include_directories(p3prc PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
+target_link_libraries(p3prc p3dtool PKG::OPENSSL)
+target_interrogate(p3prc ALL EXTENSIONS ${P3PRC_IGATEEXT})
+
+if(ANDROID)
+  target_link_libraries(p3prc log)
+endif()
+
+install(TARGETS p3prc
+  EXPORT Core COMPONENT Core
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT CoreDevel)
+
+install(FILES ${P3PRC_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+
+# Also install under the old name "p3dtoolconfig"
+# TODO: Remove this once "p3dtoolconfig" is deprecated
+if(WIN32)
+  # Symlinks aren't pretty under WIN32
+  set(_symlink "copy")
+else()
+  set(_symlink "create_symlink")
+endif()
+
+get_target_property(_type p3prc TYPE)
+if(_type STREQUAL "SHARED_LIBRARY")
+
+  set(_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}")
+  if(UNIX)
+    get_target_property(_soversion p3prc SOVERSION)
+    if(APPLE)
+      set(_suffix ".${_soversion}${_suffix}")
+    else()
+      set(_suffix "${_suffix}.${_soversion}")
+    endif()
+
+    set(_file_genex "TARGET_SONAME_FILE")
+    set(_install_dir "${CMAKE_INSTALL_LIBDIR}")
+
+  else()
+    # Win32?
+    set(_file_genex "TARGET_FILE")
+    set(_install_dir "${CMAKE_INSTALL_BINDIR}")
+
+  endif()
+
+  set(_soname "${CMAKE_SHARED_LIBRARY_PREFIX}p3dtoolconfig${_suffix}")
+
+  add_custom_command(TARGET p3prc POST_BUILD
+    COMMAND "${CMAKE_COMMAND}" -E chdir "$<${_file_genex}_DIR:p3prc>"
+      "${CMAKE_COMMAND}" -E "${_symlink}"
+      "$<${_file_genex}_NAME:p3prc>" "${_soname}"
+  )
+  install(FILES "$<${_file_genex}_DIR:p3prc>/${_soname}"
+    DESTINATION "${_install_dir}")
+endif()
+
+if(WIN32)
+  set(_libname "${CMAKE_IMPORT_LIBRARY_PREFIX}p3dtoolconfig${CMAKE_IMPORT_LIBRARY_SUFFIX}")
+else()
+  set(_libname "${CMAKE_${_type}_PREFIX}p3dtoolconfig${CMAKE_${_type}_SUFFIX}")
+endif()
+add_custom_command(TARGET p3prc POST_BUILD
+  COMMAND "${CMAKE_COMMAND}" -E chdir "$<TARGET_LINKER_FILE_DIR:p3prc>"
+    "${CMAKE_COMMAND}" -E "${_symlink}"
+    "$<TARGET_LINKER_FILE_NAME:p3prc>" "${_libname}"
+)
+install(FILES "$<TARGET_LINKER_FILE_DIR:p3prc>/${_libname}"
+  DESTINATION "${CMAKE_INSTALL_LIBDIR}")

+ 56 - 0
dtool/src/prc/prc_parameters.h.in

@@ -0,0 +1,56 @@
+/* prc_parameters.h.  Generated automatically by CMake. */
+/********************************** DO NOT EDIT ****************************/
+
+
+/* The compiled-in default directory to look for the Configrc file, in
+   the absence of the PRC_DIR environment variable set, and in
+   the absence of anything specified via the configpath directive. */
+#define DEFAULT_PRC_DIR "@DEFAULT_PRC_DIR@"
+
+/* The compiled-in name of the environment variable(s) that contain
+   the name of a single directory in which to search for prc files. */
+#define PRC_DIR_ENVVARS "@PRC_DIR_ENVVARS@"
+
+/* The compiled-in name of the environment variable(s) that contain
+   the name of multiple directories, separated by DEFAULT_PATHSEP, in
+   which to search for prc files. */
+#define PRC_PATH_ENVVARS "@PRC_PATH_ENVVARS@"
+
+/* This is a special variable that is rarely used; it exists primarily
+   to support the Cygwin-based "ctattach" tools used by the Walt
+   Disney VR Studio.  This defines a set of environment variable(s)
+   that define a search path, as above; except that the directory
+   names on these search paths are Panda-style filenames, not
+   Windows-style filenames; and the path separator is always a space
+   character, regardless of DEFAULT_PATHSEP. */
+#define PRC_PATH2_ENVVARS "@PRC_PATH2_ENVVARS@"
+
+/* The filename(s) to search for in the above paths.  Normally this is
+   *.prc. */
+#define PRC_PATTERNS "@PRC_PATTERNS@"
+
+/* The filename(s) for encrypted prc files. */
+#define PRC_ENCRYPTED_PATTERNS "@PRC_ENCRYPTED_PATTERNS@"
+
+/* The encryption key used to decrypt any encrypted prc files
+   identified by PRC_ENCRYPTED_PATTERNS. */
+#define PRC_ENCRYPTION_KEY "@PRC_ENCRYPTION_KEY@"
+
+/* The filename(s) to search for, and execute, in the above paths.
+   Normally this is empty. */
+#define PRC_EXECUTABLE_PATTERNS "@PRC_EXECUTABLE_PATTERNS@"
+
+/* The environment variable that defines optional args to pass to
+   executables found that match one of the above patterns. */
+#define PRC_EXECUTABLE_ARGS_ENVVAR "@PRC_EXECUTABLE_ARGS_ENVVAR@"
+
+/* Define if we want to enable the "trust_level" feature of prc config
+   variables.  This requires OpenSSL and PRC_PUBLIC_KEYS_FILENAME,
+   above. */
+#cmakedefine PRC_RESPECT_TRUST_LEVEL
+
+/* The trust level value for any legacy (DConfig) variables. */
+#define PRC_DCONFIG_TRUST_LEVEL @PRC_DCONFIG_TRUST_LEVEL@
+
+/* The amount by which we globally increment the trust level. */
+#define PRC_INC_TRUST_LEVEL @PRC_INC_TRUST_LEVEL@

+ 47 - 0
makepanda/selfdestruct.py

@@ -0,0 +1,47 @@
+#!/usr/bin/env python2
+
+import os
+import re
+import sys
+import shutil
+
+# Ensure user WANTS th
+if len(sys.argv) < 2 or sys.argv[1] != '--yes':
+    print('======== MAKEPANDA SELF-DESTRUCT ========')
+    print('This script will destroy every trace of')
+    print('makepanda from the Panda3D directory that')
+    print('contains it. This is for testing CMake\'s')
+    print('dependencies and fully removing makepanda')
+    print('should the latter buildsystem no longer')
+    print('be desired.')
+    print('')
+    print('If you are sure, pass --yes')
+    sys.exit(1)
+
+# Some sanity-checks to make sure this script is in the right location:
+scriptdir = os.path.abspath(os.path.dirname(__file__))
+assert os.path.split(scriptdir)[1] == 'makepanda'
+root = os.path.dirname(scriptdir)
+assert os.path.isfile(os.path.join(root, 'LICENSE'))
+assert os.path.isdir(os.path.join(root, 'pandatool'))
+
+# Now we get to work! First, the makepanda directory isn't needed:
+shutil.rmtree(os.path.join(root, 'makepanda'))
+
+# Then we look under each of the separate project trees:
+projects = ['contrib', 'direct', 'dtool', 'panda', 'pandatool']
+for project in projects:
+    # Remove non-CMakeLists.txt files from */metalibs/*/
+    for path, dirs, files in os.walk(os.path.join(root, project, 'metalibs')):
+        for filename in files:
+            if filename.lower() != 'cmakelists.txt':
+                os.unlink(os.path.join(path, filename))
+        # Unlink the directory itself, if empty
+        if not os.listdir(path):
+            os.rmdir(path)
+
+    for path, dirs, files in os.walk(os.path.join(root, project)):
+        # Get rid of _composite#.cxx files
+        for filename in files:
+            if re.match(r'.*_composite[0-9]*\.(cxx|h|mm)', filename):
+                os.unlink(os.path.join(path, filename))

+ 174 - 0
panda/CMakeLists.txt

@@ -0,0 +1,174 @@
+if(NOT BUILD_DTOOL)
+  message(FATAL_ERROR "Cannot build panda without dtool!  Please enable the BUILD_DTOOL option.")
+endif()
+
+# Include panda source directories
+add_subdirectory(src/audio)
+add_subdirectory(src/audiotraits)
+add_subdirectory(src/chan)
+add_subdirectory(src/char)
+add_subdirectory(src/cocoadisplay)
+add_subdirectory(src/collide)
+add_subdirectory(src/configfiles)
+add_subdirectory(src/cull)
+add_subdirectory(src/device)
+add_subdirectory(src/dgraph)
+add_subdirectory(src/display)
+add_subdirectory(src/distort)
+add_subdirectory(src/downloader)
+add_subdirectory(src/downloadertools)
+add_subdirectory(src/dxgsg9)
+add_subdirectory(src/dxml)
+add_subdirectory(src/egg)
+add_subdirectory(src/egg2pg)
+add_subdirectory(src/egldisplay)
+add_subdirectory(src/event)
+add_subdirectory(src/express)
+add_subdirectory(src/ffmpeg)
+add_subdirectory(src/framework)
+add_subdirectory(src/glesgsg)
+add_subdirectory(src/gles2gsg)
+add_subdirectory(src/glgsg)
+add_subdirectory(src/glstuff)
+add_subdirectory(src/glxdisplay)
+add_subdirectory(src/gobj)
+add_subdirectory(src/grutil)
+add_subdirectory(src/gsgbase)
+add_subdirectory(src/linmath)
+add_subdirectory(src/mathutil)
+add_subdirectory(src/movies)
+add_subdirectory(src/nativenet)
+add_subdirectory(src/net)
+add_subdirectory(src/pandabase)
+add_subdirectory(src/parametrics)
+add_subdirectory(src/pgraph)
+add_subdirectory(src/pgraphnodes)
+add_subdirectory(src/pgui)
+add_subdirectory(src/pipeline)
+add_subdirectory(src/pnmimage)
+add_subdirectory(src/pnmimagetypes)
+add_subdirectory(src/pnmtext)
+add_subdirectory(src/pstatclient)
+add_subdirectory(src/putil)
+add_subdirectory(src/recorder)
+add_subdirectory(src/testbed)
+add_subdirectory(src/text)
+add_subdirectory(src/tform)
+add_subdirectory(src/vision)
+add_subdirectory(src/vrpn)
+add_subdirectory(src/wgldisplay)
+add_subdirectory(src/windisplay)
+add_subdirectory(src/x11display)
+
+# For other components
+# bullet
+add_subdirectory(src/bullet)
+# ode
+add_subdirectory(src/ode)
+# physics
+add_subdirectory(src/particlesystem)
+add_subdirectory(src/physics)
+
+# Include panda metalibs
+add_subdirectory(metalibs/panda)
+add_subdirectory(metalibs/pandadx9)
+add_subdirectory(metalibs/pandaegg)
+add_subdirectory(metalibs/pandaexpress)
+add_subdirectory(metalibs/pandagl)
+add_subdirectory(metalibs/pandagles)
+add_subdirectory(metalibs/pandagles2)
+add_subdirectory(metalibs/pandaphysics)
+
+# Now add the Python modules:
+set(CORE_MODULE_COMPONENTS
+  p3chan p3char p3collide p3cull p3device p3dgraph p3display
+  p3downloader p3dxml p3event p3express p3gobj p3grutil p3gsgbase p3linmath
+  p3mathutil p3movies p3parametrics p3pgraph p3pgraphnodes p3pgui
+  p3pipeline p3pnmimage p3pstatclient p3putil p3recorder p3text p3tform
+  p3prc p3dtoolutil p3dtoolbase
+)
+
+if(WANT_NATIVE_NET)
+  list(APPEND CORE_MODULE_COMPONENTS p3nativenet)
+  if(HAVE_NET)
+    list(APPEND CORE_MODULE_COMPONENTS p3net)
+  endif()
+endif()
+
+if(HAVE_AUDIO)
+  list(APPEND CORE_MODULE_COMPONENTS p3audio)
+endif()
+
+if(HAVE_FREETYPE)
+  list(APPEND CORE_MODULE_COMPONENTS p3pnmtext)
+endif()
+
+if(INTERROGATE_PYTHON_INTERFACE)
+  add_python_module(panda3d.core ${CORE_MODULE_COMPONENTS} LINK panda)
+
+  # Generate our __init__.py
+  if(WIN32)
+    file(READ "${PROJECT_SOURCE_DIR}/cmake/templates/win32_python/__init__.py" win32_init)
+  else()
+    set(win32_init "")
+  endif()
+
+  file(WRITE "${PROJECT_BINARY_DIR}/panda3d/__init__.py"
+    "\"Python bindings for the Panda3D libraries\"
+
+__version__ = '${PROJECT_VERSION}'
+
+if __debug__:
+    import sys
+    if sys.version_info < (3, 0):
+        sys.stderr.write('''\\
+WARNING: Python 2.7 has reached EOL as of January 1, 2020.
+To suppress this warning, upgrade to Python 3.
+''')
+        sys.stdout.flush()
+    del sys
+
+${win32_init}")
+
+  if(BUILD_SHARED_LIBS)
+    install_python_package(panda3d ARCH)
+  endif()
+
+  if(HAVE_BULLET)
+    add_python_module(panda3d.bullet p3bullet IMPORT panda3d.core COMPONENT BulletPython)
+
+    export_targets(BulletPython NAMESPACE "Panda3D::Python::" COMPONENT BulletDevel)
+  endif()
+
+  if(HAVE_EGG)
+    add_python_module(panda3d.egg p3egg p3egg2pg LINK pandaegg IMPORT panda3d.core COMPONENT EggPython)
+
+    export_targets(EggPython NAMESPACE "Panda3D::Python::" COMPONENT EggDevel)
+  endif()
+
+  add_python_module(panda3d.fx pandafx IMPORT panda3d.core)
+  add_python_module(panda3d.physics p3physics p3particlesystem LINK pandaphysics IMPORT panda3d.core)
+
+  if(HAVE_ODE)
+    add_python_module(panda3d.ode p3ode IMPORT panda3d.core COMPONENT ODEPython)
+
+    export_targets(ODEPython NAMESPACE "Panda3D::Python::" COMPONENT ODEDevel)
+  endif()
+
+  if(HAVE_OPENCV OR HAVE_ARTOOLKIT)
+    add_python_module(panda3d.vision p3vision IMPORT panda3d.core COMPONENT VisionPython)
+
+    export_targets(VisionPython NAMESPACE "Panda3D::Python::" COMPONENT VisionDevel)
+  endif()
+
+  if(HAVE_VRPN)
+    add_python_module(panda3d.vrpn p3vrpn IMPORT panda3d.core COMPONENT VRPNPython)
+    set_target_properties(panda3d.vrpn PROPERTIES CXX_EXCEPTIONS ON)
+
+    export_targets(VRPNPython NAMESPACE "Panda3D::Python::" COMPONENT VRPNDevel)
+  endif()
+
+  export_targets(Python NAMESPACE "Panda3D::Python::" COMPONENT CoreDevel)
+endif()
+
+export_targets(Core COMPONENT CoreDevel)

+ 32 - 0
panda/metalibs/panda/CMakeLists.txt

@@ -0,0 +1,32 @@
+set(PANDA_LINK_TARGETS
+  p3chan p3char p3collide p3cull p3device p3dgraph p3display p3dxml
+  p3event p3gobj p3grutil p3gsgbase p3linmath p3mathutil
+  p3movies p3parametrics p3pgraph p3pgraphnodes p3pgui p3pipeline
+  p3pnmimage p3pnmimagetypes p3pstatclient p3putil p3recorder p3text p3tform
+)
+
+if(WANT_NATIVE_NET)
+  list(APPEND PANDA_LINK_TARGETS p3nativenet)
+  if(HAVE_NET)
+    list(APPEND PANDA_LINK_TARGETS p3net)
+  endif()
+endif()
+
+if(HAVE_AUDIO)
+  list(APPEND PANDA_LINK_TARGETS p3audio)
+endif()
+
+if(HAVE_FREETYPE)
+  list(APPEND PANDA_LINK_TARGETS p3pnmtext)
+endif()
+
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "CoreDevel")
+add_metalib(panda INIT init_libpanda panda.h COMPONENTS ${PANDA_LINK_TARGETS})
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS panda
+  EXPORT Core COMPONENT Core
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT CoreDevel)

+ 18 - 0
panda/metalibs/pandadx9/CMakeLists.txt

@@ -0,0 +1,18 @@
+if(NOT HAVE_DX9)
+  return()
+endif()
+
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "DX9Devel")
+add_metalib(pandadx9 ${MODULE_TYPE}
+  INCLUDE wdxGraphicsPipe9.h
+  INIT init_libpandadx9 pandadx9.h
+  EXPORT int get_pipe_type_pandadx9 "wdxGraphicsPipe9::get_class_type().get_index()"
+  COMPONENTS p3dxgsg9 p3windisplay)
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS pandadx9
+  EXPORT DX9 COMPONENT DX9
+  DESTINATION ${MODULE_DESTINATION}
+  ARCHIVE COMPONENT DX9Devel)
+
+export_targets(DX9 COMPONENT DX9Devel)

+ 19 - 0
panda/metalibs/pandaegg/CMakeLists.txt

@@ -0,0 +1,19 @@
+if(NOT HAVE_EGG)
+  return()
+endif()
+
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "EggDevel")
+add_metalib(pandaegg
+  INIT init_libpandaegg pandaegg.h
+  COMPONENTS p3egg p3egg2pg)
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+target_link_libraries(pandaegg panda)
+
+install(TARGETS pandaegg
+  EXPORT Egg COMPONENT Egg
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT EggDevel)
+
+export_targets(Egg COMPONENT EggDevel)

+ 12 - 0
panda/metalibs/pandaexpress/CMakeLists.txt

@@ -0,0 +1,12 @@
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "CoreDevel")
+add_metalib(pandaexpress
+  INIT init_libpandaexpress pandaexpress.h
+  COMPONENTS p3downloader p3express)
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS pandaexpress
+  EXPORT Core COMPONENT Core
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT CoreDevel)

+ 45 - 0
panda/metalibs/pandagl/CMakeLists.txt

@@ -0,0 +1,45 @@
+if(NOT HAVE_GL)
+  return()
+endif()
+
+set(PANDAGL_LINK_TARGETS p3glgsg p3glstuff)
+
+if(HAVE_GLX)
+  list(APPEND PANDAGL_LINK_TARGETS p3glxdisplay p3x11display)
+  set(PANDAGL_PIPE_TYPE "glxGraphicsPipe")
+
+elseif(HAVE_WGL)
+  list(APPEND PANDAGL_LINK_TARGETS p3wgldisplay p3windisplay)
+  set(PANDAGL_PIPE_TYPE "wglGraphicsPipe")
+
+elseif(HAVE_COCOA)
+  list(APPEND PANDAGL_LINK_TARGETS p3cocoadisplay)
+  set(PANDAGL_PIPE_TYPE "CocoaGraphicsPipe")
+  set(PANDAGL_PIPE_INCLUDE "cocoaGraphicsPipe.h")
+
+else()
+  message("") # Add extra line before error
+  message(SEND_ERROR
+    "When compiling with OpenGL (HAVE_GL), at least one of:
+  HAVE_WGL, HAVE_COCOA, or HAVE_GLX must be defined.")
+
+endif()
+
+if(NOT PANDAGL_PIPE_INCLUDE)
+  set(PANDAGL_PIPE_INCLUDE "${PANDAGL_PIPE_TYPE}.h")
+endif()
+
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "OpenGLDevel")
+add_metalib(pandagl ${MODULE_TYPE}
+  INCLUDE "${PANDAGL_PIPE_INCLUDE}"
+  INIT init_libpandagl pandagl.h
+  EXPORT int get_pipe_type_pandagl "${PANDAGL_PIPE_TYPE}::get_class_type().get_index()"
+  COMPONENTS ${PANDAGL_LINK_TARGETS})
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS pandagl
+  EXPORT OpenGL COMPONENT OpenGL
+  DESTINATION ${MODULE_DESTINATION}
+  ARCHIVE COMPONENT OpenGLDevel)
+
+export_targets(OpenGL NAMESPACE "Panda3D::OpenGL::" COMPONENT OpenGLDevel)

+ 28 - 0
panda/metalibs/pandagles/CMakeLists.txt

@@ -0,0 +1,28 @@
+if(NOT HAVE_GLES1 OR NOT HAVE_EGL)
+  return()
+endif()
+
+if(ANDROID)
+  set(GLES1_PIPE_TYPE "AndroidGraphicsPipe")
+  set(GLES1_PIPE_INCLUDE "androidGraphicsPipe.h")
+
+else()
+  set(GLES1_PIPE_TYPE "eglGraphicsPipe")
+  set(GLES1_PIPE_INCLUDE "eglGraphicsPipe.h")
+
+endif()
+
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "OpenGLES1Devel")
+add_metalib(pandagles ${MODULE_TYPE}
+  INCLUDE "${GLES1_PIPE_INCLUDE}"
+  INIT init_libpandagles pandagles.h
+  EXPORT int get_pipe_type_pandagles "${GLES1_PIPE_TYPE}::get_class_type().get_index()"
+  COMPONENTS p3egldisplay_gles1 p3glesgsg p3glstuff p3x11display)
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS pandagles
+  EXPORT OpenGLES1 COMPONENT OpenGLES1
+  DESTINATION ${MODULE_DESTINATION}
+  ARCHIVE COMPONENT OpenGLES1Devel)
+
+export_targets(OpenGLES1 COMPONENT OpenGLES1Devel)

+ 18 - 0
panda/metalibs/pandagles2/CMakeLists.txt

@@ -0,0 +1,18 @@
+if(NOT HAVE_GLES2 OR NOT HAVE_EGL)
+  return()
+endif()
+
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "OpenGLES2Devel")
+add_metalib(pandagles2 ${MODULE_TYPE}
+  INCLUDE eglGraphicsPipe.h
+  INIT init_libpandagles2 pandagles2.h
+  EXPORT int get_pipe_type_pandagles2 "eglGraphicsPipe::get_class_type().get_index()"
+  COMPONENTS p3egldisplay_gles2 p3gles2gsg p3glstuff p3x11display)
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS pandagles2
+  EXPORT OpenGLES2 COMPONENT OpenGLES2
+  DESTINATION ${MODULE_DESTINATION}
+  ARCHIVE COMPONENT OpenGLES2Devel)
+
+export_targets(OpenGLES2 COMPONENT OpenGLES2Devel)

+ 12 - 0
panda/metalibs/pandaphysics/CMakeLists.txt

@@ -0,0 +1,12 @@
+set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "CoreDevel")
+add_metalib(pandaphysics
+  INIT init_libpandaphysics pandaphysics.h
+  COMPONENTS p3physics p3particlesystem)
+unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
+
+install(TARGETS pandaphysics
+  EXPORT Core COMPONENT Core
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT CoreDevel)

+ 39 - 0
panda/src/audio/CMakeLists.txt

@@ -0,0 +1,39 @@
+if(NOT HAVE_AUDIO)
+  return()
+endif()
+
+set(P3AUDIO_HEADERS
+  config_audio.h
+  filterProperties.h filterProperties.I
+  audioLoadRequest.h audioLoadRequest.I
+  audioManager.h audioManager.I
+  audioSound.h audioSound.I
+  nullAudioManager.h
+  nullAudioSound.h
+)
+
+set(P3AUDIO_SOURCES
+  config_audio.cxx
+  filterProperties.cxx
+  audioLoadRequest.cxx
+  audioManager.cxx
+  audioSound.cxx
+  nullAudioManager.cxx
+  nullAudioSound.cxx
+)
+
+composite_sources(p3audio P3AUDIO_SOURCES)
+add_component_library(p3audio NOINIT SYMBOL BUILDING_PANDA_AUDIO
+  ${P3AUDIO_HEADERS} ${P3AUDIO_SOURCES})
+target_link_libraries(p3audio p3putil p3event p3movies p3linmath)
+target_interrogate(p3audio ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3audio
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3AUDIO_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 61 - 0
panda/src/audiotraits/CMakeLists.txt

@@ -0,0 +1,61 @@
+if(NOT HAVE_AUDIO)
+  return()
+elseif(NOT HAVE_FMODEX AND NOT HAVE_OPENAL)
+  message(SEND_ERROR
+    "You must have an audio backend for audio support! Turn off HAVE_AUDIO to ignore this.")
+endif()
+
+if(HAVE_FMODEX)
+  set(P3FMOD_HEADERS
+    config_fmodAudio.h
+    fmodAudioManager.h
+    fmodAudioSound.I fmodAudioSound.h
+  )
+
+  set(P3FMOD_SOURCES
+    config_fmodAudio.cxx fmodAudioManager.cxx fmodAudioSound.cxx
+  )
+
+  composite_sources(p3fmod_audio P3FMOD_SOURCES)
+  add_library(p3fmod_audio ${MODULE_TYPE} ${P3FMOD_HEADERS} ${P3FMOD_SOURCES})
+  set_target_properties(p3fmod_audio PROPERTIES DEFINE_SYMBOL BUILDING_FMOD_AUDIO)
+  target_link_libraries(p3fmod_audio panda PKG::FMODEX)
+
+  install(TARGETS p3fmod_audio
+    EXPORT FMOD COMPONENT FMOD
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT FMODDevel)
+  install(FILES ${P3FMOD_HEADERS} COMPONENT FMODDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+
+  export_targets(FMOD NAMESPACE "Panda3D::FMOD::" COMPONENT FMODDevel)
+endif()
+
+if(HAVE_OPENAL)
+  set(P3OPENAL_HEADERS
+    config_openalAudio.h
+    openalAudioManager.h
+    openalAudioSound.I openalAudioSound.h
+  )
+
+  set(P3OPENAL_SOURCES
+    config_openalAudio.cxx openalAudioManager.cxx openalAudioSound.cxx
+  )
+
+
+  composite_sources(p3openal_audio P3OPENAL_SOURCES)
+  add_library(p3openal_audio ${MODULE_TYPE} ${P3OPENAL_HEADERS} ${P3OPENAL_SOURCES})
+  set_target_properties(p3openal_audio PROPERTIES DEFINE_SYMBOL BUILDING_OPENAL_AUDIO)
+  target_link_libraries(p3openal_audio panda PKG::OPENAL)
+
+  install(TARGETS p3openal_audio
+    EXPORT OpenAL COMPONENT OpenAL
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT OpenALDevel)
+  install(FILES ${P3OPENAL_HEADERS} COMPONENT OpenALDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+
+  export_targets(OpenAL NAMESPACE "Panda3D::OpenAL::" COMPONENT OpenALDevel)
+endif()

+ 130 - 0
panda/src/bullet/CMakeLists.txt

@@ -0,0 +1,130 @@
+if(NOT HAVE_BULLET)
+  return()
+endif()
+
+set(P3BULLET_HEADERS
+  config_bullet.h
+  bullet_includes.h
+  bullet_utils.I bullet_utils.h
+  bulletAllHitsRayResult.I bulletAllHitsRayResult.h
+  bulletBaseCharacterControllerNode.I bulletBaseCharacterControllerNode.h
+  bulletBodyNode.I bulletBodyNode.h
+  bulletBoxShape.I bulletBoxShape.h
+  bulletCapsuleShape.I bulletCapsuleShape.h
+  bulletCharacterControllerNode.I bulletCharacterControllerNode.h
+  bulletClosestHitRayResult.I bulletClosestHitRayResult.h
+  bulletClosestHitSweepResult.I bulletClosestHitSweepResult.h
+  bulletConeShape.I bulletConeShape.h
+  bulletConeTwistConstraint.I bulletConeTwistConstraint.h
+  bulletConstraint.I bulletConstraint.h
+  bulletContactCallbackData.I bulletContactCallbackData.h
+  bulletContactCallbacks.h
+  bulletContactResult.I bulletContactResult.h
+  bulletConvexHullShape.I bulletConvexHullShape.h
+  bulletConvexPointCloudShape.I bulletConvexPointCloudShape.h
+  bulletCylinderShape.I bulletCylinderShape.h
+  bulletDebugNode.I bulletDebugNode.h
+  bulletFilterCallbackData.I bulletFilterCallbackData.h
+  bulletGenericConstraint.I bulletGenericConstraint.h
+  bulletGhostNode.I bulletGhostNode.h
+  bulletHeightfieldShape.I bulletHeightfieldShape.h
+  bulletHelper.I bulletHelper.h
+  bulletHingeConstraint.I bulletHingeConstraint.h
+  bulletManifoldPoint.I bulletManifoldPoint.h
+  bulletMinkowskiSumShape.I bulletMinkowskiSumShape.h
+  bulletMultiSphereShape.I bulletMultiSphereShape.h
+  bulletPersistentManifold.I bulletPersistentManifold.h
+  bulletPlaneShape.I bulletPlaneShape.h
+  bulletRigidBodyNode.I bulletRigidBodyNode.h
+  bulletRotationalLimitMotor.I bulletRotationalLimitMotor.h
+  bulletShape.I bulletShape.h
+  bulletSliderConstraint.I bulletSliderConstraint.h
+  bulletSoftBodyConfig.I bulletSoftBodyConfig.h
+  bulletSoftBodyControl.I bulletSoftBodyControl.h
+  bulletSoftBodyMaterial.I bulletSoftBodyMaterial.h
+  bulletSoftBodyNode.I bulletSoftBodyNode.h
+  bulletSoftBodyShape.I bulletSoftBodyShape.h
+  bulletSoftBodyWorldInfo.I bulletSoftBodyWorldInfo.h
+  bulletSphereShape.I bulletSphereShape.h
+  bulletSphericalConstraint.I bulletSphericalConstraint.h
+  bulletTickCallbackData.I bulletTickCallbackData.h
+  bulletTranslationalLimitMotor.I bulletTranslationalLimitMotor.h
+  bulletTriangleMesh.I bulletTriangleMesh.h
+  bulletTriangleMeshShape.I bulletTriangleMeshShape.h
+  bulletVehicle.I bulletVehicle.h
+  bulletWheel.I bulletWheel.h
+  bulletWorld.I bulletWorld.h
+)
+
+set(P3BULLET_SOURCES
+  config_bullet.cxx
+  bullet_utils.cxx
+  bulletAllHitsRayResult.cxx
+  bulletBaseCharacterControllerNode.cxx
+  bulletBodyNode.cxx
+  bulletBoxShape.cxx
+  bulletCapsuleShape.cxx
+  bulletCharacterControllerNode.cxx
+  bulletClosestHitRayResult.cxx
+  bulletClosestHitSweepResult.cxx
+  bulletConeShape.cxx
+  bulletConeTwistConstraint.cxx
+  bulletConstraint.cxx
+  bulletContactCallbackData.cxx
+  bulletContactResult.cxx
+  bulletConvexHullShape.cxx
+  bulletConvexPointCloudShape.cxx
+  bulletCylinderShape.cxx
+  bulletDebugNode.cxx
+  bulletFilterCallbackData.cxx
+  bulletGenericConstraint.cxx
+  bulletGhostNode.cxx
+  bulletHeightfieldShape.cxx
+  bulletHelper.cxx
+  bulletHingeConstraint.cxx
+  bulletManifoldPoint.cxx
+  bulletMinkowskiSumShape.cxx
+  bulletMultiSphereShape.cxx
+  bulletPersistentManifold.cxx
+  bulletPlaneShape.cxx
+  bulletRigidBodyNode.cxx
+  bulletRotationalLimitMotor.cxx
+  bulletShape.cxx
+  bulletSliderConstraint.cxx
+  bulletSoftBodyConfig.cxx
+  bulletSoftBodyControl.cxx
+  bulletSoftBodyMaterial.cxx
+  bulletSoftBodyNode.cxx
+  bulletSoftBodyShape.cxx
+  bulletSoftBodyWorldInfo.cxx
+  bulletSphereShape.cxx
+  bulletSphericalConstraint.cxx
+  bulletTickCallbackData.cxx
+  bulletTranslationalLimitMotor.cxx
+  bulletTriangleMesh.cxx
+  bulletTriangleMeshShape.cxx
+  bulletVehicle.cxx
+  bulletWheel.cxx
+  bulletWorld.cxx
+)
+
+composite_sources(p3bullet P3BULLET_SOURCES)
+add_library(p3bullet ${P3BULLET_SOURCES} ${P3BULLET_HEADERS})
+set_target_properties(p3bullet PROPERTIES DEFINE_SYMBOL BUILDING_PANDABULLET)
+target_link_libraries(p3bullet panda PKG::BULLET)
+target_interrogate(p3bullet ALL)
+
+if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+  # Clang emulating MSVC; it has builtin defines for __m128 + __m128 and co.
+  target_compile_definitions(p3bullet PUBLIC BT_NO_SIMD_OPERATOR_OVERLOADS)
+endif()
+
+install(TARGETS p3bullet
+  EXPORT Bullet COMPONENT Bullet
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+  ARCHIVE COMPONENT BulletDevel)
+install(FILES ${P3BULLET_HEADERS} COMPONENT BulletDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)
+
+export_targets(Bullet COMPONENT BulletDevel)

+ 69 - 0
panda/src/chan/CMakeLists.txt

@@ -0,0 +1,69 @@
+set(P3CHAN_HEADERS
+  animBundle.I animBundle.h
+  animBundleNode.I animBundleNode.h
+  animChannel.I animChannel.h animChannelBase.I
+  animChannelBase.h
+  animChannelFixed.I animChannelFixed.h
+  animChannelMatrixDynamic.I animChannelMatrixDynamic.h
+  animChannelMatrixFixed.I animChannelMatrixFixed.h
+  animChannelMatrixXfmTable.I animChannelMatrixXfmTable.h
+  animChannelScalarDynamic.I animChannelScalarDynamic.h
+  animChannelScalarTable.I animChannelScalarTable.h
+  animControl.I
+  animControl.h animControlCollection.I
+  animControlCollection.h animGroup.I animGroup.h
+  animPreloadTable.I animPreloadTable.h
+  auto_bind.h
+  bindAnimRequest.I bindAnimRequest.h
+  config_chan.h
+  movingPart.I movingPart.h
+  movingPartBase.I movingPartBase.h
+  movingPartMatrix.I movingPartMatrix.h movingPartScalar.I
+  movingPartScalar.h partBundle.I partBundle.h
+  partBundleHandle.I partBundleHandle.h
+  partBundleNode.I partBundleNode.h
+  partGroup.I partGroup.h
+  partSubset.I partSubset.h
+  vector_PartGroupStar.h
+)
+
+set(P3CHAN_SOURCES
+  animBundle.cxx
+  animBundleNode.cxx
+  animChannel.cxx
+  animChannelBase.cxx
+  animChannelFixed.cxx
+  animChannelMatrixDynamic.cxx
+  animChannelMatrixFixed.cxx
+  animChannelMatrixXfmTable.cxx
+  animChannelScalarDynamic.cxx
+  animChannelScalarTable.cxx
+  animControl.cxx
+  animControlCollection.cxx animGroup.cxx
+  animPreloadTable.cxx
+  auto_bind.cxx
+  bindAnimRequest.cxx
+  config_chan.cxx movingPartBase.cxx movingPartMatrix.cxx
+  movingPartScalar.cxx partBundle.cxx
+  partBundleHandle.cxx
+  partBundleNode.cxx
+  partGroup.cxx
+  partSubset.cxx
+  vector_PartGroupStar.cxx
+)
+
+composite_sources(p3chan P3CHAN_SOURCES)
+add_component_library(p3chan NOINIT SYMBOL BUILDING_PANDA_CHAN
+  ${P3CHAN_HEADERS} ${P3CHAN_SOURCES})
+target_link_libraries(p3chan p3pgraph)
+target_interrogate(p3chan ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3chan
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3CHAN_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 36 - 0
panda/src/char/CMakeLists.txt

@@ -0,0 +1,36 @@
+set(P3CHAR_HEADERS
+  character.I character.h
+  characterJoint.I characterJoint.h
+  characterJointBundle.I characterJointBundle.h
+  characterJointEffect.h characterJointEffect.I
+  characterSlider.h
+  characterVertexSlider.I characterVertexSlider.h
+  config_char.h
+  jointVertexTransform.I jointVertexTransform.h
+)
+
+set(P3CHAR_SOURCES
+  character.cxx
+  characterJoint.cxx characterJointBundle.cxx
+  characterJointEffect.cxx
+  characterSlider.cxx
+  characterVertexSlider.cxx
+  config_char.cxx
+  jointVertexTransform.cxx
+)
+
+composite_sources(p3char P3CHAR_SOURCES)
+add_component_library(p3char SYMBOL BUILDING_PANDA_CHAR
+  ${P3CHAR_HEADERS} ${P3CHAR_SOURCES})
+target_link_libraries(p3char p3chan)
+target_interrogate(p3char ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3char
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3CHAR_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 47 - 0
panda/src/cocoadisplay/CMakeLists.txt

@@ -0,0 +1,47 @@
+if(NOT APPLE OR NOT HAVE_GL OR NOT HAVE_COCOA)
+  return()
+endif()
+
+set(P3COCOADISPLAY_HEADERS
+  config_cocoadisplay.h
+  cocoaGraphicsBuffer.h cocoaGraphicsBuffer.I
+  cocoaGraphicsPipe.h cocoaGraphicsPipe.I
+  cocoaGraphicsWindow.h cocoaGraphicsWindow.I
+  cocoaGraphicsStateGuardian.h cocoaGraphicsStateGuardian.I
+  cocoaPandaApp.h
+  cocoaPandaView.h
+  cocoaPandaWindow.h
+  cocoaPandaWindowDelegate.h
+  cocoaPandaAppDelegate.h
+)
+
+set(P3COCOADISPLAY_SOURCES
+  config_cocoadisplay.mm
+  cocoaGraphicsBuffer.mm
+  cocoaGraphicsPipe.mm
+  cocoaGraphicsStateGuardian.mm
+  cocoaGraphicsWindow.mm
+  cocoaPandaApp.mm
+  cocoaPandaView.mm
+  cocoaPandaWindow.mm
+  cocoaPandaWindowDelegate.mm
+  cocoaPandaAppDelegate.mm
+)
+
+composite_sources(p3cocoadisplay P3COCOADISPLAY_SOURCES)
+add_component_library(p3cocoadisplay SYMBOL BUILDING_PANDA_COCOADISPLAY
+  ${P3COCOADISPLAY_HEADERS} ${P3COCOADISPLAY_SOURCES})
+target_link_libraries(p3cocoadisplay p3glgsg panda)
+
+# Frameworks:
+find_library(APPLICATIONSERVICES_LIBRARY ApplicationServices)
+find_library(APPKIT_LIBRARY AppKit)
+find_library(CARBON_LIBRARY Carbon)
+find_library(CORE_VIDEO_LIBRARY CoreVideo)
+target_link_libraries(p3cocoadisplay
+  ${APPLICATIONSERVICES_LIBRARY} ${APPKIT_LIBRARY} ${CARBON_LIBRARY}
+  ${CORE_VIDEO_LIBRARY})
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3cocoadisplay EXPORT OpenGL COMPONENT OpenGL DESTINATION ${CMAKE_INSTALL_LIBDIR})
+endif()

+ 82 - 0
panda/src/collide/CMakeLists.txt

@@ -0,0 +1,82 @@
+set(P3COLLIDE_HEADERS
+  collisionBox.I collisionBox.h
+  collisionCapsule.I collisionCapsule.h
+  collisionEntry.I collisionEntry.h
+  collisionGeom.I collisionGeom.h
+  collisionHandler.I collisionHandler.h
+  collisionHandlerEvent.I collisionHandlerEvent.h
+  collisionHandlerHighestEvent.h
+  collisionHandlerFloor.I collisionHandlerFloor.h
+  collisionHandlerGravity.I collisionHandlerGravity.h
+  collisionHandlerPhysical.I collisionHandlerPhysical.h
+  collisionHandlerPusher.I collisionHandlerPusher.h
+  collisionHandlerFluidPusher.I collisionHandlerFluidPusher.h
+  collisionHandlerQueue.h
+  collisionInvSphere.I collisionInvSphere.h
+  collisionLine.I collisionLine.h
+  collisionLevelStateBase.I collisionLevelStateBase.h
+  collisionLevelState.I collisionLevelState.h
+  collisionNode.I collisionNode.h
+  collisionParabola.I collisionParabola.h
+  collisionPlane.I collisionPlane.h
+  collisionPolygon.I collisionPolygon.h
+  collisionFloorMesh.I collisionFloorMesh.h
+  collisionRay.I collisionRay.h
+  collisionRecorder.I collisionRecorder.h
+  collisionSegment.I collisionSegment.h
+  collisionSolid.I collisionSolid.h
+  collisionSphere.I collisionSphere.h
+  collisionTraverser.I collisionTraverser.h
+  collisionTube.h
+  collisionVisualizer.I collisionVisualizer.h
+  config_collide.h
+)
+
+set(P3COLLIDE_SOURCES
+  collisionBox.cxx
+  collisionCapsule.cxx
+  collisionEntry.cxx
+  collisionGeom.cxx
+  collisionHandler.cxx
+  collisionHandlerEvent.cxx
+  collisionHandlerHighestEvent.cxx
+  collisionHandlerFloor.cxx
+  collisionHandlerGravity.cxx
+  collisionHandlerPhysical.cxx
+  collisionHandlerPusher.cxx
+  collisionHandlerFluidPusher.cxx
+  collisionHandlerQueue.cxx
+  collisionLevelStateBase.cxx
+  collisionLevelState.cxx
+  collisionInvSphere.cxx
+  collisionLine.cxx
+  collisionNode.cxx
+  collisionParabola.cxx
+  collisionPlane.cxx
+  collisionPolygon.cxx
+  collisionFloorMesh.cxx
+  collisionRay.cxx
+  collisionRecorder.cxx
+  collisionSegment.cxx
+  collisionSolid.cxx
+  collisionSphere.cxx
+  collisionTraverser.cxx
+  collisionVisualizer.cxx
+  config_collide.cxx
+)
+
+composite_sources(p3collide P3COLLIDE_SOURCES)
+add_component_library(p3collide SYMBOL BUILDING_PANDA_COLLIDE
+  ${P3COLLIDE_HEADERS} ${P3COLLIDE_SOURCES})
+target_link_libraries(p3collide p3tform)
+target_interrogate(p3collide ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3collide
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3COLLIDE_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 79 - 0
panda/src/configfiles/CMakeLists.txt

@@ -0,0 +1,79 @@
+# Set some variables that are used in panda.prc.in.
+set(AUX_DISPLAYS)
+
+if(HAVE_GL)
+  set(AUX_DISPLAYS "${AUX_DISPLAYS}\naux-display pandagl")
+endif()
+
+if(HAVE_DX9)
+  set(AUX_DISPLAYS "${AUX_DISPLAYS}\naux-display pandadx9")
+endif()
+
+if(HAVE_TINYDISPLAY)
+  set(AUX_DISPLAYS "${AUX_DISPLAYS}\naux-display p3tinydisplay")
+endif()
+
+if(HAVE_OPENAL)
+  set(AUDIO_LIBRARY_NAME p3openal_audio)
+elseif(HAVE_FMODEX)
+  set(AUDIO_LIBRARY_NAME p3fmod_audio)
+else()
+  set(AUDIO_LIBRARY_NAME none)
+endif()
+
+if(WIN32)
+  set(BAM_CACHE_DIR
+    "$USER_APPDATA/Panda3D-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
+elseif(APPLE)
+  set(BAM_CACHE_DIR
+    "$HOME/Library/Caches/Panda3D-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
+else()
+  set(BAM_CACHE_DIR
+    "$XDG_CACHE_HOME/panda3d")
+endif()
+
+if(UNIX)
+  # On Unices, ask the GNUInstallDirs module where /etc is -- and then install
+  # ourselves into /etc/panda3d
+  set(prc_install_path "${CMAKE_INSTALL_FULL_SYSCONFDIR}/panda3d")
+  set(prc_build_path "${PANDA_OUTPUT_DIR}/etc/panda3d")
+else()
+  set(prc_install_path "etc")
+  set(prc_build_path "${PANDA_OUTPUT_DIR}/etc")
+endif()
+
+# Path from the directory containing *.prc to the directory containing plugins
+file(RELATIVE_PATH PLUGINS_PATH
+  "${prc_build_path}" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
+
+# Path from the directory containing *.prc to the *parent of* models/
+# In the build tree, reckoning this is pretty easy
+file(RELATIVE_PATH MODELS_PARENT_PATH "${prc_build_path}" "${PANDA_OUTPUT_DIR}")
+configure_file(panda.prc.in "${CMAKE_CURRENT_BINARY_DIR}/20_panda.prc")
+
+# For the install tree, we need to introspect our paths
+set(abs_prc_install_path "${prc_install_path}")
+set(abs_datadir "${CMAKE_INSTALL_DATADIR}")
+set(abs_plugindir "${MODULE_DESTINATION}")
+if(NOT IS_ABSOLUTE "${abs_prc_install_path}")
+  set(abs_prc_install_path "${CMAKE_INSTALL_PREFIX}/${abs_prc_install_path}")
+endif()
+if(NOT IS_ABSOLUTE "${abs_datadir}")
+  set(abs_datadir "${CMAKE_INSTALL_PREFIX}/${abs_datadir}")
+endif()
+if(NOT IS_ABSOLUTE "${abs_plugindir}")
+  set(abs_plugindir "${CMAKE_INSTALL_PREFIX}/${abs_plugindir}")
+endif()
+file(RELATIVE_PATH PLUGINS_PATH
+  "${abs_prc_install_path}" "${abs_plugindir}")
+file(RELATIVE_PATH MODELS_PARENT_PATH
+  "${abs_prc_install_path}" "${abs_datadir}/panda3d")
+configure_file(panda.prc.in "${CMAKE_CURRENT_BINARY_DIR}/20_panda.prc.install")
+
+file(GENERATE OUTPUT "${prc_build_path}/20_panda.prc"
+              INPUT "${CMAKE_CURRENT_BINARY_DIR}/20_panda.prc")
+file(GENERATE OUTPUT "${prc_build_path}/20_panda.prc.install"
+              INPUT "${CMAKE_CURRENT_BINARY_DIR}/20_panda.prc.install")
+
+install(FILES "${prc_build_path}/20_panda.prc.install" RENAME "20_panda.prc"
+  COMPONENT Core DESTINATION ${prc_install_path})

+ 130 - 0
panda/src/configfiles/panda.prc.in

@@ -0,0 +1,130 @@
+#### Generated automatically by CMake ${CMAKE_VERSION} from panda.prc.in.
+################################# DO NOT EDIT ###########################
+
+# Some paths first...
+plugin-path $THIS_PRC_DIR/${PLUGINS_PATH}
+model-path $MAIN_DIR
+model-path $THIS_PRC_DIR/${MODELS_PARENT_PATH}
+model-path $THIS_PRC_DIR/${MODELS_PARENT_PATH}/models
+
+# Let's set up a default window size of 800x600.  The user can
+# override this in a separate, personal prc file.
+win-origin -2 -2
+win-size 800 600
+
+# For debugging, it's nice to have notify-level at the default setting of
+# "info", but everywhere else we turn the verbosity down to "warning"
+$<$<CONFIG:Debug>:#>notify-level warning
+
+# Define the display types that have been compiled in.  Panda will
+# pick one of these by going through the list in this order until one
+# is found that works, unless the user specifically requests a
+# particular display type with the load-display directive.
+${AUX_DISPLAYS}
+
+# Define an appropriate default audio library.
+audio-library-name ${AUDIO_LIBRARY_NAME}
+
+# The egg loader is handy to have available by default.  This allows
+# clients to load egg files.  (The bam loader is built-in so bam files
+# are always loadable).
+
+# By qualifying with the extension "egg", we indicate the egg loader
+# should be made available only if you explicitly name a file with an
+# .egg extension.
+
+# Also see ptloader, which is built as part of pandatool; it allows
+# files of more exotic types (like .flt, .mb, .lwo, and .dxf) to be
+# loaded directly into Panda.
+
+load-file-type egg pandaegg
+default-model-extension .egg
+
+# Enable the model-cache, but only for models, not textures.
+model-cache-dir ${BAM_CACHE_DIR}
+model-cache-textures #f
+
+
+# These entries work very similar to load-file-type, except they are
+# used by the MovieVideo and MovieAudio code to determine which module
+# should be loaded in order to decode files of the given extension.
+
+# ffmpeg is added by default because it used to be compiled in.
+# The * is a special catch-all extension that is consulted unless a
+# loader has been defined with an explicit extension.
+
+load-audio-type * p3ffmpeg
+load-video-type * p3ffmpeg
+
+
+# The following lines define some handy object types to use within the
+# egg syntax.  This remaps <ObjectType> { name } into whatever egg
+# syntax is given by egg-object-type-name, which makes a handy
+# abbreviation for modeling packages (like Maya) to insert
+# sophisticated egg syntax into the generated egg file, using a single
+# object type string.
+
+egg-object-type-portal          <Scalar> portal { 1 }
+egg-object-type-polylight       <Scalar> polylight { 1 }
+egg-object-type-seq24           <Switch> { 1 } <Scalar> fps { 24 }
+egg-object-type-seq12           <Switch> { 1 } <Scalar> fps { 12 }
+egg-object-type-seq10           <Switch> { 1 } <Scalar> fps { 10 }
+egg-object-type-seq8            <Switch> { 1 } <Scalar> fps { 8 }
+egg-object-type-seq6            <Switch> { 1} <Scalar>  fps { 6 }
+egg-object-type-seq4            <Switch> { 1} <Scalar>  fps { 4 }
+egg-object-type-seq2            <Switch> { 1} <Scalar>  fps { 2 }
+egg-object-type-indexed         <Scalar> indexed { 1 }
+
+egg-object-type-binary          <Scalar> alpha { binary }
+egg-object-type-dual            <Scalar> alpha { dual }
+egg-object-type-glass           <Scalar> alpha { blend_no_occlude }
+
+# These are just shortcuts to define the Model and DCS flags, which
+# indicate nodes that should not be flattened out of the hierarchy
+# during the conversion process.  DCS goes one step further and
+# indicates that the node's transform is important and should be
+# preserved (DCS stands for Dynamic Coordinate System).  Notouch is
+# even stronger, and means not to do any flattening below the node at
+# all.
+egg-object-type-model           <Model> { 1 }
+egg-object-type-dcs             <DCS> { 1 }
+egg-object-type-notouch         <DCS> { no_touch }
+
+# The following define various kinds of collision geometry.  These
+# mark the geometry at this level and below as invisible collision
+# polygons, which can be used by Panda's collision system to detect
+# collisions more optimally than regular visible polygons.
+egg-object-type-barrier         <Collide> { Polyset descend }
+egg-object-type-sphere          <Collide> { Sphere descend }
+egg-object-type-invsphere       <Collide> { InvSphere descend }
+egg-object-type-tube            <Collide> { Tube descend }
+
+# As above, but these are flagged to be "intangible", so that they
+# will trigger an event but not stop an object from passing through.
+egg-object-type-trigger         <Collide> { Polyset descend intangible }
+egg-object-type-trigger-sphere  <Collide> { Sphere descend intangible }
+
+# "floor" and "dupefloor" define the nodes in question as floor
+# polygons.  dupefloor means to duplicate the geometry first so that
+# the same polygons serve both as visible geometry and as collision
+# polygons.
+egg-object-type-floor           <Collide> { Polyset descend level }
+egg-object-type-dupefloor       <Collide> { Polyset keep descend level }
+
+# "bubble" puts an invisible bubble around an object, but does not
+# otherwise remove the geometry.
+egg-object-type-bubble          <Collide> { Sphere keep descend }
+
+# "ghost" turns off the normal collide bit that is set on visible
+# geometry by default, so that if you are using visible geometry for
+# collisions, this particular geometry will not be part of those
+# collisions--it is ghostlike.
+egg-object-type-ghost           <Scalar> collide-mask { 0 }
+
+# "glow" is useful for halo effects and things of that ilk.  It
+# renders the object in add mode instead of the normal opaque mode.
+egg-object-type-glow            <Scalar> blend { add }
+
+# This isn't used in the egg loader, it controls a setting only within
+# maya2egg itself.  So if it appears in an egg file, it means nothing.
+egg-object-type-keep-all-uvsets

+ 37 - 0
panda/src/cull/CMakeLists.txt

@@ -0,0 +1,37 @@
+set(P3CULL_HEADERS
+  binCullHandler.h binCullHandler.I
+  config_cull.h
+  cullBinBackToFront.h cullBinBackToFront.I
+  cullBinFixed.h cullBinFixed.I
+  cullBinFrontToBack.h cullBinFrontToBack.I
+  cullBinStateSorted.h cullBinStateSorted.I
+  cullBinUnsorted.h cullBinUnsorted.I
+  drawCullHandler.h drawCullHandler.I
+)
+
+set(P3CULL_SOURCES
+  binCullHandler.cxx
+  config_cull.cxx
+  cullBinBackToFront.cxx
+  cullBinFixed.cxx
+  cullBinFrontToBack.cxx
+  cullBinStateSorted.cxx
+  cullBinUnsorted.cxx
+  drawCullHandler.cxx
+)
+
+composite_sources(p3cull P3CULL_SOURCES)
+add_component_library(p3cull SYMBOL BUILDING_PANDA_CULL
+  ${P3CULL_HEADERS} ${P3CULL_SOURCES})
+target_link_libraries(p3cull p3pgraph)
+target_interrogate(p3cull ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3cull
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3CULL_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 80 - 0
panda/src/device/CMakeLists.txt

@@ -0,0 +1,80 @@
+set(P3DEVICE_HEADERS
+  analogNode.h analogNode.I
+  buttonNode.h buttonNode.I
+  clientAnalogDevice.h clientAnalogDevice.I
+  clientBase.h clientBase.I
+  clientButtonDevice.h clientButtonDevice.I
+  clientDevice.h clientDevice.I
+  clientDialDevice.h clientDialDevice.I
+  clientTrackerDevice.h clientTrackerDevice.I
+  config_device.h
+  dialNode.h dialNode.I
+  evdevInputDevice.h evdevInputDevice.I
+  inputDevice.h inputDevice.I
+  inputDeviceManager.h inputDeviceManager.I
+  inputDeviceNode.h
+  inputDeviceSet.h inputDeviceSet.I
+  ioKitInputDevice.h
+  ioKitInputDeviceManager.h
+  linuxInputDeviceManager.h
+  linuxJoystickDevice.h linuxJoystickDevice.I
+  trackerData.h trackerData.I
+  trackerNode.h trackerNode.I
+  virtualMouse.h
+  winInputDeviceManager.h
+  winRawInputDevice.h
+  xInputDevice.h
+)
+
+set(P3DEVICE_SOURCES
+  analogNode.cxx
+  buttonNode.cxx
+  clientAnalogDevice.cxx
+  clientBase.cxx
+  clientButtonDevice.cxx
+  clientDevice.cxx
+  clientDialDevice.cxx
+  clientTrackerDevice.cxx
+  config_device.cxx
+  dialNode.cxx
+  evdevInputDevice.cxx
+  inputDevice.cxx
+  inputDeviceManager.cxx
+  inputDeviceNode.cxx
+  inputDeviceSet.cxx
+  ioKitInputDevice.cxx
+  ioKitInputDeviceManager.cxx
+  linuxInputDeviceManager.cxx
+  linuxJoystickDevice.cxx
+  trackerData.cxx
+  trackerNode.cxx
+  virtualMouse.cxx
+  winInputDeviceManager.cxx
+  winRawInputDevice.cxx
+  xInputDevice.cxx
+)
+
+composite_sources(p3device P3DEVICE_SOURCES)
+add_component_library(p3device SYMBOL BUILDING_PANDA_DEVICE
+  ${P3DEVICE_HEADERS} ${P3DEVICE_SOURCES})
+target_link_libraries(p3device p3dgraph)
+target_interrogate(p3device ALL)
+
+if(WIN32)
+  target_link_libraries(p3device Cfgmgr32.lib)
+
+elseif(APPLE)
+  find_library(IOKIT_LIBRARY IOKit)
+  target_link_libraries(p3device ${IOKIT_LIBRARY})
+
+endif()
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3device
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3DEVICE_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

+ 29 - 0
panda/src/dgraph/CMakeLists.txt

@@ -0,0 +1,29 @@
+set(P3DGRAPH_HEADERS
+  config_dgraph.h
+  dataGraphTraverser.I dataGraphTraverser.h
+  dataNode.I dataNode.h
+  dataNodeTransmit.I dataNodeTransmit.h
+)
+
+set(P3DGRAPH_SOURCES
+  config_dgraph.cxx
+  dataGraphTraverser.cxx
+  dataNode.cxx
+  dataNodeTransmit.cxx
+)
+
+composite_sources(p3dgraph P3DGRAPH_SOURCES)
+add_component_library(p3dgraph NOINIT SYMBOL BUILDING_PANDA_DGRAPH
+  ${P3DGRAPH_HEADERS} ${P3DGRAPH_SOURCES})
+target_link_libraries(p3dgraph p3pgraph)
+target_interrogate(p3dgraph ALL)
+
+if(NOT BUILD_METALIBS)
+  install(TARGETS p3dgraph
+    EXPORT Core COMPONENT Core
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d
+    ARCHIVE COMPONENT CoreDevel)
+endif()
+install(FILES ${P3DGRAPH_HEADERS} COMPONENT CoreDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d)

部分文件因文件數量過多而無法顯示