diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md index 91417cb9ff0..762c6844506 100644 --- a/.github/ISSUE_TEMPLATE/bug.md +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -2,6 +2,7 @@ name: Bug report about: Report a defect title: +type: bug labels: assignees: --- diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..98ee85f95f5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +contact_links: + - name: Community forums + url: https://discourse.panda3d.org/ + about: Please visit the community forums for technical support and other questions. + + - name: Documentation bugs + url: https://github.com/panda3d/panda3d-docs/issues + about: Problems with the online documentation should be reported on the panda3d-docs issue tracker, not here. + + - name: Discord server + url: https://discord.gg/UyepRMm + about: Get real-time help with questions about Panda3D or discuss ideas with the developers on our Discord server. diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md index 954153caf3e..190f226dbb6 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.md +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -2,6 +2,7 @@ name: Enhancement request about: Request new functionality or improvement to existing functionality title: +type: feature labels: enhancement assignees: --- diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..4fc308718e4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..04cea3eec72 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,554 @@ +name: Continuous Integration +on: [push, pull_request] + +jobs: + cmake: + name: CMake Buildsystem + if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')" + + strategy: + fail-fast: false + + matrix: + profile: + - ubuntu-bionic-double-standard-unity-makefile + - ubuntu-bionic-coverage-ninja + #- macos-coverage-unity-xcode + - macos-nometa-standard-makefile + - windows-standard-unity-msvc + - windows-nopython-nometa-standard-msvc + + include: + - profile: ubuntu-bionic-double-standard-unity-makefile + os: ubuntu-20.04 + config: Standard + unity: YES + generator: Unix Makefiles + compiler: Default + metalibs: YES + python: YES + eigen: NO + double: YES + + - profile: ubuntu-bionic-coverage-ninja + os: ubuntu-20.04 + config: Coverage + unity: NO + generator: Ninja + compiler: Clang + metalibs: YES + python: YES + eigen: NO + double: NO + + #- profile: macos-coverage-unity-xcode + # os: macOS-13 + # config: Coverage + # unity: YES + # generator: Xcode + # compiler: Default + # metalibs: YES + # python: YES + # eigen: NO + # double: NO + + - profile: macos-nometa-standard-makefile + os: macOS-13 + config: Standard + unity: NO + generator: Unix Makefiles + compiler: Default + metalibs: NO + python: YES + eigen: NO + double: NO + + - profile: windows-standard-unity-msvc + os: windows-2022 + config: Standard + unity: YES + generator: Visual Studio 17 2022 + compiler: Default + metalibs: YES + python: YES + eigen: NO + double: NO + + - profile: windows-nopython-nometa-standard-msvc + os: windows-2022 + config: Standard + unity: NO + generator: Visual Studio 17 2022 + compiler: Default + metalibs: NO + python: NO + eigen: NO + double: NO + + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 10 + + - name: Self-destruct makepanda + run: python3 makepanda/selfdestruct.py --yes + + - name: Install dependencies (macOS) + if: runner.os == 'macOS' + run: | + curl -O https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-mac.tar.gz + tar -xf panda3d-1.10.15-tools-mac.tar.gz + mv panda3d-1.10.15/thirdparty thirdparty + rmdir panda3d-1.10.15 + + # Temporary hack so that pzip can run, since we are about to remove Cg anyway. + install_name_tool -id "$(pwd)/thirdparty/darwin-libs-a/nvidiacg/lib/libCg.dylib" thirdparty/darwin-libs-a/nvidiacg/lib/libCg.dylib + + brew install ccache + + - name: Set up XCode (macOS) + if: runner.os == 'macOS' + run: sudo xcode-select -s /Applications/Xcode_14.3.1.app/Contents/Developer + + - 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 + python3-setuptools python3-tk + + - name: Cache dependencies (Windows) + if: runner.os == 'Windows' + uses: actions/cache@v4 + with: + path: thirdparty + key: ci-cmake-${{ runner.OS }}-thirdparty-v1.10.15-r1 + - name: Install dependencies (Windows) + if: runner.os == 'Windows' + shell: powershell + run: | + if (!(Test-Path thirdparty/win-libs-vc14-x64)) { + $wc = New-Object System.Net.WebClient + $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-win64.zip", "thirdparty-tools.zip") + Expand-Archive -Path thirdparty-tools.zip + Move-Item -Path thirdparty-tools/panda3d-1.10.15/thirdparty -Destination . + } + + - name: ccache (non-Windows) + if: runner.os != 'Windows' + uses: actions/cache@v4 + with: + path: ccache + key: ci-cmake-ccache-${{ matrix.profile }} + + - name: Configure + shell: bash + env: + CMAKE_GENERATOR: "${{ matrix.generator }}" + run: > + mkdir -p build + + cd build + + if ${{ matrix.compiler == 'Clang' }}; then + if [[ "$CMAKE_GENERATOR" =~ Studio.+20(19|22) ]]; then + export CMAKE_GENERATOR_TOOLSET=ClangCL + elif [[ "$CMAKE_GENERATOR" == *Studio* ]]; then + export CMAKE_GENERATOR_TOOLSET=LLVM + else + export CC=clang CXX=clang++ + fi + fi + + if ${{ runner.os != 'Windows' }}; then + compilerLauncher=$(echo -DCMAKE_C{,XX}_COMPILER_LAUNCHER=ccache) + export CCACHE_DIR="$(dirname $PWD)/ccache" + echo "CCACHE_DIR=$(dirname $PWD)/ccache" >> $GITHUB_ENV + fi + + cmake + ${compilerLauncher:-} + -D CMAKE_UNITY_BUILD=${{ matrix.unity }} + -D CMAKE_BUILD_TYPE="${{ matrix.config }}" + -D BUILD_METALIBS=${{ matrix.metalibs }} + -D HAVE_PYTHON=${{ runner.os != 'Windows' && matrix.python || 'NO' }} + -D HAVE_EIGEN=${{ matrix.eigen }} + -D STDFLOAT_DOUBLE=${{ matrix.double }} + .. + + - 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 3.8) + if: contains(matrix.python, 'YES') + uses: actions/setup-python@v5 + 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 -DHAVE_PYTHON=YES + -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 + env: + PYTHONPATH: ${{ matrix.config }} + run: | + PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt + export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw + $PYTHON_EXECUTABLE -m pytest ../tests --cov=. + # END B + + - name: Setup Python (Python 3.9) + if: contains(matrix.python, 'YES') + uses: actions/setup-python@v5 + with: + python-version: '3.9' + - name: Configure (Python 3.9) + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + run: > + cmake -DWANT_PYTHON_VERSION=3.9 -DHAVE_PYTHON=YES + -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" . + - name: Build (Python 3.9) + if: contains(matrix.python, 'YES') + # BEGIN A + working-directory: build + run: cmake --build . --config ${{ matrix.config }} --parallel 4 + # END A + - name: Test (Python 3.9) + # BEGIN B + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + env: + PYTHONPATH: ${{ matrix.config }} + run: | + PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt + export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw + $PYTHON_EXECUTABLE -m pytest ../tests --cov=. + # END B + + - name: Setup Python (Python 3.10) + if: contains(matrix.python, 'YES') + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Configure (Python 3.10) + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + run: > + cmake -DWANT_PYTHON_VERSION=3.10 -DHAVE_PYTHON=YES + -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" . + - name: Build (Python 3.10) + if: contains(matrix.python, 'YES') + # BEGIN A + working-directory: build + run: cmake --build . --config ${{ matrix.config }} --parallel 4 + # END A + - name: Test (Python 3.10) + # BEGIN B + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + env: + PYTHONPATH: ${{ matrix.config }} + run: | + PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt + export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw + $PYTHON_EXECUTABLE -m pytest ../tests --cov=. + # END B + + - name: Setup Python (Python 3.11) + if: contains(matrix.python, 'YES') + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Configure (Python 3.11) + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + run: > + cmake -DWANT_PYTHON_VERSION=3.11 -DHAVE_PYTHON=YES + -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" . + - name: Build (Python 3.11) + if: contains(matrix.python, 'YES') + # BEGIN A + working-directory: build + run: cmake --build . --config ${{ matrix.config }} --parallel 4 + # END A + - name: Test (Python 3.11) + # BEGIN B + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + env: + PYTHONPATH: ${{ matrix.config }} + run: | + PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt + export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw + $PYTHON_EXECUTABLE -m pytest ../tests --cov=. + # END B + + - name: Setup Python (Python 3.12) + if: contains(matrix.python, 'YES') + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Configure (Python 3.12) + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + run: > + cmake -DWANT_PYTHON_VERSION=3.12 -DHAVE_PYTHON=YES + -DPython_FIND_REGISTRY=NEVER -DPython_ROOT="$pythonLocation" . + - name: Build (Python 3.12) + if: contains(matrix.python, 'YES') + # BEGIN A + working-directory: build + run: cmake --build . --config ${{ matrix.config }} --parallel 4 + # END A + - name: Test (Python 3.12) + # BEGIN B + if: contains(matrix.python, 'YES') + working-directory: build + shell: bash + env: + PYTHONPATH: ${{ matrix.config }} + run: | + PYTHON_EXECUTABLE=$(grep 'Python_EXECUTABLE:' CMakeCache.txt | sed 's/.*=//') + $PYTHON_EXECUTABLE -m pip install -r ../requirements-test.txt + export COVERAGE_FILE=.coverage.$RANDOM LLVM_PROFILE_FILE=$PWD/pid-%p.profraw + $PYTHON_EXECUTABLE -m pytest ../tests --cov=. + # 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 pip install coverage + 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) -y ../.github/codecov.yml + + makepanda: + if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')" + strategy: + matrix: + os: [ubuntu-20.04, windows-2019, macOS-13] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Install dependencies (Ubuntu) + if: matrix.os == 'ubuntu-20.04' + run: | + sudo apt-get update + sudo apt-get install build-essential bison flex libfreetype6-dev libgl1-mesa-dev libjpeg-dev libode-dev libopenal-dev libpng-dev libssl-dev libvorbis-dev libx11-dev libxcursor-dev libxrandr-dev nvidia-cg-toolkit zlib1g-dev + - name: Get thirdparty packages (Windows) + if: runner.os == 'Windows' + shell: powershell + run: | + $wc = New-Object System.Net.WebClient + $wc.DownloadFile("https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-win64.zip", "thirdparty-tools.zip") + Expand-Archive -Path thirdparty-tools.zip + Move-Item -Path thirdparty-tools/panda3d-1.10.15/thirdparty -Destination . + - name: Get thirdparty packages (macOS) + if: runner.os == 'macOS' + run: | + curl -O https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-mac.tar.gz + tar -xf panda3d-1.10.15-tools-mac.tar.gz + mv panda3d-1.10.15/thirdparty thirdparty + rmdir panda3d-1.10.15 + (cd thirdparty/darwin-libs-a && rm -rf rocket) + + - name: Set up XCode (macOS) + if: runner.os == 'macOS' + run: sudo xcode-select -s /Applications/Xcode_14.3.1.app/Contents/Developer + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: '3.13' + - name: Build Python 3.13 + shell: bash + run: | + python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2 + - name: Test Python 3.13 + shell: bash + run: | + python -m pip install -r requirements-test.txt + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Build Python 3.12 (double) + shell: bash + run: | + python makepanda/makepanda.py --override STDFLOAT_DOUBLE=1 --git-commit=${{github.sha}} --outputdir=built_dbl --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2 + - name: Test Python 3.12 (double) + shell: bash + run: | + python -m pip install -r requirements-test.txt + PYTHONPATH=built_dbl LD_LIBRARY_PATH=built_dbl/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built_dbl/lib python -m pytest + + - name: Make installer + run: | + python makepanda/makepackage.py --verbose --lzma --outputdir=built_dbl + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Build Python 3.11 + shell: bash + run: | + python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2 + - name: Test Python 3.11 + shell: bash + run: | + python -m pip install -r requirements-test.txt + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Build Python 3.10 + shell: bash + run: | + python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2 + - name: Test Python 3.10 + shell: bash + run: | + python -m pip install -r requirements-test.txt + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + + - name: Set up Python 3.9 + uses: actions/setup-python@v5 + with: + python-version: '3.9' + - name: Build Python 3.9 + shell: bash + run: | + python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2 + - name: Test Python 3.9 + shell: bash + run: | + python -m pip install -r requirements-test.txt + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + + - name: Set up Python 3.8 + uses: actions/setup-python@v5 + with: + python-version: '3.8' + - name: Build Python 3.8 + shell: bash + run: | + python makepanda/makepanda.py --git-commit=${{github.sha}} --outputdir=built --everything --no-eigen --python-incdir="$pythonLocation/include" --python-libdir="$pythonLocation/lib" --verbose --threads=4 --windows-sdk=10 --msvc-version=14.2 + - name: Test Python 3.8 + shell: bash + run: | + python -m pip install -r requirements-test.txt + PYTHONPATH=built LD_LIBRARY_PATH=built/lib:$pythonLocation/lib DYLD_LIBRARY_PATH=built/lib python -m pytest + + - name: Make installer + run: | + python makepanda/makepackage.py --verbose --lzma + + emscripten: + if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential ninja-build bison flex nodejs python3-pip + + - name: Setup emsdk + uses: mymindstorm/setup-emsdk@v14 + with: + version: 4.0.2 + actions-cache-folder: 'emsdk-cache' + + - name: Restore Python build cache + id: cache-emscripten-python-restore + uses: actions/cache/restore@v4 + with: + path: ~/python + key: cache-emscripten-python-3.12.8 + + - name: Build Python 3.12 + if: steps.cache-emscripten-python-restore.outputs.cache-hit != 'true' + run: | + wget https://www.python.org/ftp/python/3.12.8/Python-3.12.8.tar.xz + tar -xJf Python-3.12.8.tar.xz + (cd Python-3.12.8 && EM_CONFIG=$EMSDK/.emscripten python3 Tools/wasm/wasm_build.py emscripten-browser) + (cd Python-3.12.8/builddir/emscripten-browser && make install DESTDIR=~/python) + cp Python-3.12.8/builddir/emscripten-browser/Modules/_hacl/libHacl_Hash_SHA2.a ~/python/usr/local/lib + cp Python-3.12.8/builddir/emscripten-browser/Modules/_decimal/libmpdec/libmpdec.a ~/python/usr/local/lib + cp Python-3.12.8/builddir/emscripten-browser/Modules/expat/libexpat.a ~/python/usr/local/lib + rm -rf Python-3.12.8 + + - name: Save Python build cache + id: cache-emscripten-python-save + if: steps.cache-emscripten-python-restore.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ~/python + key: ${{ steps.cache-emscripten-python-restore.outputs.cache-primary-key }} + + - name: Build for Emscripten + shell: bash + run: | + python3 makepanda/makepanda.py --git-commit=${{github.sha}} --target emscripten --python-incdir=~/python/usr/local/include --python-libdir=~/python/usr/local/lib --static --everything --no-pandatool --no-deploytools --verbose --threads=4 + + - name: Install test dependencies + shell: bash + run: | + python3 -m pip install -t ~/python/usr/local/lib/python3.12/site-packages -r requirements-test.txt + + - name: Test in node.js + shell: bash + run: | + PYTHONHOME=~/python/usr/local PYTHONPATH=built node built/bin/run_tests.js tests diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml new file mode 100644 index 00000000000..377ab8ffa0b --- /dev/null +++ b/.github/workflows/mypy.yml @@ -0,0 +1,23 @@ +name: Run Mypy +on: [push, pull_request] + +jobs: + mypy: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.9', '3.13'] + fail-fast: false + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install mypy==1.14.1 + - name: Run mypy on direct + run: python tests/run_mypy.py diff --git a/BACKERS.md b/BACKERS.md index d1a9dd8727a..2b48940fc39 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -4,10 +4,11 @@ This is a list of all the people who are contributing financially to Panda3D. I ## Bronze Sponsors -[ChangeCrab](https://changecrab.com/) ![Bronze Sponsors](https://opencollective.com/panda3d/tiers/bronze-sponsor.svg?avatarHeight=48&width=600) +[Route4Me](https://route4me.com/) * [Daniel Stokes](https://opencollective.com/daniel-stokes) * [David Rose](https://opencollective.com/david-rose) +* [Route4Me](https://route4me.com/) ## Benefactors @@ -32,6 +33,7 @@ This is a list of all the people who are contributing financially to Panda3D. I * GameDev JONI * Max Rodriguez * Jethro Schoppenhorst +* dabe ## Backers diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d1ced66a40..fba23f92d64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,7 @@ 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) +option(BUILD_TOOLS "Build binary tools." ON) # Include Panda3D packages if(BUILD_DTOOL) diff --git a/README.md b/README.md index 54fb9fd07f3..2d96c5ca56b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Please ensure that you build Panda3D with Python 3.11.9. Windows ------- -You can build Panda3D with the Microsoft Visual C++ 2015, 2017, 2019 or 2022 +You can build Panda3D with the Microsoft Visual C++ 2017, 2019 or 2022 compiler, which can be downloaded for free from the [Visual Studio site](https://visualstudio.microsoft.com/downloads/). You will also need to install the [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk), and if you intend to target Windows Vista, you will also need the @@ -42,8 +42,8 @@ depending on whether you are on a 32-bit or 64-bit system, or you can [click here](https://github.com/rdb/panda3d-thirdparty) for instructions on building them from source. -- https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-win64.zip -- https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-win32.zip +- https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-win64.zip +- https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-win32.zip After acquiring these dependencies, you can build Panda3D from the command prompt using the following command. Change the `--msvc-version` option based @@ -114,7 +114,7 @@ macOS ----- On macOS, you will need to download a set of precompiled thirdparty packages in order to -compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.14/panda3d-1.10.14-tools-mac.tar.gz). +compile Panda3D, which can be acquired from [here](https://www.panda3d.org/download/panda3d-1.10.15/panda3d-1.10.15-tools-mac.tar.gz). After placing the thirdparty directory inside the panda3d source directory, you may build Panda3D using a command like the following: @@ -133,6 +133,73 @@ package file in order to install the SDK onto your system. +You will also need to choose which version of Python you want to use. +Install the appropriate package for it (such as `python37` or `python38`) and +run the makepanda script with your chosen Python version: + +```bash +python3.11 makepanda/makepanda.py --everything --installer --no-egl --no-gles --no-gles2 +``` + +If successful, this will produce a .pkg file in the root of the source +directory which you can install using `pkg install`. + +Android +------- + +Although it's possible to build Panda3D on an Android device using the +[termux](https://termux.com/) shell, the recommended route is to cross-compile +.whl files using the SDK and NDK, which can then be used by the `build_apps` +command to build a Python application into an .apk or .aab bundle. You will +need to get the latest thirdparty packages, which can be obtained from here: + +https://rdb.name/thirdparty-android.tar.gz + +This includes a copy of Python 3.13 compiled for Android. You will need to +use Python 3.13 on the host as well. + +These commands show how to compile wheels for the supported Android ABIs: + +```bash +export ANDROID_SDK_ROOT=/home/rdb/local/android +python3.13 makepanda/makepanda.py --everything --outputdir built-droid-arm64 --arch arm64 --target android-21 --threads 6 --wheel +python3.13 makepanda/makepanda.py --everything --outputdir built-droid-armv7a --arch arm --target android-21 --threads 6 --wheel +python3.13 makepanda/makepanda.py --everything --outputdir built-droid-x86_64 --arch x86_64 --target android-21 --threads 6 --wheel +python3.13 makepanda/makepanda.py --everything --outputdir built-droid-x86 --arch x86 --target android-21 --threads 6 --wheel +``` + +It is now possible to use the generated wheels with `build_apps`, as explained +on this page: + +https://discourse.panda3d.org/t/deployment-for-android/28226 + +Running Tests +============= + +Install [PyTest](https://docs.pytest.org/en/latest/getting-started.html#installation) +and run the `pytest` command. If you have not installed Panda3D, you will +need to configure your environment by pointing the `PYTHONPATH` variable at +the `built` directory. On Linux, you will also need to point the +`LD_LIBRARY_PATH` variable at the `built/lib` directory. + +As a convenience, you can alternatively pass the `--tests` option to makepanda. + +Reporting Issues +================ + +If you encounter any bugs when using Panda3D, please report them in the bug +tracker. This is hosted at: + + https://github.com/panda3d/panda3d/issues + +Make sure to first use the search function to see if the bug has already been +reported. When filling out a bug report, make sure that you include as much +information as possible to help the developers track down the issue, such as +your version of Panda3D, operating system, architecture, and any code and +models that are necessary for the developers to reproduce the issue. + +If you're not sure whether you've encountered a bug, feel free to ask about +it in the forums or the IRC channel first. Supporting the Project ====================== diff --git a/cmake/macros/Interrogate.cmake b/cmake/macros/Interrogate.cmake index eea12f95681..7533be7564c 100644 --- a/cmake/macros/Interrogate.cmake +++ b/cmake/macros/Interrogate.cmake @@ -257,7 +257,7 @@ function(interrogate_sources target output database language_flags) make_directory "${output_directory}" COMMAND ${CMAKE_COMMAND} -E make_directory "${database_directory}" - COMMAND host_interrogate + COMMAND interrogate -oc "${output}" -od "${database}" -srcdir "${srcdir}" @@ -272,7 +272,7 @@ function(interrogate_sources target output database language_flags) ${include_flags} ${scan_sources} - DEPENDS host_interrogate ${sources} ${extensions} ${nfiles} + DEPENDS interrogate ${sources} ${extensions} ${nfiles} COMMENT "Interrogating ${target}") # Propagate the target's compile definitions to the output file @@ -283,7 +283,7 @@ endfunction(interrogate_sources) # # Function: add_python_module(module [lib1 [lib2 ...]] [LINK lib1 ...] -# [IMPORT mod1 ...]) +# [IMPORT mod1 ...] [INIT func1 ...]) # 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 @@ -305,7 +305,7 @@ function(add_python_module module) set(keyword) foreach(arg ${ARGN}) - if(arg STREQUAL "LINK" OR arg STREQUAL "IMPORT" OR arg STREQUAL "COMPONENT") + if(arg STREQUAL "LINK" OR arg STREQUAL "IMPORT" OR arg STREQUAL "INIT" OR arg STREQUAL "COMPONENT") set(keyword "${arg}") elseif(keyword STREQUAL "LINK") @@ -316,6 +316,10 @@ function(add_python_module module) list(APPEND import_flags "-import" "${arg}") set(keyword) + elseif(keyword STREQUAL "INIT") + list(APPEND import_flags "-init" "${arg}") + set(keyword) + elseif(keyword STREQUAL "COMPONENT") set(component "${arg}") set(keyword) @@ -362,13 +366,13 @@ function(add_python_module module) 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 + COMMAND interrogate_module -oc "${CMAKE_CURRENT_BINARY_DIR}/${PANDA_CFG_INTDIR}/${module}_module.cxx" -module ${module} -library ${modname} ${import_flags} ${INTERROGATE_MODULE_OPTIONS} ${IMOD_FLAGS} ${infiles_rel} - DEPENDS host_interrogate_module ${infiles_abs} + DEPENDS interrogate_module ${infiles_abs} COMMENT "Generating module ${module}") # CMake chokes on ${CMAKE_CFG_INTDIR} in source paths when unity builds are diff --git a/cmake/macros/Python.cmake b/cmake/macros/Python.cmake index 32258d4a6dc..ce605e00b92 100644 --- a/cmake/macros/Python.cmake +++ b/cmake/macros/Python.cmake @@ -49,6 +49,7 @@ function(add_python_target target) add_library(${target} ${MODULE_TYPE} ${sources}) target_link_libraries(${target} PKG::PYTHON) + target_include_directories(${target} PRIVATE "${PROJECT_SOURCE_DIR}/dtool/src/interrogatedb") if(BUILD_SHARED_LIBS) set(_outdir "${PANDA_OUTPUT_DIR}/${slash_namespace}") diff --git a/direct/src/actor/Actor.py b/direct/src/actor/Actor.py index 263ac8803af..cc81d525cab 100644 --- a/direct/src/actor/Actor.py +++ b/direct/src/actor/Actor.py @@ -737,6 +737,13 @@ def getLOD(self, lodName): else: return None + def getPlayMode(self, animName=None, partName=None): + if self.__animControlDict: + controls = self.getAnimControls(animName, partName, onlyPlaying=False) + if controls: + return controls[0].getPlayMode() + return None + def hasLOD(self): """ Return 1 if the actor has LODs, 0 otherwise @@ -1762,7 +1769,7 @@ def getAnimControl(self, animName, partName=None, lodName=None, return None def getAnimControls(self, animName=None, partName=None, lodName=None, - allowAsyncBind = True): + allowAsyncBind = True, onlyPlaying = True): """getAnimControls(self, string, string=None, string=None) Returns a list of the AnimControls that represent the given @@ -1840,7 +1847,7 @@ def getAnimControls(self, animName=None, partName=None, lodName=None, # get all playing animations for thisPart, animDict in animDictItems: for anim in animDict.values(): - if anim.animControl and anim.animControl.isPlaying(): + if anim.animControl and (not onlyPlaying or anim.animControl.isPlaying()): controls.append(anim.animControl) else: # get the named animation(s) only. @@ -2660,3 +2667,4 @@ def renamePartBundles(self, partName, newBundleName): get_base_frame_rate = getBaseFrameRate remove_anim_control_dict = removeAnimControlDict load_anims_on_all_lods = loadAnimsOnAllLODs + get_play_mode = getPlayMode diff --git a/direct/src/dcparse/CMakeLists.txt b/direct/src/dcparse/CMakeLists.txt index e5cdee5b18b..b48d772c174 100644 --- a/direct/src/dcparse/CMakeLists.txt +++ b/direct/src/dcparse/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(p3dcparse dcparse.cxx) target_link_libraries(p3dcparse p3direct) install(TARGETS p3dcparse EXPORT Direct COMPONENT Direct DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/direct/src/dcparser/dcClass_ext.cxx b/direct/src/dcparser/dcClass_ext.cxx index cf09a97d348..65f55bf33ba 100644 --- a/direct/src/dcparser/dcClass_ext.cxx +++ b/direct/src/dcparser/dcClass_ext.cxx @@ -522,31 +522,35 @@ client_format_generate_CMU(PyObject *distobj, DOID_TYPE do_id, } // Also specify the optional fields. - int num_optional_fields = 0; if (PyObject_IsTrue(optional_fields)) { - num_optional_fields = PySequence_Size(optional_fields); - } - packer.raw_pack_uint16(num_optional_fields); - - for (int i = 0; i < num_optional_fields; i++) { - PyObject *py_field_name = PySequence_GetItem(optional_fields, i); - std::string field_name = PyUnicode_AsUTF8(py_field_name); - Py_XDECREF(py_field_name); - - DCField *field = _this->get_field_by_name(field_name); - if (field == nullptr) { - std::ostringstream strm; - strm << "No field named " << field_name << " in class " << _this->get_name() - << "\n"; - nassert_raise(strm.str()); - return Datagram(); - } - packer.raw_pack_uint16(field->get_number()); - packer.begin_pack(field); - if (!pack_required_field(packer, distobj, field)) { - return Datagram(); + optional_fields = PySequence_Tuple(optional_fields); + Py_ssize_t num_optional_fields = PyTuple_GET_SIZE(optional_fields); + packer.raw_pack_uint16(num_optional_fields); + + for (Py_ssize_t i = 0; i < num_optional_fields; i++) { + PyObject *py_field_name = PyTuple_GET_ITEM(optional_fields, i); + std::string field_name = PyUnicode_AsUTF8(py_field_name); + + DCField *field = _this->get_field_by_name(field_name); + if (field == nullptr) { + std::ostringstream strm; + strm << "No field named " << field_name << " in class " << _this->get_name() + << "\n"; + nassert_raise(strm.str()); + Py_DECREF(optional_fields); + return Datagram(); + } + packer.raw_pack_uint16(field->get_number()); + packer.begin_pack(field); + if (!pack_required_field(packer, distobj, field)) { + Py_DECREF(optional_fields); + return Datagram(); + } + packer.end_pack(); } - packer.end_pack(); + Py_DECREF(optional_fields); + } else { + packer.raw_pack_uint16(0); } return Datagram(packer.get_data(), packer.get_length()); @@ -602,13 +606,13 @@ ai_format_generate(PyObject *distobj, DOID_TYPE do_id, // Also specify the optional fields. if (has_optional_fields) { - int num_optional_fields = PySequence_Size(optional_fields); + optional_fields = PySequence_Tuple(optional_fields); + Py_ssize_t num_optional_fields = PyTuple_GET_SIZE(optional_fields); packer.raw_pack_uint16(num_optional_fields); - for (int i = 0; i < num_optional_fields; ++i) { - PyObject *py_field_name = PySequence_GetItem(optional_fields, i); + for (Py_ssize_t i = 0; i < num_optional_fields; ++i) { + PyObject *py_field_name = PyTuple_GET_ITEM(optional_fields, i); std::string field_name = PyUnicode_AsUTF8(py_field_name); - Py_XDECREF(py_field_name); DCField *field = _this->get_field_by_name(field_name); if (field == nullptr) { @@ -616,6 +620,7 @@ ai_format_generate(PyObject *distobj, DOID_TYPE do_id, strm << "No field named " << field_name << " in class " << _this->get_name() << "\n"; nassert_raise(strm.str()); + Py_DECREF(optional_fields); return Datagram(); } @@ -623,10 +628,13 @@ ai_format_generate(PyObject *distobj, DOID_TYPE do_id, packer.begin_pack(field); if (!pack_required_field(packer, distobj, field)) { + Py_DECREF(optional_fields); return Datagram(); } packer.end_pack(); } + + Py_DECREF(optional_fields); } return Datagram(packer.get_data(), packer.get_length()); diff --git a/direct/src/dcparser/dcField_ext.cxx b/direct/src/dcparser/dcField_ext.cxx index e2c1167811c..a10fffd4564 100644 --- a/direct/src/dcparser/dcField_ext.cxx +++ b/direct/src/dcparser/dcField_ext.cxx @@ -278,8 +278,9 @@ get_pystr(PyObject *value) { return result; } - if (value->ob_type != nullptr) { - PyObject *typestr = PyObject_Str((PyObject *)(value->ob_type)); + PyTypeObject *type = Py_TYPE(value); + if (type != nullptr) { + PyObject *typestr = PyObject_Str((PyObject *)type); if (typestr != nullptr) { std::string result = PyUnicode_AsUTF8(typestr); Py_DECREF(typestr); diff --git a/direct/src/dcparser/dcPacker_ext.cxx b/direct/src/dcparser/dcPacker_ext.cxx index 276a2dd7f92..9ffca60ba91 100644 --- a/direct/src/dcparser/dcPacker_ext.cxx +++ b/direct/src/dcparser/dcPacker_ext.cxx @@ -136,6 +136,7 @@ pack_object(PyObject *object) { // The supplied object is not an instance of the expected class object, // but it is a sequence. This is case (2). _this->push(); + Py_BEGIN_CRITICAL_SECTION(object); int size = PySequence_Size(object); for (int i = 0; i < size; ++i) { PyObject *element = PySequence_GetItem(object, i); @@ -146,6 +147,7 @@ pack_object(PyObject *object) { std::cerr << "Unable to extract item " << i << " from sequence.\n"; } } + Py_END_CRITICAL_SECTION(); _this->pop(); } else { // The supplied object is not a sequence, and we weren't expecting a diff --git a/direct/src/dcparser/dcParser.cxx.prebuilt b/direct/src/dcparser/dcParser.cxx.prebuilt index 6f4f167302c..aeab2dc34cf 100644 --- a/direct/src/dcparser/dcParser.cxx.prebuilt +++ b/direct/src/dcparser/dcParser.cxx.prebuilt @@ -179,7 +179,7 @@ dc_cleanup_parser() { # endif # endif -#include "dcParser.yxx.h" +#include "dcParser.h" /* Symbol kind. */ enum yysymbol_kind_t { diff --git a/direct/src/directbase/TestStart.py b/direct/src/directbase/TestStart.py index bdbab206e57..16ada8e9e7e 100755 --- a/direct/src/directbase/TestStart.py +++ b/direct/src/directbase/TestStart.py @@ -8,6 +8,9 @@ # Put an axis in the world: base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render) +assert base.camera is not None +assert base.camLens is not None + base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0) base.camLens.setFov(52.0) base.camLens.setNearFar(1.0, 10000.0) diff --git a/direct/src/directbase/ThreeUpStart.py b/direct/src/directbase/ThreeUpStart.py index 3ca50b34fe6..26f9bf74012 100644 --- a/direct/src/directbase/ThreeUpStart.py +++ b/direct/src/directbase/ThreeUpStart.py @@ -10,6 +10,9 @@ # Put an axis in the world: base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render) +assert base.camera is not None +assert base.camLens is not None + base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0) base.camLens.setFov(52.0) base.camLens.setNearFar(1.0, 10000.0) diff --git a/direct/src/dist/FreezeTool.py b/direct/src/dist/FreezeTool.py index 678f8c08885..37b697f8781 100644 --- a/direct/src/dist/FreezeTool.py +++ b/direct/src/dist/FreezeTool.py @@ -88,6 +88,7 @@ def pytest_imports(): 'numpy.core._dtype_ctypes', 'numpy.core._methods', ], + 'panda3d.core': ['enum'], 'pandas.compat': ['lzma', 'cmath'], 'pandas._libs.tslibs.conversion': ['pandas._libs.tslibs.base'], 'plyer': ['plyer.platforms'], @@ -925,7 +926,22 @@ def __init__(self, previous = None, debugLevel = 0, if sys.version_info < (3, 8): abi_flags += 'm' - if 'linux' in self.platform: + if 'android' in self.platform: + arch = self.platform.split('_', 1)[1] + if arch in ('arm64', 'aarch64'): + suffixes.append(('.cpython-{0}{1}-aarch64-linux-android.so'.format(abi_version, abi_flags), 'rb', 3)) + elif arch in ('arm', 'armv7l'): + suffixes.append(('.cpython-{0}{1}-arm-linux-androideabi.so'.format(abi_version, abi_flags), 'rb', 3)) + elif arch in ('x86_64', 'amd64'): + suffixes.append(('.cpython-{0}{1}-x86_64-linux-android.so'.format(abi_version, abi_flags), 'rb', 3)) + elif arch in ('i386', 'i686'): + suffixes.append(('.cpython-{0}{1}-i686-linux-android.so'.format(abi_version, abi_flags), 'rb', 3)) + + suffixes += [ + ('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3), + ('.so', 'rb', 3), + ] + elif 'linux' in self.platform: suffixes += [ ('.cpython-{0}{1}-x86_64-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3), ('.cpython-{0}{1}-i686-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3), @@ -1150,6 +1166,9 @@ def done(self, addStartupModules = False): self.modules['_frozen_importlib'] = self.ModuleDef('importlib._bootstrap', implicit = True) self.modules['_frozen_importlib_external'] = self.ModuleDef('importlib._bootstrap_external', implicit = True) + if self.platform.startswith('android'): + self.modules['_android_support'] = self.ModuleDef('_android_support', implicit = True) + for moduleName in startupModules: if moduleName not in self.modules: self.addModule(moduleName, implicit = True) diff --git a/direct/src/dist/_android.py b/direct/src/dist/_android.py index ac6a8c85b96..bebb7bf9df2 100644 --- a/direct/src/dist/_android.py +++ b/direct/src/dist/_android.py @@ -50,7 +50,7 @@ def compile(attrib, manifest): bitmask = 0 flags = attrib.value.split('|') for flag in flags: - bitmask = values[flag] + bitmask |= values[flag] attrib.compiled_item.prim.int_hexadecimal_value = bitmask return compile @@ -168,10 +168,11 @@ def compile(attrib, manifest): 'allowSingleTap': bool_resource(0x1010259), 'allowTaskReparenting': bool_resource(0x1010204), 'alwaysRetainTaskState': bool_resource(0x1010203), + 'appCategory': enum_resource(0x01010545, "game", "audio", "video", "image", "social", "news", "maps", "productivity", "accessibility"), 'clearTaskOnLaunch': bool_resource(0x1010015), + 'configChanges': flag_resource(0x0101001f, mcc=0x0001, mnc=0x0002, locale=0x0004, touchscreen=0x0008, keyboard=0x0010, keyboardHidden=0x0020, navigation=0x0040, orientation=0x0080, screenLayout=0x0100, uiMode=0x0200, screenSize=0x0400, smallestScreenSize=0x0800, layoutDirection=0x2000, colorMode=0x4000, grammaticalGender=0x8000, fontScale=0x40000000, fontWeightAdjustment=0x10000000), 'debuggable': bool_resource(0x0101000f), 'documentLaunchMode': enum_resource(0x1010445, "none", "intoExisting", "always", "never"), - 'configChanges': flag_resource(0x0101001f, mcc=0x0001, mnc=0x0002, locale=0x0004, touchscreen=0x0008, keyboard=0x0010, keyboardHidden=0x0020, navigation=0x0040, orientation=0x0080, screenLayout=0x0100, uiMode=0x0200, screenSize=0x0400, smallestScreenSize=0x0800, layoutDirection=0x2000, fontScale=0x40000000), 'enabled': bool_resource(0x101000e), 'excludeFromRecents': bool_resource(0x1010017), 'exported': bool_resource(0x1010010), @@ -179,6 +180,7 @@ def compile(attrib, manifest): 'finishOnTaskLaunch': bool_resource(0x1010014), 'fullBackupContent': bool_resource(0x10104eb), 'glEsVersion': int_resource(0x1010281), + 'hardwareAccelerated': bool_resource(0x10102d3), 'hasCode': bool_resource(0x101000c), 'host': str_resource(0x1010028), 'icon': ref_resource(0x1010002), @@ -194,8 +196,9 @@ def compile(attrib, manifest): 'name': str_resource(0x1010003), 'noHistory': bool_resource(0x101022d), 'pathPattern': str_resource(0x101002c), - 'resizeableActivity': bool_resource(0x10104f6), + 'preferMinimalPostProcessing': bool_resource(0x101060c), 'required': bool_resource(0x101028e), + 'resizeableActivity': bool_resource(0x10104f6), 'scheme': str_resource(0x1010027), 'screenOrientation': enum_resource(0x101001e, 'landscape', 'portrait', 'user', 'behind', 'sensor', 'nosensor', 'sensorLandscape', 'sensorPortrait', 'reverseLandscape', 'reversePortrait', 'fullSensor', 'userLandscape', 'userPortrait', 'fullUser', 'locked'), 'stateNotNeeded': bool_resource(0x1010016), diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index 505e57697b2..cfddcd89aff 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -75,6 +75,7 @@ def _model_to_bam(_build_cmd, srcpath, dstpath): src_fn = p3d.Filename.from_os_specific(srcpath) dst_fn = p3d.Filename.from_os_specific(dstpath) + dst_fn.set_binary() _register_python_loaders() @@ -85,8 +86,30 @@ def _model_to_bam(_build_cmd, srcpath, dstpath): if not node: raise IOError('Failed to load model: %s' % (srcpath)) - if not p3d.NodePath(node).write_bam_file(dst_fn): - raise IOError('Failed to write .bam file: %s' % (dstpath)) + stream = p3d.OFileStream() + if not dst_fn.open_write(stream): + raise IOError('Failed to open .bam file for writing: %s' % (dstpath)) + + # We pass it the source filename here so that texture files are made + # relative to the original pathname and don't point from the destination + # back into the source directory. + dout = p3d.DatagramOutputFile() + if not dout.open(stream, src_fn) or not dout.write_header("pbj\0\n\r"): + raise IOError('Failed to write to .bam file: %s' % (dstpath)) + + writer = p3d.BamWriter(dout) + writer.root_node = node + writer.init() + if _build_cmd.bam_embed_textures: + writer.set_file_texture_mode(p3d.BamEnums.BTM_rawdata) + else: + writer.set_file_texture_mode(p3d.BamEnums.BTM_relative) + writer.write_object(node) + writer.flush() + writer = None + dout.close() + dout = None + stream.close() macosx_binary_magics = ( @@ -165,11 +188,26 @@ def get_data(path): """ SITE_PY_ANDROID = """ +# Define this first, before we import anything that might import an extension +# module. import sys, os +from importlib import _bootstrap, _bootstrap_external + +class AndroidExtensionFinder: + @classmethod + def find_spec(cls, fullname, path=None, target=None): + soname = 'libpy.' + fullname + '.so' + path = os.path.join(sys.platlibdir, soname) + + if os.path.exists(path): + loader = _bootstrap_external.ExtensionFileLoader(fullname, path) + return _bootstrap.ModuleSpec(fullname, loader, origin=path) + + +sys.meta_path.append(AndroidExtensionFinder) + + from _frozen_importlib import _imp, FrozenImporter -from importlib import _bootstrap_external -from importlib.abc import Loader, MetaPathFinder -from importlib.machinery import ModuleSpec from io import RawIOBase, TextIOWrapper from android_log import write as android_log_write @@ -219,8 +257,9 @@ def readable(self): def writable(self): return True -sys.stdout = AndroidLogStream(2, 'Python') -sys.stderr = AndroidLogStream(3, 'Python') +if sys.version_info < (3, 13): + sys.stdout = AndroidLogStream(4, 'python.stdout') + sys.stderr = AndroidLogStream(5, 'python.stderr') # Alter FrozenImporter to give a __file__ property to frozen modules. @@ -239,20 +278,6 @@ def get_data(path): FrozenImporter.find_spec = find_spec FrozenImporter.get_data = get_data - - -class AndroidExtensionFinder(MetaPathFinder): - @classmethod - def find_spec(cls, fullname, path=None, target=None): - soname = 'libpy.' + fullname + '.so' - path = os.path.join(os.path.dirname(sys.executable), soname) - - if os.path.exists(path): - loader = _bootstrap_external.ExtensionFileLoader(fullname, path) - return ModuleSpec(fullname, loader, origin=path) - - -sys.meta_path.append(AndroidExtensionFinder) """ @@ -271,6 +296,7 @@ def initialize_options(self): self.application_id = None self.android_abis = None self.android_debuggable = False + self.android_app_category = None self.android_version_code = 1 self.android_min_sdk_version = 21 self.android_max_sdk_version = None @@ -289,6 +315,11 @@ def initialize_options(self): 'macosx_10_9_x86_64', 'win_amd64', ] + + if sys.version_info >= (3, 13): + # This version of Python is only available for 10.13+. + self.platforms[1] = 'macosx_10_13_x86_64' + self.plugins = [] self.embed_prc_data = True self.extra_prc_files = [] @@ -307,6 +338,7 @@ def initialize_options(self): ] self.file_handlers = {} self.bam_model_extensions = ['.egg', '.gltf', '.glb'] + self.bam_embed_textures = False self.exclude_dependencies = [ # Windows 'kernel32.dll', 'user32.dll', 'wsock32.dll', 'ws2_32.dll', @@ -321,7 +353,8 @@ def initialize_options(self): # manylinux1/linux 'libdl.so.*', 'libstdc++.so.*', 'libm.so.*', 'libgcc_s.so.*', - 'libpthread.so.*', 'libc.so.*', 'ld-linux-x86-64.so.*', + 'libpthread.so.*', 'libc.so.*', + 'ld-linux-x86-64.so.*', 'ld-linux-aarch64.so.*', 'libgl.so.*', 'libx11.so.*', 'libncursesw.so.*', 'libz.so.*', 'librt.so.*', 'libutil.so.*', 'libnsl.so.1', 'libXext.so.6', 'libXrender.so.1', 'libICE.so.6', 'libSM.so.6', 'libEGL.so.1', @@ -486,6 +519,18 @@ def finalize_options(self): tmp.update(self.package_data_dirs) self.package_data_dirs = tmp + if 'android' in self.platforms: + assert self.application_id, \ + 'Must have a valid application_id when targeting Android!' + + parts = self.application_id.split('.') + assert len(parts) >= 2, \ + 'application_id must contain at least one \'.\' separator!' + + for part in parts: + assert part.isidentifier(), \ + 'Each part of application_id must be a valid identifier!' + # Default to all supported ABIs (for the given Android version). if self.android_max_sdk_version and self.android_max_sdk_version < 21: assert self.android_max_sdk_version >= 19, \ @@ -646,14 +691,20 @@ def download_wheels(self, platform): subprocess.check_call([sys.executable, '-m', 'pip'] + pip_args) except: # Display a more helpful message for these common issues. - if platform.startswith('manylinux2010_') and sys.version_info >= (3, 11): + if platform.startswith('macosx_10_9_') and sys.version_info >= (3, 13): + new_platform = platform.replace('macosx_10_9_', 'macosx_10_13_') + self.announce('This error likely occurs because {} is not a supported target as of Python 3.13.\nChange the target platform to {} instead.'.format(platform, new_platform), distutils.log.ERROR) + elif platform.startswith('manylinux2010_') and sys.version_info >= (3, 11): new_platform = platform.replace('manylinux2010_', 'manylinux2014_') self.announce('This error likely occurs because {} is not a supported target as of Python 3.11.\nChange the target platform to {} instead.'.format(platform, new_platform), distutils.log.ERROR) elif platform.startswith('manylinux1_') and sys.version_info >= (3, 10): new_platform = platform.replace('manylinux1_', 'manylinux2014_') self.announce('This error likely occurs because {} is not a supported target as of Python 3.10.\nChange the target platform to {} instead.'.format(platform, new_platform), distutils.log.ERROR) elif platform.startswith('macosx_10_6_') and sys.version_info >= (3, 8): - new_platform = platform.replace('macosx_10_6_', 'macosx_10_9_') + if sys.version_info >= (3, 13): + new_platform = platform.replace('macosx_10_6_', 'macosx_10_13_') + else: + new_platform = platform.replace('macosx_10_6_', 'macosx_10_9_') self.announce('This error likely occurs because {} is not a supported target as of Python 3.8.\nChange the target platform to {} instead.'.format(platform, new_platform), distutils.log.ERROR) raise @@ -746,10 +797,29 @@ def generate_android_manifest(self, path): version = self.distribution.get_version() classifiers = self.distribution.get_classifiers() - is_game = False - for classifier in classifiers: - if classifier == 'Topic :: Games/Entertainment' or classifier.startswith('Topic :: Games/Entertainment ::'): - is_game = True + # If we have no app category, determine it based on the classifiers. + category = self.android_app_category + if not category: + for classifier in classifiers: + classifier = tuple(classifier.split(' :: ')) + if len(classifier) < 2 or classifier[0] != 'Topic': + continue + + if classifier[:2] == ('Topic', 'Games/Entertainment'): + category = 'game' + break + elif classifier[:3] == ('Topic', 'Multimedia', 'Audio'): + category = 'audio' + elif classifier[:4] == ('Topic', 'Multimedia', 'Graphics', 'Editors'): + category = 'image' + elif classifier[:2] == ('Topic', 'Communications', 'Usenet News'): + category = 'news' + elif classifier[:2] == ('Topic', 'Office/Business'): + category = 'productivity' + elif classifier[:3] == ('Topic', 'Communications', 'Chat'): + category = 'social' + elif classifier[:3] == ('Topic', 'Multimedia', 'Video'): + category = 'video' manifest = ET.Element('manifest') manifest.set('xmlns:android', 'http://schemas.android.com/apk/res/android') @@ -780,9 +850,13 @@ def generate_android_manifest(self, path): application = ET.SubElement(manifest, 'application') application.set('android:label', name) - application.set('android:isGame', ('false', 'true')[is_game]) + if category == 'game': + application.set('android:isGame', 'true') + if category: + application.set('android:appCategory', category) application.set('android:debuggable', ('false', 'true')[self.android_debuggable]) application.set('android:extractNativeLibs', 'true') + application.set('android:hardwareAccelerated', 'true') app_icon = self.icon_objects.get('*', self.icon_objects.get(self.macos_main_app)) if app_icon: @@ -792,9 +866,11 @@ def generate_android_manifest(self, path): activity = ET.SubElement(application, 'activity') activity.set('android:name', 'org.panda3d.android.PythonActivity') activity.set('android:label', appname) - activity.set('android:theme', '@android:style/Theme.NoTitleBar') - activity.set('android:configChanges', 'orientation|keyboardHidden') + activity.set('android:theme', '@android:style/Theme.NoTitleBar.Fullscreen') + activity.set('android:alwaysRetainTaskState', 'true') + activity.set('android:configChanges', 'layoutDirection|locale|grammaticalGender|fontScale|fontWeightAdjustment|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation') activity.set('android:launchMode', 'singleInstance') + activity.set('android:preferMinimalPostProcessing', 'true') act_icon = self.icon_objects.get(appname) if act_icon and act_icon is not app_icon: diff --git a/direct/src/distributed/ConnectionRepository.py b/direct/src/distributed/ConnectionRepository.py index 62c2d5da466..a29c61cafa8 100644 --- a/direct/src/distributed/ConnectionRepository.py +++ b/direct/src/distributed/ConnectionRepository.py @@ -174,35 +174,6 @@ def _adjustGcThreshold(self, task): return retVal def generateGlobalObject(self, doId, dcname, values=None): - def applyFieldValues(distObj, dclass, values): - for i in range(dclass.getNumInheritedFields()): - field = dclass.getInheritedField(i) - if field.asMolecularField() is None: - value = values.get(field.getName(), None) - if value is None and field.isRequired(): - # Gee, this could be better. What would really be - # nicer is to get value from field.getDefaultValue - # or similar, but that returns a binary string, not - # a python tuple, like the following does. If you - # want to change something better, please go ahead. - packer = DCPacker() - packer.beginPack(field) - packer.packDefaultValue() - packer.endPack() - - unpacker = DCPacker() - unpacker.setUnpackData(packer.getString()) - unpacker.beginUnpack(field) - value = unpacker.unpackObject() - unpacker.endUnpack() - if value is not None: - function = getattr(distObj, field.getName()) - if function is not None: - function(*value) - else: - self.notify.error("\n\n\nNot able to find %s.%s"%( - distObj.__class__.__name__, field.getName())) - # Look up the dclass dclass = self.dclassesByName.get(dcname+self.dcSuffix) if dclass is None: @@ -229,7 +200,37 @@ def applyFieldValues(distObj, dclass, values): distObj.generateInit() # Only called when constructed distObj.generate() if values is not None: - applyFieldValues(distObj, dclass, values) + for i in range(dclass.getNumInheritedFields()): + field = dclass.getInheritedField(i) + if field.asMolecularField() is None: + value = values.get(field.getName(), None) + if value is None and field.isRequired(): + # Gee, this could be better. What would really be + # nicer is to get value from field.getDefaultValue + # or similar, but that returns a binary string, not + # a python tuple, like the following does. If you + # want to change something better, please go ahead. + packer = DCPacker() + packer.beginPack(field) + packer.packDefaultValue() + packer.endPack() + + unpacker = DCPacker() + unpacker.setUnpackData(packer.getString()) + unpacker.beginUnpack(field) + value = unpacker.unpackObject() + unpacker.endUnpack() + if value is not None: + function = getattr(distObj, field.getName()) + if function is not None: + function(*value) + else: + self.notify.error( + "\n\n\nNot able to find %s.%s" % ( + distObj.__class__.__name__, + field.getName() + ) + ) distObj.announceGenerate() distObj.parentId = 0 distObj.zoneId = 0 diff --git a/direct/src/distributed/DistributedObjectAI.py b/direct/src/distributed/DistributedObjectAI.py index b67ee57d1ee..164d57eb2c8 100644 --- a/direct/src/distributed/DistributedObjectAI.py +++ b/direct/src/distributed/DistributedObjectAI.py @@ -299,7 +299,7 @@ def getZoneData(self): # setLocation destroys self._zoneData if we move away to # a different zone if self._zoneData is None: - from otp.ai.AIZoneData import AIZoneData # type: ignore[import] + from otp.ai.AIZoneData import AIZoneData # type: ignore[import-not-found] self._zoneData = AIZoneData(self.air, self.parentId, self.zoneId) return self._zoneData @@ -489,7 +489,7 @@ def beginBarrier(self, name, avIds, timeout, callback): # simultaneously on different lists of avatars, although they # should have different names. - from otp.ai import Barrier # type: ignore[import] + from otp.ai import Barrier # type: ignore[import-not-found] context = self.__nextBarrierContext # We assume the context number is passed as a uint16. self.__nextBarrierContext = (self.__nextBarrierContext + 1) & 0xffff diff --git a/direct/src/distributed/DistributedObjectUD.py b/direct/src/distributed/DistributedObjectUD.py index 341ce41616d..a49110e472e 100755 --- a/direct/src/distributed/DistributedObjectUD.py +++ b/direct/src/distributed/DistributedObjectUD.py @@ -424,7 +424,7 @@ def beginBarrier(self, name, avIds, timeout, callback): # simultaneously on different lists of avatars, although they # should have different names. - from otp.ai import Barrier # type: ignore[import] + from otp.ai import Barrier # type: ignore[import-not-found] context = self.__nextBarrierContext # We assume the context number is passed as a uint16. self.__nextBarrierContext = (self.__nextBarrierContext + 1) & 0xffff diff --git a/direct/src/distributed/cConnectionRepository.cxx b/direct/src/distributed/cConnectionRepository.cxx index 0eb40547efd..8dd11eadbe7 100644 --- a/direct/src/distributed/cConnectionRepository.cxx +++ b/direct/src/distributed/cConnectionRepository.cxx @@ -688,11 +688,12 @@ handle_update_field() { nassertr(doId2do != nullptr, false); PyObject *doId = PyLong_FromUnsignedLong(do_id); - PyObject *distobj = PyDict_GetItem(doId2do, doId); + PyObject *distobj; + int result = PyDict_GetItemRef(doId2do, doId, &distobj); Py_DECREF(doId); Py_DECREF(doId2do); - if (distobj != nullptr) { + if (result > 0) { PyObject *dclass_obj = PyObject_GetAttrString(distobj, "dclass"); nassertr(dclass_obj != nullptr, false); @@ -711,9 +712,11 @@ handle_update_field() { nassertr(neverDisable != nullptr, false); unsigned int cNeverDisable = PyLong_AsLong(neverDisable); + Py_DECREF(neverDisable); if (!cNeverDisable) { // in quiet zone and distobj is disable-able drop update on the // floor + Py_DECREF(distobj); #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); #endif @@ -721,13 +724,8 @@ handle_update_field() { } } - // It's a good idea to ensure the reference count to distobj is raised - // while we call the update method--otherwise, the update method might - // get into trouble if it tried to delete the object from the doId2do - // map. - PyObject *distobj_ref = Py_NewRef(distobj); - invoke_extension(dclass).receive_update(distobj_ref, _di); - Py_DECREF(distobj_ref); + invoke_extension(dclass).receive_update(distobj, _di); + Py_DECREF(distobj); if (PyErr_Occurred()) { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) @@ -777,10 +775,11 @@ handle_update_field_owner() { PyObject *doId = PyLong_FromUnsignedLong(do_id); // pass the update to the owner view first - PyObject *distobjOV = PyDict_GetItem(doId2ownerView, doId); + PyObject *distobjOV; + int result = PyDict_GetItemRef(doId2ownerView, doId, &distobjOV); Py_DECREF(doId2ownerView); - if (distobjOV != nullptr) { + if (result > 0) { PyObject *dclass_obj = PyObject_GetAttrString(distobjOV, "dclass"); nassertr(dclass_obj != nullptr, false); @@ -798,32 +797,29 @@ handle_update_field_owner() { int field_id = packer.raw_unpack_uint16(); DCField *field = dclass->get_field_by_index(field_id); if (field->is_ownrecv()) { - // It's a good idea to ensure the reference count to distobjOV is - // raised while we call the update method--otherwise, the update - // method might get into trouble if it tried to delete the object from - // the doId2do map. - PyObject *distobjOV_ref = Py_NewRef(distobjOV); // make a copy of the datagram iterator so that we can use the main // iterator for the non-owner update DatagramIterator _odi(_di); - invoke_extension(dclass).receive_update(distobjOV_ref, _odi); - Py_DECREF(distobjOV_ref); + invoke_extension(dclass).receive_update(distobjOV, _odi); if (PyErr_Occurred()) { + Py_DECREF(distobjOV); #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); #endif return false; } } + Py_DECREF(distobjOV); } // now pass the update to the visible view - PyObject *distobj = PyDict_GetItem(doId2do, doId); + PyObject *distobj; + result = PyDict_GetItemRef(doId2do, doId, &distobj); Py_DECREF(doId); Py_DECREF(doId2do); - if (distobj != nullptr) { + if (result > 0) { PyObject *dclass_obj = PyObject_GetAttrString(distobj, "dclass"); nassertr(dclass_obj != nullptr, false); @@ -842,21 +838,17 @@ handle_update_field_owner() { //int field_id = packer.raw_unpack_uint16(); //DCField *field = dclass->get_field_by_index(field_id); if (true) {//field->is_broadcast()) { - // It's a good idea to ensure the reference count to distobj is raised - // while we call the update method--otherwise, the update method might - // get into trouble if it tried to delete the object from the doId2do - // map. - PyObject *distobj_ref = Py_NewRef(distobj); - invoke_extension(dclass).receive_update(distobj_ref, _di); - Py_DECREF(distobj_ref); + invoke_extension(dclass).receive_update(distobj, _di); if (PyErr_Occurred()) { + Py_DECREF(distobj); #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); #endif return false; } } + Py_DECREF(distobj); } } @@ -956,12 +948,14 @@ describe_message(std::ostream &out, const string &prefix, nassertv(doId2do != nullptr); PyObject *doId = PyLong_FromUnsignedLong(do_id); - PyObject *distobj = PyDict_GetItem(doId2do, doId); + PyObject *distobj; + int result = PyDict_GetItemRef(doId2do, doId, &distobj); Py_DECREF(doId); Py_DECREF(doId2do); - if (distobj != nullptr) { + if (result > 0) { PyObject *dclass_obj = PyObject_GetAttrString(distobj, "dclass"); + Py_DECREF(distobj); nassertv(dclass_obj != nullptr); PyObject *dclass_this = PyObject_GetAttrString(dclass_obj, "this"); diff --git a/direct/src/filter/CommonFilters.py b/direct/src/filter/CommonFilters.py index 85d0a18f16c..942b2748f68 100644 --- a/direct/src/filter/CommonFilters.py +++ b/direct/src/filter/CommonFilters.py @@ -100,6 +100,11 @@ """ +class ToneMap: + ACES = object() + PBR_NEUTRAL = object() + + class FilterConfig: pass @@ -279,16 +284,19 @@ def reconfigure(self, fullrebuild, changed): text = "//Cg\n" if "HighDynamicRange" in configuration: - text += "static const float3x3 aces_input_mat = {\n" - text += " {0.59719, 0.35458, 0.04823},\n" - text += " {0.07600, 0.90834, 0.01566},\n" - text += " {0.02840, 0.13383, 0.83777},\n" - text += "};\n" - text += "static const float3x3 aces_output_mat = {\n" - text += " { 1.60475, -0.53108, -0.07367},\n" - text += " {-0.10208, 1.10813, -0.00605},\n" - text += " {-0.00327, -0.07276, 1.07602},\n" - text += "};\n" + tonemap = configuration["HighDynamicRange"] + if tonemap is ToneMap.ACES: + text += "static const float3x3 aces_input_mat = {\n" + text += " {0.59719, 0.35458, 0.04823},\n" + text += " {0.07600, 0.90834, 0.01566},\n" + text += " {0.02840, 0.13383, 0.83777},\n" + text += "};\n" + text += "static const float3x3 aces_output_mat = {\n" + text += " { 1.60475, -0.53108, -0.07367},\n" + text += " {-0.10208, 1.10813, -0.00605},\n" + text += " {-0.00327, -0.07276, 1.07602},\n" + text += "};\n" + text += "void vshader(float4 vtx_position : POSITION,\n" text += " out float4 l_position : POSITION,\n" @@ -381,10 +389,30 @@ def reconfigure(self, fullrebuild, changed): if "ExposureAdjust" in configuration: text += " o_color.rgb *= k_exposure;\n" - # With thanks to Stephen Hill! if "HighDynamicRange" in configuration: - text += " float3 aces_color = mul(aces_input_mat, o_color.rgb);\n" - text += " o_color.rgb = saturate(mul(aces_output_mat, (aces_color * (aces_color + 0.0245786f) - 0.000090537f) / (aces_color * (0.983729f * aces_color + 0.4329510f) + 0.238081f)));\n" + tonemap = configuration["HighDynamicRange"] + if tonemap is ToneMap.ACES: + # With thanks to Stephen Hill! + text += " float3 aces_color = mul(aces_input_mat, o_color.rgb);\n" + text += " o_color.rgb = saturate(mul(aces_output_mat, (aces_color * (aces_color + 0.0245786f) - 0.000090537f) / (aces_color * (0.983729f * aces_color + 0.4329510f) + 0.238081f)));\n" + elif tonemap is ToneMap.PBR_NEUTRAL: + text += " const float start_compression = 0.8 - 0.04;\n" + text += " const float desaturation = 0.15;\n" + + text += " float x = min(o_color.r, min(o_color.g, o_color.b));\n" + text += " float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n" + text += " o_color.rgb -= offset;\n" + + text += " float peak = max(o_color.r, max(o_color.g, o_color.b));\n" + + text += " if (peak >= start_compression) {\n" + text += " const float d = 1.0 - start_compression;\n" + text += " float new_peak = 1.0 - d * d / (peak + d - start_compression);\n" + text += " o_color.rgb *= new_peak / peak;\n" + text += " float g = 1.0 - 1.0 / (desaturation * (peak - new_peak) + 1.0);\n" + + text += " o_color.rgb = lerp(o_color.rgb, new_peak * float3(1, 1, 1), g);\n" + text += "}\n" if "GammaAdjust" in configuration: gamma = configuration["GammaAdjust"] @@ -668,10 +696,10 @@ def delSrgbEncode(self): return self.reconfigure(old_enable, "SrgbEncode") return True - def setHighDynamicRange(self): + def setHighDynamicRange(self, tonemap=ToneMap.ACES): """ Enables HDR rendering by using a floating-point framebuffer, disabling color clamping on the main scene, and applying a tone map - operator (ACES). + operator (ACES or Khronos PBR Neutral). It may also be necessary to use setExposureAdjust to perform exposure compensation on the scene, depending on the lighting intensity. @@ -679,8 +707,11 @@ def setHighDynamicRange(self): .. versionadded:: 1.10.7 """ - fullrebuild = (("HighDynamicRange" in self.configuration) is False) - self.configuration["HighDynamicRange"] = 1 + fullrebuild = "HighDynamicRange" not in self.configuration or \ + self.configuration["HighDynamicRange"] is not tonemap + if tonemap is not ToneMap.ACES and tonemap is not ToneMap.PBR_NEUTRAL: + raise ValueError("Invalid value for tonemap") + self.configuration["HighDynamicRange"] = tonemap return self.reconfigure(fullrebuild, "HighDynamicRange") def delHighDynamicRange(self): diff --git a/direct/src/fsm/FSM.py b/direct/src/fsm/FSM.py index 06efc4b1a55..e7a44986912 100644 --- a/direct/src/fsm/FSM.py +++ b/direct/src/fsm/FSM.py @@ -485,9 +485,8 @@ def requestNext(self, *args): new_index = (cur_index + 1) % len(self.stateArray) return self.request(self.stateArray[new_index], args) else: - assert self.notifier.debug( + assert self.notify.debug( "stateArray empty. Can't switch to next.") - finally: self.fsmLock.release() @@ -503,7 +502,7 @@ def requestPrev(self, *args): new_index = (cur_index - 1) % len(self.stateArray) return self.request(self.stateArray[new_index], args) else: - assert self.notifier.debug( + assert self.notify.debug( "stateArray empty. Can't switch to next.") finally: self.fsmLock.release() diff --git a/direct/src/interval/cMetaInterval.cxx b/direct/src/interval/cMetaInterval.cxx index 3627a99bc00..a203167557e 100644 --- a/direct/src/interval/cMetaInterval.cxx +++ b/direct/src/interval/cMetaInterval.cxx @@ -679,7 +679,7 @@ write(std::ostream &out, int indent_level) const { int total_digits = num_decimals + 4; static const int max_digits = 32; // totally arbitrary nassertv(total_digits <= max_digits); - char format_str[16]; + char format_str[26]; sprintf(format_str, "%%%d.%df", total_digits, num_decimals); indent(out, indent_level) << get_name() << ":\n"; @@ -708,7 +708,7 @@ timeline(std::ostream &out) const { int total_digits = num_decimals + 4; static const int max_digits = 32; // totally arbitrary nassertv(total_digits <= max_digits); - char format_str[16]; + char format_str[26]; sprintf(format_str, "%%%d.%df", total_digits, num_decimals); int extra_indent_level = 0; diff --git a/direct/src/showbase/DistancePhasedNode.py b/direct/src/showbase/DistancePhasedNode.py index fc4c5a471b1..5fc12769e00 100755 --- a/direct/src/showbase/DistancePhasedNode.py +++ b/direct/src/showbase/DistancePhasedNode.py @@ -87,7 +87,8 @@ def __deallocateId(id): """ Reuse abandoned ids. """ - DistancePhasedNode.__InstanceDeque.append(id) + if DistancePhasedNode is not None: + DistancePhasedNode.__InstanceDeque.append(id) def __init__(self, name, phaseParamMap = {}, autoCleanup = True, diff --git a/direct/src/showbase/Loader.py b/direct/src/showbase/Loader.py index 141c71a3684..7febb9012dc 100644 --- a/direct/src/showbase/Loader.py +++ b/direct/src/showbase/Loader.py @@ -126,7 +126,7 @@ async def __aiter__(self): yield await req # special methods - def __init__(self, base): + def __init__(self, base=None): self.base = base self.loader = PandaLoader.getGlobalPtr() @@ -134,15 +134,15 @@ def __init__(self, base): self.hook = "async_loader_%s" % (Loader.loaderIndex) Loader.loaderIndex += 1 - self.accept(self.hook, self.__gotAsyncObject) - - self._loadPythonFileTypes() def destroy(self): self.ignore(self.hook) self.loader.stopThreads() del self.base - del self.loader + + def _init_base(self, base): + self.base = base + self.accept(self.hook, self.__gotAsyncObject) @classmethod def _loadPythonFileTypes(cls): @@ -229,6 +229,10 @@ def loadModel(self, modelPath, loaderOptions = None, noCache = None, """ assert Loader.notify.debug("Loading model: %s" % (modelPath,)) + + if not self._loadedPythonFileTypes: + self._loadPythonFileTypes() + if loaderOptions is None: loaderOptions = LoaderOptions() else: @@ -416,6 +420,9 @@ def saveModel(self, modelPath, node, loaderOptions = None, a callback is used, the model is saved asynchronously, and the true/false status is passed to the callback function. """ + if not self._loadedPythonFileTypes: + self._loadPythonFileTypes() + if loaderOptions is None: loaderOptions = LoaderOptions() else: diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 75436a4d647..26370c65a11 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -32,6 +32,8 @@ """ +from __future__ import annotations + __all__ = ['ShowBase', 'WindowControls'] # This module redefines the builtin import function with one @@ -71,9 +73,11 @@ GraphicsPipe, GraphicsPipeSelection, GraphicsWindow, + InputDevice, InputDeviceManager, InputDeviceNode, KeyboardButton, + Lens, LensNode, Mat4, ModelNode, @@ -118,9 +122,11 @@ from direct.extensions_native import NodePath_extensions # pylint: disable=unused-import # This needs to be available early for DirectGUI imports +from typing import Any +builtins: Any # Tell mypy not to worry about us setting attributes on builtins import sys import builtins -builtins.config = DConfig # type: ignore[attr-defined] +builtins.config = DConfig from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify from direct.directnotify.Notifier import Notifier @@ -141,7 +147,7 @@ from direct.showbase import ExceptionVarDump from . import DirectObject from . import SfxPlayer -from typing import ClassVar, Optional +from typing import Callable, ClassVar, Literal, NoReturn if __debug__: from direct.showbase import GarbageReport from direct.directutil import DeltaProfiler @@ -150,9 +156,10 @@ @atexit.register -def exitfunc(): - if getattr(builtins, 'base', None) is not None: - builtins.base.destroy() +def exitfunc() -> None: + base = getattr(builtins, 'base', None) + if base is not None: + base.destroy() # Now ShowBase is a DirectObject. We need this so ShowBase can hang # hooks on messages, particularly on window-event. This doesn't @@ -170,7 +177,9 @@ class ShowBase(DirectObject.DirectObject): aspect2d: NodePath pixel2d: NodePath - def __init__(self, fStartDirect=True, windowType=None): + cluster: Any | None + + def __init__(self, fStartDirect: bool = True, windowType: str | None = None) -> None: """Opens a window, sets up a 3-D and several 2-D scene graphs, and everything else needed to render the scene graph to the window. @@ -233,10 +242,10 @@ def __init__(self, fStartDirect=True, windowType=None): self.wantRender2dp = ConfigVariableBool('want-render2dp', True).value self.screenshotExtension = ConfigVariableString('screenshot-extension', 'jpg').value - self.musicManager = None - self.musicManagerIsValid = None - self.sfxManagerList = [] - self.sfxManagerIsValidList = [] + self.musicManager: AudioManager | None = None + self.musicManagerIsValid: bool | None = None + self.sfxManagerList: list[AudioManager] = [] + self.sfxManagerIsValidList: list[bool] = [] self.wantStats = ConfigVariableBool('want-pstats', False).value self.wantTk = False @@ -245,12 +254,12 @@ def __init__(self, fStartDirect=True, windowType=None): #: Fill this in with a function to invoke when the user "exits" #: the program by closing the main window. - self.exitFunc = None + self.exitFunc: Callable[[], object] | None = None #: Add final-exit callbacks to this list. These will be called #: when sys.exit() is called, after Panda has unloaded, and #: just before Python is about to shut down. - self.finalExitCallbacks = [] + self.finalExitCallbacks: list[Callable[[], object]] = [] # Set up the TaskManager to reset the PStats clock back # whenever we resume from a pause. This callback function is @@ -268,7 +277,7 @@ def __init__(self, fStartDirect=True, windowType=None): self.__configAspectRatio = ConfigVariableDouble('aspect-ratio', 0).value # This variable is used to see if the aspect ratio has changed when # we get a window-event. - self.__oldAspectRatio = None + self.__oldAspectRatio: float | None = None #: This is set to the value of the window-type config variable, but may #: optionally be overridden in the Showbase constructor. Should either @@ -279,68 +288,68 @@ def __init__(self, fStartDirect=True, windowType=None): self.requireWindow = ConfigVariableBool('require-window', True).value #: This is the main, or only window; see `winList` for a list of *all* windows. - self.win = None - self.frameRateMeter = None - self.sceneGraphAnalyzerMeter = None + self.win: GraphicsOutput | None = None + self.frameRateMeter: FrameRateMeter | None = None + self.sceneGraphAnalyzerMeter: SceneGraphAnalyzerMeter | None = None #: A list of all windows opened via `openWindow()`. - self.winList = [] - self.winControls = [] - self.mainWinMinimized = 0 - self.mainWinForeground = 0 + self.winList: list[GraphicsEngine] = [] + self.winControls: list[WindowControls] = [] + self.mainWinMinimized = False + self.mainWinForeground = False #: Contains the :class:`~panda3d.core.GraphicsPipe` object created by #: `makeDefaultPipe()`. - self.pipe = None + self.pipe: GraphicsPipe | None = None #: The full list of :class:`~panda3d.core.GraphicsPipe` objects, #: including any auxiliary pipes. Filled by `makeAllPipes()`. - self.pipeList = [] - self.mouse2cam = None - self.buttonThrowers = None - self.mouseWatcher = None + self.pipeList: list[GraphicsPipe] = [] + self.mouse2cam: NodePath | None = None + self.buttonThrowers: list[ButtonThrower] | None = None + self.mouseWatcher: NodePath | None = None #: The :class:`~panda3d.core.MouseWatcher` object, created by #: `setupMouse()`. - self.mouseWatcherNode = None - self.pointerWatcherNodes = None - self.mouseInterface = None - self.drive = None - self.trackball = None - self.texmem = None - self.showVertices = None - self.deviceButtonThrowers = [] + self.mouseWatcherNode: MouseWatcher | None = None + self.pointerWatcherNodes: list[MouseWatcher] | None = None + self.mouseInterface: NodePath | None = None + self.drive: NodePath | None = None + self.trackball: NodePath | None = None + self.texmem: Any | None = None + self.showVertices: NodePath | None = None + self.deviceButtonThrowers: list[NodePath] = [] #: This is a :class:`~panda3d.core.NodePath` pointing to the #: :class:`~panda3d.core.Camera` object set up for the 3D scene. #: Usually a child of `camera`. - self.cam = None + self.cam: NodePath | None = None #: Same as `cam`, but for the 2D scene graph. - self.cam2d = None + self.cam2d: NodePath | None = None #: Same as `cam2d`, but for the 2D overlay scene graph. - self.cam2dp = None + self.cam2dp: NodePath | None = None #: This is the :class:`~panda3d.core.NodePath` that should be used to #: manipulate the camera. It points at the node to which the default #: camera (`cam`, `camNode`) is attached. - self.camera = None + self.camera: NodePath | None = None #: Same as `camera`, but for the 2D scene graph. Parent of `cam2d`. - self.camera2d = None + self.camera2d: NodePath | None = None #: Same as `camera2d`, but for the 2D overlay scene graph. Parent of #: `cam2dp`. - self.camera2dp = None + self.camera2dp: NodePath | None = None #: A list of all cameras created with `makeCamera()`, including `cam`. - self.camList = [] + self.camList: list[NodePath] = [] #: Convenience accessor for base.cam.node(), containing a #: :class:`~panda3d.core.Camera` object. - self.camNode = None + self.camNode: Camera | None = None #: Convenience accessor for base.camNode.get_lens(), containing a #: :class:`~panda3d.core.Lens` object. - self.camLens = None - self.camFrustumVis = None + self.camLens: Lens | None = None + self.camFrustumVis: NodePath | None = None self.direct = None #: This is used to store the wx.Application object used when want-wx is #: set or `startWx()` is called. - self.wxApp = None + self.wxApp: Any | None = None self.wxAppCreated = False - self.tkRoot = None + self.tkRoot: Any | None = None self.tkRootCreated = False # This is used for syncing multiple PCs in a distributed cluster @@ -371,11 +380,11 @@ def __init__(self, fStartDirect=True, windowType=None): #: traverse it automatically in the collisionLoop task, so you won't #: need to call :meth:`~panda3d.core.CollisionTraverser.traverse()` #: yourself every frame. - self.cTrav = 0 - self.shadowTrav = 0 + self.cTrav: CollisionTraverser | Literal[0] = 0 + self.shadowTrav: CollisionTraverser | Literal[0] = 0 self.cTravStack = Stack() # Ditto for an AppTraverser. - self.appTrav = 0 + self.appTrav: Any | Literal[0] = 0 # This is the DataGraph traverser, which we might as well # create now. @@ -383,7 +392,7 @@ def __init__(self, fStartDirect=True, windowType=None): # Maybe create a RecorderController to record and/or play back # the user session. - self.recorder = None + self.recorder: RecorderController | None = None playbackSession = ConfigVariableFilename('playback-session', '') recordSession = ConfigVariableFilename('record-session', '') if not playbackSession.empty(): @@ -429,9 +438,9 @@ def __init__(self, fStartDirect=True, windowType=None): self.useTrackball() #: `.Loader.Loader` object. - self.loader = Loader.Loader(self) + self.loader = ShowBaseGlobal.loader + self.loader._init_base(self) self.graphicsEngine.setDefaultLoader(self.loader.loader) - ShowBaseGlobal.loader = self.loader #: The global event manager, as imported from `.EventManagerGlobal`. self.eventMgr = eventMgr @@ -448,22 +457,22 @@ def __init__(self, fStartDirect=True, windowType=None): #: If `enableParticles()` has been called, this is the particle manager #: as imported from :mod:`direct.particles.ParticleManagerGlobal`. self.particleMgr = None - self.particleMgrEnabled = 0 + self.particleMgrEnabled = False #: If `enableParticles()` has been called, this is the physics manager #: as imported from :mod:`direct.showbase.PhysicsManagerGlobal`. self.physicsMgr = None - self.physicsMgrEnabled = 0 - self.physicsMgrAngular = 0 + self.physicsMgrEnabled = False + self.physicsMgrAngular = False #: This is the global :class:`~panda3d.core.InputDeviceManager`, which #: keeps track of connected input devices. self.devices = InputDeviceManager.getGlobalPtr() - self.__inputDeviceNodes = {} + self.__inputDeviceNodes: dict[InputDevice, NodePath] = {} self.createStats() - self.AppHasAudioFocus = 1 + self.AppHasAudioFocus = True # Get a pointer to Panda's global ClockObject, used for # synchronizing events between Python and C. @@ -502,7 +511,7 @@ def __init__(self, fStartDirect=True, windowType=None): affinity = ConfigVariableInt('client-cpu-affinity', -1).value if (affinity in (None, -1)) and autoAffinity: affinity = 0 - if affinity not in (None, -1): + if affinity is not None and affinity != -1: # Windows XP supports a 32-bit affinity mask TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32)) @@ -575,7 +584,7 @@ def __init__(self, fStartDirect=True, windowType=None): # Now hang a hook on the window-event from Panda. This allows # us to detect when the user resizes, minimizes, or closes the # main window. - self.__prevWindowProperties = None + self.__prevWindowProperties: WindowProperties | None = None self.__directObject.accept('window-event', self.windowEvent) # Transition effects (fade, iris, etc) @@ -658,7 +667,7 @@ def printEnvDebugInfo(self): #print getDnaPath() print("}") - def destroy(self): + def destroy(self) -> None: """ Call this function to destroy the ShowBase and stop all its tasks, freeing all of the Panda resources. Normally, you should not need to call it explicitly, as it is bound to the @@ -672,7 +681,7 @@ def destroy(self): complete. """ - if Thread.getCurrentThread() != Thread.getMainThread(): + if sys.platform != "android" and Thread.getCurrentThread() != Thread.getMainThread(): task = taskMgr.add(self.destroy, extraArgs=[]) task.wait() return @@ -704,6 +713,7 @@ def destroy(self): self.shutdown() if getattr(self, 'musicManager', None): + assert self.musicManager is not None self.musicManager.shutdown() self.musicManager = None for sfxManager in self.sfxManagerList: @@ -711,12 +721,12 @@ def destroy(self): self.sfxManagerList = [] if getattr(self, 'loader', None): self.loader.destroy() - self.loader = None + del self.loader if getattr(self, 'graphicsEngine', None): self.graphicsEngine.removeAllWindows() try: - self.direct.panel.destroy() + self.direct.panel.destroy() # type: ignore[attr-defined] except Exception: pass @@ -1185,7 +1195,7 @@ def openMainWindow(self, *args, **kw): self.setSceneGraphAnalyzerMeter(flag.value) return success - def setSleep(self, amount): + def setSleep(self, amount: float) -> None: """ Sets up a task that calls python 'sleep' every frame. This is a simple way to reduce the CPU usage (and frame rate) of a panda program. @@ -1200,12 +1210,12 @@ def setSleep(self, amount): self.taskMgr.remove('clientSleep') self.taskMgr.add(self.__sleepCycleTask, 'clientSleep', sort = 55) - def __sleepCycleTask(self, task): + def __sleepCycleTask(self, task: object) -> int: Thread.sleep(self.clientSleep) #time.sleep(self.clientSleep) return Task.cont - def setFrameRateMeter(self, flag): + def setFrameRateMeter(self, flag: bool) -> None: """ Turns on or off (according to flag) a standard frame rate meter in the upper-right corner of the main window. @@ -1219,7 +1229,7 @@ def setFrameRateMeter(self, flag): self.frameRateMeter.clearWindow() self.frameRateMeter = None - def setSceneGraphAnalyzerMeter(self, flag): + def setSceneGraphAnalyzerMeter(self, flag: bool) -> None: """ Turns on or off (according to flag) a standard frame rate meter in the upper-right corner of the main window. @@ -1242,7 +1252,7 @@ def setupWindowControls(self, winCtrl=None): mouseKeyboard = self.dataRoot.find("**/*")) self.winControls.append(winCtrl) - def setupRender(self): + def setupRender(self) -> None: """ Creates the render scene graph, the primary scene graph for rendering 3-d geometry. @@ -1252,11 +1262,11 @@ def setupRender(self): self.render.setAttrib(RescaleNormalAttrib.makeDefault()) self.render.setTwoSided(0) - self.backfaceCullingEnabled = 1 - self.textureEnabled = 1 - self.wireframeEnabled = 0 + self.backfaceCullingEnabled = True + self.textureEnabled = True + self.wireframeEnabled = False - def setupRender2d(self): + def setupRender2d(self) -> None: """ Creates the render2d scene graph, the primary scene graph for 2-d objects and gui elements that are superimposed over the @@ -1355,7 +1365,7 @@ def setupRender2d(self): if xsize > 0 and ysize > 0: self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize) - def setupRender2dp(self): + def setupRender2dp(self) -> None: """ Creates a render2d scene graph, the secondary scene graph for 2-d objects and gui elements that are superimposed over the @@ -1436,7 +1446,7 @@ def setAspectRatio(self, aspectRatio): self.__configAspectRatio = aspectRatio self.adjustWindowAspectRatio(self.getAspectRatio()) - def getAspectRatio(self, win = None): + def getAspectRatio(self, win: GraphicsOutput | None = None) -> float: # Returns the actual aspect ratio of the indicated (or main # window), or the default aspect ratio if there is not yet a # main window. @@ -1445,7 +1455,7 @@ def getAspectRatio(self, win = None): if self.__configAspectRatio: return self.__configAspectRatio - aspectRatio = 1 + aspectRatio: float = 1 if win is None: win = self.win @@ -1468,7 +1478,7 @@ def getAspectRatio(self, win = None): return aspectRatio - def getSize(self, win = None): + def getSize(self, win: GraphicsOutput | None = None) -> tuple[int, int]: """ Returns the actual size of the indicated (or main window), or the default size if there is not yet a main window. @@ -1677,7 +1687,7 @@ def makeCamera2dp(self, win, sort = 20, return camera2dp - def setupDataGraph(self): + def setupDataGraph(self) -> None: """ Creates the data graph and populates it with the basic input devices. @@ -2006,7 +2016,7 @@ def updateManagers(self, state): self.physicsMgr.doPhysics(dt) return Task.cont - def createStats(self, hostname=None, port=None): + def createStats(self, hostname: str | None = None, port: int | None = None) -> bool: """ If want-pstats is set in Config.prc, or the `wantStats` member is otherwise set to True, connects to the PStats server. @@ -2168,7 +2178,7 @@ def playMusic(self, music, looping = 0, interrupt = 1, volume = None, time = 0.0 music.setLoop(looping) music.play() - def __resetPrevTransform(self, state): + def __resetPrevTransform(self, state: object) -> int: # Clear out the previous velocity deltas now, after we have # rendered (the previous frame). We do this after the render, # so that we have a chance to draw a representation of spheres @@ -2179,7 +2189,7 @@ def __resetPrevTransform(self, state): PandaNode.resetAllPrevTransform() return Task.cont - def __dataLoop(self, state): + def __dataLoop(self, state: object) -> int: # Check if there were newly connected devices. self.devices.update() @@ -2189,7 +2199,7 @@ def __dataLoop(self, state): self.dgTrav.traverse(self.dataRootNode) return Task.cont - def __ivalLoop(self, state): + def __ivalLoop(self, state: object) -> int: # Execute all intervals in the global ivalMgr. IntervalManager.ivalMgr.step() return Task.cont @@ -2207,7 +2217,7 @@ def __shadowCollisionLoop(self, state): self.shadowTrav.traverse(self.render) return Task.cont - def __collisionLoop(self, state): + def __collisionLoop(self, state: object) -> int: # run the collision traversal if we have a # CollisionTraverser set. if self.cTrav: @@ -2219,14 +2229,14 @@ def __collisionLoop(self, state): messenger.send("collisionLoopFinished") return Task.cont - def __audioLoop(self, state): + def __audioLoop(self, state: object) -> int: if self.musicManager is not None: self.musicManager.update() for x in self.sfxManagerList: x.update() return Task.cont - def __garbageCollectStates(self, state): + def __garbageCollectStates(self, state: object) -> int: """ This task is started only when we have garbage-collect-states set in the Config.prc file, in which case we're responsible for taking out Panda's garbage from @@ -2237,7 +2247,7 @@ def __garbageCollectStates(self, state): RenderState.garbageCollect() return Task.cont - def __igLoop(self, state): + def __igLoop(self, state: object) -> int: if __debug__: # We render the watch variables for the onScreenDebug as soon # as we reasonably can before the renderFrame(). @@ -2277,7 +2287,7 @@ def __igLoop(self, state): throw_new_frame() return Task.cont - def __igLoopSync(self, state): + def __igLoopSync(self, state: object) -> int: if __debug__: # We render the watch variables for the onScreenDebug as soon # as we reasonably can before the renderFrame(). @@ -2286,6 +2296,7 @@ def __igLoopSync(self, state): if self.recorder: self.recorder.recordFrame() + assert self.cluster is not None self.cluster.collectData() # Finally, render the frame. @@ -2315,6 +2326,7 @@ def __igLoopSync(self, state): time.sleep(0.1) self.graphicsEngine.readyFlip() + assert self.cluster is not None self.cluster.waitForFlipCommand() self.graphicsEngine.flipFrame() @@ -2323,7 +2335,7 @@ def __igLoopSync(self, state): throw_new_frame() return Task.cont - def restart(self, clusterSync=False, cluster=None): + def restart(self, clusterSync: bool = False, cluster=None) -> None: self.shutdown() # __resetPrevTransform goes at the very beginning of the frame. self.taskMgr.add( @@ -2354,7 +2366,7 @@ def restart(self, clusterSync=False, cluster=None): self.taskMgr.add(self.__audioLoop, 'audioLoop', sort = 60) self.eventMgr.restart() - def shutdown(self): + def shutdown(self) -> None: self.taskMgr.remove('audioLoop') self.taskMgr.remove('igLoop') self.taskMgr.remove('shadowCollisionLoop') @@ -2745,7 +2757,7 @@ def oobe(self, cam = None): self.oobeVis.reparentTo(self.camera) self.oobeMode = 1 - def __oobeButton(self, suffix, button): + def __oobeButton(self, suffix: str, button: str) -> None: if button.startswith('mouse'): # Eat mouse buttons. return @@ -3065,7 +3077,7 @@ def _movieTask(self, state): else: return Task.cont - def windowEvent(self, win): + def windowEvent(self, win: GraphicsOutput) -> None: if win != self.win: # This event isn't about our window. return @@ -3084,9 +3096,9 @@ def windowEvent(self, win): self.userExit() if properties.getForeground() and not self.mainWinForeground: - self.mainWinForeground = 1 + self.mainWinForeground = True elif not properties.getForeground() and self.mainWinForeground: - self.mainWinForeground = 0 + self.mainWinForeground = False if __debug__: if self.__autoGarbageLogging: GarbageReport.b_checkForGarbageLeaks() @@ -3094,12 +3106,12 @@ def windowEvent(self, win): if properties.getMinimized() and not self.mainWinMinimized: # If the main window is minimized, throw an event to # stop the music. - self.mainWinMinimized = 1 + self.mainWinMinimized = True messenger.send('PandaPaused') elif not properties.getMinimized() and self.mainWinMinimized: # If the main window is restored, throw an event to # restart the music. - self.mainWinMinimized = 0 + self.mainWinMinimized = False messenger.send('PandaRestarted') # If we have not forced the aspect ratio, let's see if it has @@ -3117,7 +3129,7 @@ def windowEvent(self, win): if self.wantRender2dp: self.pixel2dp.setScale(2.0 / xsize, 1.0, 2.0 / ysize) - def adjustWindowAspectRatio(self, aspectRatio): + def adjustWindowAspectRatio(self, aspectRatio: float) -> None: """ This function is normally called internally by `windowEvent()`, but it may also be called to explicitly adjust the aspect ratio of the render/render2d DisplayRegion, by a @@ -3195,14 +3207,14 @@ class that has redefined these. """ # If anybody needs to update their GUI, put a callback on this event messenger.send("aspectRatioChanged") - def userExit(self): + def userExit(self) -> NoReturn: # The user has requested we exit the program. Deal with this. if self.exitFunc: self.exitFunc() self.notify.info("Exiting ShowBase.") self.finalizeExit() - def finalizeExit(self): + def finalizeExit(self) -> NoReturn: """ Called by `userExit()` to quit the application. The default implementation just calls `sys.exit()`. @@ -3431,7 +3443,7 @@ def run(self) -> None: # pylint: disable=method-hidden This method must be called from the main thread, otherwise an error is thrown. """ - if Thread.getCurrentThread() != Thread.getMainThread(): + if Thread.getCurrentThread() != Thread.getMainThread() and sys.platform != "android": self.notify.error("run() must be called from the main thread.") return diff --git a/direct/src/showbase/ShowBaseGlobal.py b/direct/src/showbase/ShowBaseGlobal.py index 4cd4e8623b3..fe891e9c1ba 100644 --- a/direct/src/showbase/ShowBaseGlobal.py +++ b/direct/src/showbase/ShowBaseGlobal.py @@ -62,7 +62,8 @@ #: A dummy scene graph that is not being rendered by anything. hidden = NodePath("hidden") -loader: Loader +#: The global Loader instance for models, textures, etc. +loader = Loader() # Set direct notify categories now that we have config directNotify.setDconfigLevels() diff --git a/direct/src/showbase/Transitions.py b/direct/src/showbase/Transitions.py index aa79e4b38b9..1db17d97a46 100644 --- a/direct/src/showbase/Transitions.py +++ b/direct/src/showbase/Transitions.py @@ -264,6 +264,54 @@ def loadIris(self): self.iris = base.loader.loadModel(self.IrisModelName) self.iris.setPos(0, 0, 0) + def getIrisInIval(self, t=0.5, finishIval=None, blendType='noBlend'): + """ + Returns an interval without starting it. This is particularly useful in + cutscenes, so when the cutsceneIval is escaped out of we can finish the iris immediately + """ + self.noTransitions() + self.loadIris() + + scale = 0.18 * max(base.a2dRight, base.a2dTop) + transitionIval = Sequence(Func(self.iris.reparentTo, ShowBaseGlobal.aspect2d, DGG.FADE_SORT_INDEX), + LerpScaleInterval(self.iris, t, + scale = scale, + startScale = 0.01, + blendType=blendType), + Func(self.iris.detachNode), + Func(self.__finishTransition), + name = self.irisTaskName, + ) + if finishIval: + transitionIval.append(finishIval) + return transitionIval + + def getIrisOutIval(self, t=0.5, finishIval=None, blendType='noBlend'): + """ + Create a sequence that lerps the iris out, then + parents the iris to hidden + """ + self.noTransitions() + self.loadIris() + self.loadFade() # we need this to cover up the hole. + + scale = 0.18 * max(base.a2dRight, base.a2dTop) + transitionIval = Sequence(Func(self.iris.reparentTo, ShowBaseGlobal.aspect2d, DGG.FADE_SORT_INDEX), + LerpScaleInterval(self.iris, t, + scale = 0.01, + startScale = scale, + blendType=blendType), + Func(self.iris.detachNode), + # Use the fade to cover up the hole that the iris would leave + Func(self.fadeOut, 0), + Func(self.__finishTransition), + name = self.irisTaskName, + ) + + if finishIval: + transitionIval.append(finishIval) + return transitionIval + def irisIn(self, t=0.5, finishIval=None, blendType = 'noBlend'): """ Play an iris in transition over t seconds. @@ -271,28 +319,14 @@ def irisIn(self, t=0.5, finishIval=None, blendType = 'noBlend'): of the iris polygon up so it looks like we iris in. When the scale lerp is finished, it parents the iris polygon to hidden. """ - self.noTransitions() - self.loadIris() if t == 0: self.iris.detachNode() fut = AsyncFuture() fut.setResult(None) return fut else: - self.iris.reparentTo(ShowBaseGlobal.aspect2d, DGG.FADE_SORT_INDEX) - - scale = 0.18 * max(base.a2dRight, base.a2dTop) - self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, - scale = scale, - startScale = 0.01, - blendType=blendType), - Func(self.iris.detachNode), - Func(self.__finishTransition), - name = self.irisTaskName, - ) + self.transitionIval = self.getIrisInIval(t, finishIval, blendType) self.__transitionFuture = AsyncFuture() - if finishIval: - self.transitionIval.append(finishIval) self.transitionIval.start() return self.__transitionFuture @@ -304,9 +338,6 @@ def irisOut(self, t=0.5, finishIval=None, blendType='noBlend'): lerp is finished, it leaves the iris polygon covering the aspect2d plane until you irisIn or call noIris. """ - self.noTransitions() - self.loadIris() - self.loadFade() # we need this to cover up the hole. if t == 0: self.iris.detachNode() self.fadeOut(0) @@ -314,22 +345,8 @@ def irisOut(self, t=0.5, finishIval=None, blendType='noBlend'): fut.setResult(None) return fut else: - self.iris.reparentTo(ShowBaseGlobal.aspect2d, DGG.FADE_SORT_INDEX) - - scale = 0.18 * max(base.a2dRight, base.a2dTop) - self.transitionIval = Sequence(LerpScaleInterval(self.iris, t, - scale = 0.01, - startScale = scale, - blendType=blendType), - Func(self.iris.detachNode), - # Use the fade to cover up the hole that the iris would leave - Func(self.fadeOut, 0), - Func(self.__finishTransition), - name = self.irisTaskName, - ) + self.transitionIval = self.getIrisOutIval(t, finishIval, blendType) self.__transitionFuture = AsyncFuture() - if finishIval: - self.transitionIval.append(finishIval) self.transitionIval.start() return self.__transitionFuture diff --git a/direct/src/stdpy/glob.py b/direct/src/stdpy/glob.py index 3b4f0fefb51..8944548a6c4 100755 --- a/direct/src/stdpy/glob.py +++ b/direct/src/stdpy/glob.py @@ -52,7 +52,7 @@ def glob1(dirname, pattern): if not dirname: dirname = os.curdir try: - names = os.listdir(dirname) + names = file.listdir(dirname) except os.error: return [] if pattern[0] != '.': diff --git a/direct/src/task/Task.py b/direct/src/task/Task.py index 9896b9c5ee0..f879cbd5425 100644 --- a/direct/src/task/Task.py +++ b/direct/src/task/Task.py @@ -28,7 +28,7 @@ signal = None else: try: - import _signal as signal # type: ignore[import, no-redef] + import _signal as signal # type: ignore[import-not-found, no-redef] except ImportError: signal = None diff --git a/doc/CODING_STYLE.md b/doc/CODING_STYLE.md index 614057737dd..05814b74e13 100644 --- a/doc/CODING_STYLE.md +++ b/doc/CODING_STYLE.md @@ -184,7 +184,7 @@ Try to group logically-similar lines, separating them with a single blank line. Modern language features ------------------------ -Panda3D is a C++11 project. The use of the following modern language features +Panda3D is a C++14 project. The use of the following modern language features is greatly encouraged: 1. `nullptr` over `NULL` @@ -197,4 +197,4 @@ creating a typedef for the container type instead. Avoid using `std::function` in cases where a lambda can be accepted directly (using a template function), since it has extra overhead over lambdas. -C++14 and C++17 features should be avoided for now. +C++17 features should be avoided for now. diff --git a/doc/ReleaseNotes b/doc/ReleaseNotes index 97a15ddbe8f..e5651145b7d 100644 --- a/doc/ReleaseNotes +++ b/doc/ReleaseNotes @@ -1,3 +1,64 @@ +----------------------- RELEASE 1.10.15 ----------------------- + +This release adds support for Python 3.13, and fixes some significant bugs. +Upgrading is highly recommended. + +Windowing +* Fix regression related to fullscreen switching on Windows (#1594) +* Fix issues related to fullscreen switching corner cases on macOS +* Fix keyUp event being eaten when switching fullscreen modes on macOS +* Support UTF-8 window titles on X11 +* Fix wrong error message on X11 if xf86dga extension is not found + +Rendering +* Add "Khronos PBR Neutral" tone mapping operator to HDR filter (#1659) +* OpenGL: Fix offscreen buffer clearing if back buffers are requested +* DirectX 9: Fix crash on window event after window close +* DirectX 9: Fix support for r32f and rgba32f textures +* DirectX 9: Fix crash when copying inverted framebuffer to texture RAM +* DirectX 9: Fix buffer crash if main window has no depth buffer + +Text +* Fix handling of surrogate pairs in text on Windows (#1629) +* Fix disabling text-native-antialias setting not working properly +* Fix small-caps not working with text-use-harfbuzz enabled (#1666) +* Show error instead of crash if glyph does not fit in page (#1626) +* Update docstring for set_text_color() (#1621) + +GUI +* Fix crash when PGEntry removes itself with background focus (#1650) +* Fix `PGEntry::get_cursor_Y()`, which always returned 0.0 (#1633) +* Now makes copies of mutable default values in DirectGUI constructor (#1587) + +Deployment +* Fix wrong relative paths with bam_model_extensions (#1642) +* Add bam_embed_textures option to embed textures in .bam files +* Don't warn about missing ld-linux library on aarch64 Linux +* build_apps dist hooks no longer import Panda3D (#1624) + +Miscellaneous +* Fix major memory leak on M1/M2/M3 Macs +* Fix seeking in OpenAL sounds not working on macOS in some cases (#1607) +* Fix direct.stdpy.glob not finding files in VFS (#1675) +* Improve printing of floating-point linmath objects (#1671) +* Fix VFS mount points not being listed as directories (#1244) +* Fix splits occurring in RopeNode geometry (#1325) +* Fix DistancePhasedNode exception at module clean-up time +* Fix magfilter on KW_mipmap in egg-palettize (#1631) +* Fix creating LerpFunctionInterval from functools.partial (#1623) +* Fix "no attribute notifier" in FSM.requestNext/Prev (#1644) +* Fix file_texture_mode property on BamWriter being read-only +* TransformState getters no longer return references to temporary (#1625) + +Build +* Assorted build fixes for Python 3.13 and 3.13t +* Fix assorted compiler warnings +* Build fix for newer FFmpeg versions +* Add --ignore option to test_wheel.py to allow ignoring tests +* Update Eigen to 3.2.10 (fixes binder2nd error when building with C++17) +* Fix non-determinism in Python bindings (#1651) +* Fix preprocessor issues in interrogate (#1635) + ----------------------- RELEASE 1.10.14 ----------------------- This release adds support for Python 3.12 and furthermore contains significant diff --git a/dtool/CMakeLists.txt b/dtool/CMakeLists.txt index 62308bd9801..36e93a0be36 100644 --- a/dtool/CMakeLists.txt +++ b/dtool/CMakeLists.txt @@ -2,11 +2,9 @@ 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) diff --git a/dtool/CompilerFlags.cmake b/dtool/CompilerFlags.cmake index 48f931387f4..31d96279e32 100644 --- a/dtool/CompilerFlags.cmake +++ b/dtool/CompilerFlags.cmake @@ -51,8 +51,8 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GCC") endif() -# Panda3D is now a C++11 project. -set(CMAKE_CXX_STANDARD 11) +# Panda3D is now a C++14 project. +set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Set certain CMake flags we expect @@ -190,8 +190,8 @@ else() check_cxx_compiler_flag("-fno-rtti" COMPILER_SUPPORTS_FRTTI) if(COMPILER_SUPPORTS_FRTTI) - set(cxx_rtti_on "-frtti") - set(cxx_rtti_off "-fno-rtti") + set(cxx_rtti_on "$<$,$>:-frtti>") + set(cxx_rtti_off "$<$,$>:-fno-rtti>") else() set(cxx_rtti_on) diff --git a/dtool/Config.cmake b/dtool/Config.cmake index d269b62e3ea..67ea64c9ce0 100644 --- a/dtool/Config.cmake +++ b/dtool/Config.cmake @@ -221,12 +221,6 @@ mark_as_advanced(DEFAULT_PRC_DIR PRC_DIR_ENVVARS PRC_PATH_ENVVARS # 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 @@ -249,8 +243,79 @@ option(INTERROGATE_VERBOSE "Set this if you would like interrogate to generate advanced debugging information." OFF) +set(_default_build_interrogate OFF) +if (INTERROGATE_C_INTERFACE OR INTERROGATE_PYTHON_INTERFACE) + set(_default_build_interrogate ON) +endif() + +option(BUILD_INTERROGATE + "Do you want to build interrogate from source? This is necessary +if you wish to build Python or other bindings around Panda3D's C++ +interface. Set this to false if you already have a compatible +version of interrogate installed." ${_default_build_interrogate}) + mark_as_advanced(INTERROGATE_OPTIONS) +if(BUILD_INTERROGATE) + include(ExternalProject) + + set(_interrogate_dir "${PROJECT_BINARY_DIR}/interrogate") + + ExternalProject_Add( + panda3d-interrogate + + GIT_REPOSITORY https://github.com/panda3d/interrogate.git + GIT_TAG d2844d994fcc465a4e22b10001d3ac5c4012b814 + + PREFIX ${_interrogate_dir} + CMAKE_ARGS + -DHAVE_PYTHON=OFF + -DBUILD_SHARED_LIBS=OFF + -DCMAKE_INSTALL_PREFIX:PATH= + + EXCLUDE_FROM_ALL ON + BUILD_BYPRODUCTS "${_interrogate_dir}/bin/interrogate" + "${_interrogate_dir}/bin/interrogate_module" + ) + + add_executable(interrogate IMPORTED GLOBAL) + add_dependencies(interrogate panda3d-interrogate) + set_target_properties(interrogate PROPERTIES IMPORTED_LOCATION "${_interrogate_dir}/bin/interrogate") + + add_executable(interrogate_module IMPORTED GLOBAL) + add_dependencies(interrogate_module panda3d-interrogate) + set_target_properties(interrogate_module PROPERTIES IMPORTED_LOCATION "${_interrogate_dir}/bin/interrogate_module") + +else() + find_program(INTERROGATE_EXECUTABLE interrogate) + find_program(INTERROGATE_MODULE_EXECUTABLE interrogate_module) + + add_executable(interrogate IMPORTED GLOBAL) + if(INTERROGATE_EXECUTABLE) + set_target_properties(interrogate PROPERTIES + IMPORTED_LOCATION "${INTERROGATE_EXECUTABLE}") + + elseif(INTERROGATE_PYTHON_INTERFACE OR INTERROGATE_C_INTERFACE) + message(FATAL_ERROR + "Requested interrogate bindings, but interrogate not found. Set " + "BUILD_INTERROGATE to build interrogate from source, or set " + "INTERROGATE_EXECUTABLE to the location of this tool.") + endif() + + add_executable(interrogate_module IMPORTED GLOBAL) + if(INTERROGATE_MODULE_EXECUTABLE) + set_target_properties(interrogate_module PROPERTIES + IMPORTED_LOCATION "${INTERROGATE_MODULE_EXECUTABLE}") + + elseif(INTERROGATE_PYTHON_INTERFACE) + message(FATAL_ERROR + "Requested interrogate bindings, but interrogate not found. Set " + "BUILD_INTERROGATE to build interrogate from source, or set " + "INTERROGATE_MODULE_EXECUTABLE to the location of this tool.") + endif() + +endif() + # # The following options have to do with optional debugging features. # diff --git a/dtool/Package.cmake b/dtool/Package.cmake index 42758c2702f..dfa6c5772a5 100644 --- a/dtool/Package.cmake +++ b/dtool/Package.cmake @@ -1,9 +1,54 @@ -set(_thirdparty_dir_default "${PROJECT_SOURCE_DIR}/thirdparty") -if(NOT IS_DIRECTORY "${_thirdparty_dir_default}") - set(_thirdparty_dir_default "") +set(_thirdparty_platform) + +if(APPLE) + set(_thirdparty_platform "darwin-libs-a") + +elseif(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_thirdparty_platform "win-libs-vc14-x64") + else() + set(_thirdparty_platform "win-libs-vc14") + endif() + +elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(_thirdparty_platform "linux-libs-arm64") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_thirdparty_platform "linux-libs-x64") + else() + set(_thirdparty_platform "linux-libs-a") + endif() + +elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(_thirdparty_platform "freebsd-libs-arm64") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_thirdparty_platform "freebsd-libs-x64") + else() + set(_thirdparty_platform "freebsd-libs-a") + endif() + +elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") + set(_thirdparty_platform "android-libs-${CMAKE_ANDROID_ARCH}") + +elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + set(_thirdparty_platform "emscripten-libs") + +elseif(CMAKE_SYSTEM_NAME STREQUAL "WASI") + set(_thirdparty_platform "wasi-libs-${CMAKE_SYSTEM_PROCESSOR}") + endif() -if(CMAKE_SYSTEM_NAME STREQUAL "WASI") - set(_thirdparty_dir_default "") + +set(_thirdparty_dir_default "") +if(_thirdparty_platform) + if(IS_DIRECTORY "${PROJECT_SOURCE_DIR}/thirdparty/${_thirdparty_platform}") + set(_thirdparty_dir_default "${PROJECT_SOURCE_DIR}/thirdparty") + + else() + message(WARNING + "Ignoring thirdparty directory without ${_thirdparty_platform} subdirectory.") + + endif() endif() set(THIRDPARTY_DIRECTORY "${_thirdparty_dir_default}" CACHE PATH @@ -14,6 +59,11 @@ set(THIRDPARTY_DIRECTORY "${_thirdparty_dir_default}" CACHE PATH set(THIRDPARTY_DLLS) if(THIRDPARTY_DIRECTORY) + if(NOT _thirdparty_platform) + message(FATAL_ERROR + "You can't use THIRDPARTY_DIRECTORY on this platform. Unset it to continue.") + endif() + # This policy is necessary for PackageName_ROOT variables to be respected if(POLICY CMP0074) cmake_policy(GET CMP0074 _policy_cmp0074) @@ -24,63 +74,14 @@ if(THIRDPARTY_DIRECTORY) "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") - elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - set(_package_dir ${THIRDPARTY_DIRECTORY}/linux-libs-arm64) - elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_package_dir ${THIRDPARTY_DIRECTORY}/linux-libs-x64) - else() - set(_package_dir ${THIRDPARTY_DIRECTORY}/linux-libs-a) - endif() - - elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - set(_package_dir ${THIRDPARTY_DIRECTORY}/freebsd-libs-arm64) - elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_package_dir ${THIRDPARTY_DIRECTORY}/freebsd-libs-x64) - else() - set(_package_dir ${THIRDPARTY_DIRECTORY}/freebsd-libs-a) - endif() - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") - set(_package_dir ${THIRDPARTY_DIRECTORY}/android-libs-${CMAKE_ANDROID_ARCH}) - - 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 @@ -133,7 +134,7 @@ if(THIRDPARTY_DIRECTORY) endif() # Set search path - set(${_Package}_ROOT "${_package_dir}/${_package}") + set(${_Package}_ROOT "${THIRDPARTY_DIRECTORY}/${_thirdparty_platform}/${_package}") # Set up copying DLLs, if necessary file(GLOB _dlls "${${_Package}_ROOT}/bin/*.dll") @@ -200,6 +201,27 @@ if(DEFINED _PREV_WANT_PYTHON_VERSION endif() +# Look for Python in the thirdparty directory on Windows. +if(WIN32 AND THIRDPARTY_DIRECTORY) + set(_python_dir_suffix "") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_python_dir_suffix "-x64") + endif() + + if(WANT_PYTHON_VERSION) + set(Python_ROOT_DIR "${THIRDPARTY_DIRECTORY}/win-python${WANT_PYTHON_VERSION}${_python_dir_suffix}") + else() + # CMake doesn't support NATURAL sorting until 3.18, so we sort the 3.1x + # versions separately from the prior versions. + file(GLOB _python_dirs "${THIRDPARTY_DIRECTORY}/win-python3.[0-9][0-9]${_python_dir_suffix}") + file(GLOB _python_dirs2 "${THIRDPARTY_DIRECTORY}/win-python3.[0-9]${_python_dir_suffix}") + list(SORT _python_dirs COMPARE FILE_BASENAME CASE INSENSITIVE ORDER DESCENDING) + list(SORT _python_dirs2 COMPARE FILE_BASENAME CASE INSENSITIVE ORDER DESCENDING) + list(APPEND _python_dirs ${_python_dirs2}) + set(Python_ROOT_DIR "${_python_dirs}") + endif() +endif() + if(WANT_PYTHON_VERSION) # A specific version is requested; ensure we get that specific version list(APPEND WANT_PYTHON_VERSION "EXACT") @@ -319,6 +341,104 @@ if(HAVE_PYTHON) set(PYTHON_EXTENSION_SUFFIX "${_EXT_SUFFIX}" CACHE STRING "Suffix for Python binary extension modules.") + # Determine the platform to use for .whl files. + if(WIN32) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(_platform "win-amd64") + else() + set(_platform "win32") + endif() + + elseif(APPLE) + if(NOT CMAKE_OSX_ARCHITECTURES) + set(_arch_tag ${CMAKE_SYSTEM_PROCESSOR}) + + elseif("x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES) + if("arm64" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(_arch_tag "universal2") + + elseif("i386" IN_LIST CMAKE_OSX_ARCHITECTURES AND + "ppc64" IN_LIST CMAKE_OSX_ARCHITECTURES AND + "ppc" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(_arch_tag "universal") + + elseif("i386" IN_LIST CMAKE_OSX_ARCHITECTURES AND + "ppc" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(_arch_tag "fat32") + + elseif("ppc64" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(_arch_tag "fat64") + + elseif("i386" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(_arch_tag "intel") + + else() + set(_arch_tag "x86_64") + + endif() + + elseif("i386" IN_LIST CMAKE_OSX_ARCHITECTURES AND + "ppc" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(_arch_tag "fat") + + else() + list(GET CMAKE_OSX_ARCHITECTURES 0 _arch_tag) + + endif() + + set(_target "${CMAKE_OSX_DEPLOYMENT_TARGET}") + + if(_arch_tag STREQUAL "arm64" AND _target VERSION_LESS "11.0") + set(_target "11.0") + + elseif(PYTHON_VERSION_STRING VERSION_GREATER_EQUAL "3.13" AND _target VERSION_LESS "10.13") + set(_target "10.13") + + elseif(PYTHON_VERSION_STRING VERSION_GREATER_EQUAL "3.8" AND _target VERSION_LESS "10.9") + set(_target "10.9") + + endif() + + set(_platform "macosx-${_target}-${_arch_tag}") + + elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(_platform "linux-${CMAKE_SYSTEM_PROCESSOR}") + + if(IS_DIRECTORY "/opt/python") + # Sloppy detection for manylinux. + if(EXISTS "/lib64/libc-2.5.so" OR EXISTS "/lib/libc-2.5.so") + set(_platform "manylinux1-${CMAKE_SYSTEM_PROCESSOR}") + + elseif(EXISTS "/lib64/libc-2.12.so" OR EXISTS "/lib/libc-2.12.so") + set(_platform "manylinux2010-${CMAKE_SYSTEM_PROCESSOR}") + + elseif(EXISTS "/lib64/libc-2.17.so" OR EXISTS "/lib/libc-2.17.so") + set(_platform "manylinux2014-${CMAKE_SYSTEM_PROCESSOR}") + + elseif(EXISTS "/lib/x86_64-linux-gnu/libc-2.24.so" OR EXISTS "/lib/i386-linux-gnu/libc-2.24.so") + set(_platform "manylinux_2_24-${CMAKE_SYSTEM_PROCESSOR}") + + elseif(EXISTS "/etc/almalinux-release" AND EXISTS "/lib64/libc-2.28.so") + set(_platform "manylinux_2_28-${CMAKE_SYSTEM_PROCESSOR}") + + endif() + endif() + + elseif(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + set(_platform "emscripten-${CMAKE_SYSTEM_PROCESSOR}") + + else() + set(_platform "") + + endif() + + # This is being read out of the CMake cache by makewheel.py. + if(_platform) + set(PYTHON_PLATFORM_TAG "${_platform}" CACHE STRING "" FORCE) + else() + unset(PYTHON_PLATFORM_TAG CACHE) + endif() + endif() if(NOT DEFINED _PREV_PYTHON_VALUES) diff --git a/dtool/dtool_config.h.in b/dtool/dtool_config.h.in index f115e022c3f..2c178844071 100644 --- a/dtool/dtool_config.h.in +++ b/dtool/dtool_config.h.in @@ -24,9 +24,6 @@ /* 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 diff --git a/dtool/metalibs/dtoolconfig/pydtool.cxx b/dtool/metalibs/dtoolconfig/pydtool.cxx deleted file mode 100644 index 38b6e6359a8..00000000000 --- a/dtool/metalibs/dtoolconfig/pydtool.cxx +++ /dev/null @@ -1,3112 +0,0 @@ -/* - * This file was generated by: - * interrogate -D EXPCL_DTOOLCONFIG= -nodb -python -promiscuous -I../../../built/include -module panda3d.interrogatedb -library interrogatedb -string -true-names -do-module -oc pydtool.cxx ../../src/interrogatedb/interrogate_interface.h ../../src/interrogatedb/interrogate_request.h - * - */ - -#include - -#include "../../src/interrogatedb/interrogate_interface.h" -#include "../../src/interrogatedb/interrogate_request.h" -#include "dtoolbase.h" - -#undef _POSIX_C_SOURCE -#undef _XOPEN_SOURCE -#define PY_SSIZE_T_CLEAN 1 - -#if PYTHON_FRAMEWORK - #include -#else - #include "Python.h" -#endif - -static PyObject *_inP07yttbRf(PyObject *self, PyObject *args); -static PyObject *_inP07ytda_g(PyObject *self, PyObject *args); -static PyObject *_inP07yt4RgX(PyObject *self, PyObject *args); -static PyObject *_inP07yt3Gip(PyObject *self, PyObject *args); -static PyObject *_inP07ytRKDz(PyObject *self, PyObject *args); -static PyObject *_inP07ytgZ9N(PyObject *self, PyObject *args); -static PyObject *_inP07ytFnRZ(PyObject *self, PyObject *args); -static PyObject *_inP07ytg0Qv(PyObject *self, PyObject *args); -static PyObject *_inP07yttrqw(PyObject *self, PyObject *args); -static PyObject *_inP07ytdmpW(PyObject *self, PyObject *args); -static PyObject *_inP07ytUYgQ(PyObject *self, PyObject *args); -static PyObject *_inP07yt0k7F(PyObject *self, PyObject *args); -static PyObject *_inP07ytfIsr(PyObject *self, PyObject *args); -static PyObject *_inP07ytvysR(PyObject *self, PyObject *args); -static PyObject *_inP07ytYQ_2(PyObject *self, PyObject *args); -static PyObject *_inP07yt3kdv(PyObject *self, PyObject *args); -static PyObject *_inP07ytew01(PyObject *self, PyObject *args); -static PyObject *_inP07ytQna7(PyObject *self, PyObject *args); -static PyObject *_inP07ytkg95(PyObject *self, PyObject *args); -static PyObject *_inP07ytluRc(PyObject *self, PyObject *args); -static PyObject *_inP07yttHdM(PyObject *self, PyObject *args); -static PyObject *_inP07ytDId0(PyObject *self, PyObject *args); -static PyObject *_inP07ytHuAm(PyObject *self, PyObject *args); -static PyObject *_inP07yt_xr0(PyObject *self, PyObject *args); -static PyObject *_inP07ytH5qp(PyObject *self, PyObject *args); -static PyObject *_inP07ytLfJw(PyObject *self, PyObject *args); -static PyObject *_inP07yt_Atg(PyObject *self, PyObject *args); -static PyObject *_inP07ytlBqc(PyObject *self, PyObject *args); -static PyObject *_inP07ytNdUp(PyObject *self, PyObject *args); -static PyObject *_inP07ytlS0p(PyObject *self, PyObject *args); -static PyObject *_inP07ytZZe7(PyObject *self, PyObject *args); -static PyObject *_inP07ytV5S_(PyObject *self, PyObject *args); -static PyObject *_inP07yto9vD(PyObject *self, PyObject *args); -static PyObject *_inP07ytv7tF(PyObject *self, PyObject *args); -static PyObject *_inP07ythOg6(PyObject *self, PyObject *args); -static PyObject *_inP07ytoZUn(PyObject *self, PyObject *args); -static PyObject *_inP07ytq45U(PyObject *self, PyObject *args); -static PyObject *_inP07yt6IPa(PyObject *self, PyObject *args); -static PyObject *_inP07ytU2_B(PyObject *self, PyObject *args); -static PyObject *_inP07ytHFO2(PyObject *self, PyObject *args); -static PyObject *_inP07ytcfjm(PyObject *self, PyObject *args); -static PyObject *_inP07yt3Sjw(PyObject *self, PyObject *args); -static PyObject *_inP07ytgJcX(PyObject *self, PyObject *args); -static PyObject *_inP07ytYlw6(PyObject *self, PyObject *args); -static PyObject *_inP07ytsmnz(PyObject *self, PyObject *args); -static PyObject *_inP07ytxQ10(PyObject *self, PyObject *args); -static PyObject *_inP07yt6gPB(PyObject *self, PyObject *args); -static PyObject *_inP07ytISgV(PyObject *self, PyObject *args); -static PyObject *_inP07ytH3bx(PyObject *self, PyObject *args); -static PyObject *_inP07ytzeUk(PyObject *self, PyObject *args); -static PyObject *_inP07ytUeI5(PyObject *self, PyObject *args); -static PyObject *_inP07ytbmxJ(PyObject *self, PyObject *args); -static PyObject *_inP07ytY8Lc(PyObject *self, PyObject *args); -static PyObject *_inP07ytJAAI(PyObject *self, PyObject *args); -static PyObject *_inP07yt0UXw(PyObject *self, PyObject *args); -static PyObject *_inP07ytuSvx(PyObject *self, PyObject *args); -static PyObject *_inP07ytwpYd(PyObject *self, PyObject *args); -static PyObject *_inP07ytOfNh(PyObject *self, PyObject *args); -static PyObject *_inP07ytf5_U(PyObject *self, PyObject *args); -static PyObject *_inP07ytL3ZB(PyObject *self, PyObject *args); -static PyObject *_inP07ytXw0I(PyObject *self, PyObject *args); -static PyObject *_inP07yt3zru(PyObject *self, PyObject *args); -static PyObject *_inP07ytRrg2(PyObject *self, PyObject *args); -static PyObject *_inP07ytEJCx(PyObject *self, PyObject *args); -static PyObject *_inP07ytWAZr(PyObject *self, PyObject *args); -static PyObject *_inP07ytHQi6(PyObject *self, PyObject *args); -static PyObject *_inP07ytrD_M(PyObject *self, PyObject *args); -static PyObject *_inP07ytYaah(PyObject *self, PyObject *args); -static PyObject *_inP07yt2otr(PyObject *self, PyObject *args); -static PyObject *_inP07ytNP_b(PyObject *self, PyObject *args); -static PyObject *_inP07ytrrrN(PyObject *self, PyObject *args); -static PyObject *_inP07ytjolz(PyObject *self, PyObject *args); -static PyObject *_inP07ytt_JD(PyObject *self, PyObject *args); -static PyObject *_inP07ytwEts(PyObject *self, PyObject *args); -static PyObject *_inP07ytrJWs(PyObject *self, PyObject *args); -static PyObject *_inP07ytpmFD(PyObject *self, PyObject *args); -static PyObject *_inP07ytyYUX(PyObject *self, PyObject *args); -static PyObject *_inP07yt54dn(PyObject *self, PyObject *args); -static PyObject *_inP07ytGMpW(PyObject *self, PyObject *args); -static PyObject *_inP07ytNuBV(PyObject *self, PyObject *args); -static PyObject *_inP07yt9UwA(PyObject *self, PyObject *args); -static PyObject *_inP07yt3FDt(PyObject *self, PyObject *args); -static PyObject *_inP07ytDgOY(PyObject *self, PyObject *args); -static PyObject *_inP07ytf513(PyObject *self, PyObject *args); -static PyObject *_inP07ytsqGH(PyObject *self, PyObject *args); -static PyObject *_inP07yt7shV(PyObject *self, PyObject *args); -static PyObject *_inP07ytA1eF(PyObject *self, PyObject *args); -static PyObject *_inP07yt776V(PyObject *self, PyObject *args); -static PyObject *_inP07ytryup(PyObject *self, PyObject *args); -static PyObject *_inP07ytiytI(PyObject *self, PyObject *args); -static PyObject *_inP07ytZc07(PyObject *self, PyObject *args); -static PyObject *_inP07ytfaH0(PyObject *self, PyObject *args); -static PyObject *_inP07ytGB9D(PyObject *self, PyObject *args); -static PyObject *_inP07ytrppS(PyObject *self, PyObject *args); -static PyObject *_inP07ytO50x(PyObject *self, PyObject *args); -static PyObject *_inP07ytsxxs(PyObject *self, PyObject *args); -static PyObject *_inP07ytMT0z(PyObject *self, PyObject *args); -static PyObject *_inP07ytiW3v(PyObject *self, PyObject *args); -static PyObject *_inP07yt4Px8(PyObject *self, PyObject *args); -static PyObject *_inP07ytNHcs(PyObject *self, PyObject *args); -static PyObject *_inP07ytqHrb(PyObject *self, PyObject *args); -static PyObject *_inP07ytaOqq(PyObject *self, PyObject *args); -static PyObject *_inP07ytpTBb(PyObject *self, PyObject *args); -static PyObject *_inP07ytZUkn(PyObject *self, PyObject *args); -static PyObject *_inP07ytqWOw(PyObject *self, PyObject *args); -static PyObject *_inP07ytHu7x(PyObject *self, PyObject *args); -static PyObject *_inP07ytwGnA(PyObject *self, PyObject *args); -static PyObject *_inP07ytXGxx(PyObject *self, PyObject *args); -static PyObject *_inP07ytj04Z(PyObject *self, PyObject *args); -static PyObject *_inP07ytEOv4(PyObject *self, PyObject *args); -static PyObject *_inP07ytpCqJ(PyObject *self, PyObject *args); -static PyObject *_inP07yt_Pz3(PyObject *self, PyObject *args); -static PyObject *_inP07ytt_06(PyObject *self, PyObject *args); -static PyObject *_inP07ytmuPs(PyObject *self, PyObject *args); -static PyObject *_inP07ytvM8B(PyObject *self, PyObject *args); -static PyObject *_inP07ytap97(PyObject *self, PyObject *args); -static PyObject *_inP07yt0o8D(PyObject *self, PyObject *args); -static PyObject *_inP07ytOoQ2(PyObject *self, PyObject *args); -static PyObject *_inP07ytKuFh(PyObject *self, PyObject *args); -static PyObject *_inP07yto5L6(PyObject *self, PyObject *args); -static PyObject *_inP07ytzgKK(PyObject *self, PyObject *args); -static PyObject *_inP07yt0FIF(PyObject *self, PyObject *args); -static PyObject *_inP07ytZqvD(PyObject *self, PyObject *args); -static PyObject *_inP07ytDyRd(PyObject *self, PyObject *args); -static PyObject *_inP07ytMnKa(PyObject *self, PyObject *args); -static PyObject *_inP07ytRtji(PyObject *self, PyObject *args); -static PyObject *_inP07ytCnbQ(PyObject *self, PyObject *args); -static PyObject *_inP07ytoxqc(PyObject *self, PyObject *args); -static PyObject *_inP07ytZQIS(PyObject *self, PyObject *args); -static PyObject *_inP07ytdUVN(PyObject *self, PyObject *args); -static PyObject *_inP07ytZtNk(PyObject *self, PyObject *args); -static PyObject *_inP07ytihbt(PyObject *self, PyObject *args); -static PyObject *_inP07ytbyPY(PyObject *self, PyObject *args); -static PyObject *_inP07ytAaT6(PyObject *self, PyObject *args); -static PyObject *_inP07ytgL9q(PyObject *self, PyObject *args); -static PyObject *_inP07ytWB97(PyObject *self, PyObject *args); -static PyObject *_inP07ytDUAl(PyObject *self, PyObject *args); -static PyObject *_inP07yt1_Kf(PyObject *self, PyObject *args); -static PyObject *_inP07yt98lD(PyObject *self, PyObject *args); -static PyObject *_inP07yt9SHr(PyObject *self, PyObject *args); -static PyObject *_inP07ytdiZP(PyObject *self, PyObject *args); -static PyObject *_inP07ytTdER(PyObject *self, PyObject *args); -static PyObject *_inP07ytYO56(PyObject *self, PyObject *args); -static PyObject *_inP07ytxtCG(PyObject *self, PyObject *args); -static PyObject *_inP07yt_EB2(PyObject *self, PyObject *args); -static PyObject *_inP07ytEG1l(PyObject *self, PyObject *args); -static PyObject *_inP07yt7tUq(PyObject *self, PyObject *args); -static PyObject *_inP07ytyStU(PyObject *self, PyObject *args); -static PyObject *_inP07ytdM85(PyObject *self, PyObject *args); -static PyObject *_inP07ytk_GN(PyObject *self, PyObject *args); -static PyObject *_inP07yt8QjG(PyObject *self, PyObject *args); -static PyObject *_inP07ytyMtj(PyObject *self, PyObject *args); -static PyObject *_inP07ytHDtN(PyObject *self, PyObject *args); -static PyObject *_inP07ytHFjA(PyObject *self, PyObject *args); -static PyObject *_inP07yt_NPR(PyObject *self, PyObject *args); -static PyObject *_inP07ytcTOH(PyObject *self, PyObject *args); -static PyObject *_inP07ytC5Uk(PyObject *self, PyObject *args); -static PyObject *_inP07ythdU7(PyObject *self, PyObject *args); -static PyObject *_inP07ytQPxU(PyObject *self, PyObject *args); -static PyObject *_inP07ytO7Pz(PyObject *self, PyObject *args); -static PyObject *_inP07ytvu_E(PyObject *self, PyObject *args); -static PyObject *_inP07ytxGUt(PyObject *self, PyObject *args); -static PyObject *_inP07ytzM1P(PyObject *self, PyObject *args); -static PyObject *_inP07ytoY5L(PyObject *self, PyObject *args); -static PyObject *_inP07yte_7S(PyObject *self, PyObject *args); -static PyObject *_inP07ytw_15(PyObject *self, PyObject *args); - - -/* - * Python simple wrapper for - * void interrogate_add_search_directory(char const *dirname) - */ -static PyObject * -_inP07yttbRf(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - (::interrogate_add_search_directory)((char const *)param0); - return Py_BuildValue(""); - } - return nullptr; -} - -/* - * Python simple wrapper for - * void interrogate_add_search_path(char const *pathstring) - */ -static PyObject * -_inP07ytda_g(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - (::interrogate_add_search_path)((char const *)param0); - return Py_BuildValue(""); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_error_flag(void) - */ -static PyObject * -_inP07yt4RgX(PyObject *, PyObject *args) { - if (PyArg_ParseTuple(args, "")) { - bool return_value = (::interrogate_error_flag)(); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_number_of_manifests(void) - */ -static PyObject * -_inP07yt3Gip(PyObject *, PyObject *args) { - if (PyArg_ParseTuple(args, "")) { - int return_value = (::interrogate_number_of_manifests)(); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * ManifestIndex interrogate_get_manifest(int n) - */ -static PyObject * -_inP07ytRKDz(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - ManifestIndex return_value = (::interrogate_get_manifest)((int)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * ManifestIndex interrogate_get_manifest_by_name(char const *manifest_name) - */ -static PyObject * -_inP07ytgZ9N(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - ManifestIndex return_value = (::interrogate_get_manifest_by_name)((char const *)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_manifest_name(ManifestIndex manifest) - */ -static PyObject * -_inP07ytFnRZ(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_manifest_name)((ManifestIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_manifest_definition(ManifestIndex manifest) - */ -static PyObject * -_inP07ytg0Qv(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_manifest_definition)((ManifestIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_manifest_has_type(ManifestIndex manifest) - */ -static PyObject * -_inP07yttrqw(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_manifest_has_type)((ManifestIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_manifest_get_type(ManifestIndex manifest) - */ -static PyObject * -_inP07ytdmpW(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_manifest_get_type)((ManifestIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_manifest_has_getter(ManifestIndex manifest) - */ -static PyObject * -_inP07ytUYgQ(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_manifest_has_getter)((ManifestIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_manifest_getter(ManifestIndex manifest) - */ -static PyObject * -_inP07yt0k7F(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_manifest_getter)((ManifestIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_manifest_has_int_value(ManifestIndex manifest) - */ -static PyObject * -_inP07ytfIsr(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_manifest_has_int_value)((ManifestIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_manifest_get_int_value(ManifestIndex manifest) - */ -static PyObject * -_inP07ytvysR(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_manifest_get_int_value)((ManifestIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_element_name(ElementIndex element) - */ -static PyObject * -_inP07ytYQ_2(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_element_name)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_element_scoped_name(ElementIndex element) - */ -static PyObject * -_inP07yt3kdv(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_element_scoped_name)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_comment(ElementIndex element) - */ -static PyObject * -_inP07ytew01(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_comment)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_element_comment(ElementIndex element) - */ -static PyObject * -_inP07ytQna7(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_element_comment)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * ElementIndex interrogate_get_element_by_name(char const *element_name) - */ -static PyObject * -_inP07ytkg95(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - ElementIndex return_value = (::interrogate_get_element_by_name)((char const *)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * ElementIndex interrogate_get_element_by_scoped_name(char const *element_name) - */ -static PyObject * -_inP07ytluRc(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - ElementIndex return_value = (::interrogate_get_element_by_scoped_name)((char const *)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_element_type(ElementIndex element) - */ -static PyObject * -_inP07yttHdM(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_element_type)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_getter(ElementIndex element) - */ -static PyObject * -_inP07ytDId0(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_getter)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_getter(ElementIndex element) - */ -static PyObject * -_inP07ytHuAm(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_getter)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_setter(ElementIndex element) - */ -static PyObject * -_inP07yt_xr0(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_setter)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_setter(ElementIndex element) - */ -static PyObject * -_inP07ytH5qp(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_setter)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_has_function(ElementIndex element) - */ -static PyObject * -_inP07ytLfJw(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_has_function)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_has_function(ElementIndex element) - */ -static PyObject * -_inP07yt_Atg(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_has_function)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_clear_function(ElementIndex element) - */ -static PyObject * -_inP07ytlBqc(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_clear_function)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_clear_function(ElementIndex element) - */ -static PyObject * -_inP07ytNdUp(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_clear_function)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_del_function(ElementIndex element) - */ -static PyObject * -_inP07ytlS0p(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_del_function)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_del_function(ElementIndex element) - */ -static PyObject * -_inP07ytZZe7(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_del_function)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_insert_function(ElementIndex element) - */ -static PyObject * -_inP07ytV5S_(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_insert_function)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_insert_function(ElementIndex element) - */ -static PyObject * -_inP07yto9vD(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_insert_function)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_has_getkey_function(ElementIndex element) - */ -static PyObject * -_inP07ytv7tF(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_has_getkey_function)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_getkey_function(ElementIndex element) - */ -static PyObject * -_inP07ythOg6(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_getkey_function)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_element_length_function(ElementIndex element) - */ -static PyObject * -_inP07ytoZUn(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_element_length_function)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_is_sequence(ElementIndex element) - */ -static PyObject * -_inP07ytq45U(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_is_sequence)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_element_is_mapping(ElementIndex element) - */ -static PyObject * -_inP07yt6IPa(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_element_is_mapping)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_number_of_globals(void) - */ -static PyObject * -_inP07ytU2_B(PyObject *, PyObject *args) { - if (PyArg_ParseTuple(args, "")) { - int return_value = (::interrogate_number_of_globals)(); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * ElementIndex interrogate_get_global(int n) - */ -static PyObject * -_inP07ytHFO2(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - ElementIndex return_value = (::interrogate_get_global)((int)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_number_of_global_functions(void) - */ -static PyObject * -_inP07ytcfjm(PyObject *, PyObject *args) { - if (PyArg_ParseTuple(args, "")) { - int return_value = (::interrogate_number_of_global_functions)(); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_get_global_function(int n) - */ -static PyObject * -_inP07yt3Sjw(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_get_global_function)((int)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_number_of_functions(void) - */ -static PyObject * -_inP07ytgJcX(PyObject *, PyObject *args) { - if (PyArg_ParseTuple(args, "")) { - int return_value = (::interrogate_number_of_functions)(); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_get_function(int n) - */ -static PyObject * -_inP07ytYlw6(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_get_function)((int)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_function_name(FunctionIndex function) - */ -static PyObject * -_inP07ytsmnz(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_function_name)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_function_scoped_name(FunctionIndex function) - */ -static PyObject * -_inP07ytxQ10(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_function_scoped_name)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_has_comment(FunctionIndex function) - */ -static PyObject * -_inP07yt6gPB(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_has_comment)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_function_comment(FunctionIndex function) - */ -static PyObject * -_inP07ytISgV(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_function_comment)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_function_prototype(FunctionIndex function) - */ -static PyObject * -_inP07ytH3bx(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_function_prototype)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_is_method(FunctionIndex function) - */ -static PyObject * -_inP07ytzeUk(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_is_method)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_function_class(FunctionIndex function) - */ -static PyObject * -_inP07ytUeI5(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_function_class)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_is_unary_op(FunctionIndex function) - */ -static PyObject * -_inP07ytbmxJ(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_is_unary_op)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_is_operator_typecast(FunctionIndex function) - */ -static PyObject * -_inP07ytY8Lc(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_is_operator_typecast)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_is_constructor(FunctionIndex function) - */ -static PyObject * -_inP07ytJAAI(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_is_constructor)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_is_destructor(FunctionIndex function) - */ -static PyObject * -_inP07yt0UXw(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_is_destructor)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_has_module_name(FunctionIndex function) - */ -static PyObject * -_inP07ytuSvx(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_has_module_name)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_function_module_name(FunctionIndex function) - */ -static PyObject * -_inP07ytwpYd(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_function_module_name)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_has_library_name(FunctionIndex function) - */ -static PyObject * -_inP07ytOfNh(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_has_library_name)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_function_library_name(FunctionIndex function) - */ -static PyObject * -_inP07ytf5_U(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_function_library_name)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_function_is_virtual(FunctionIndex function) - */ -static PyObject * -_inP07ytL3ZB(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_function_is_virtual)((FunctionIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_function_number_of_c_wrappers(FunctionIndex function) - */ -static PyObject * -_inP07ytXw0I(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_function_number_of_c_wrappers)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionWrapperIndex interrogate_function_c_wrapper(FunctionIndex function, int n) - */ -static PyObject * -_inP07yt3zru(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - FunctionWrapperIndex return_value = (::interrogate_function_c_wrapper)((FunctionIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_function_number_of_python_wrappers(FunctionIndex function) - */ -static PyObject * -_inP07ytRrg2(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_function_number_of_python_wrappers)((FunctionIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionWrapperIndex interrogate_function_python_wrapper(FunctionIndex function, int n) - */ -static PyObject * -_inP07ytEJCx(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - FunctionWrapperIndex return_value = (::interrogate_function_python_wrapper)((FunctionIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_wrapper_name(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytWAZr(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_wrapper_name)((FunctionWrapperIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_wrapper_function(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytHQi6(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_wrapper_function)((FunctionWrapperIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_is_callable_by_name(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytrD_M(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_is_callable_by_name)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_is_copy_constructor(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytYaah(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_is_copy_constructor)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_is_coerce_constructor(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07yt2otr(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_is_coerce_constructor)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_is_extension(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytNP_b(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_is_extension)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_is_deprecated(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytrrrN(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_is_deprecated)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_has_comment(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytjolz(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_has_comment)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_wrapper_comment(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytt_JD(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_wrapper_comment)((FunctionWrapperIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_has_return_value(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytwEts(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_has_return_value)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_wrapper_return_type(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytrJWs(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_wrapper_return_type)((FunctionWrapperIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_caller_manages_return_value(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytpmFD(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_caller_manages_return_value)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_wrapper_return_value_destructor(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytyYUX(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_wrapper_return_value_destructor)((FunctionWrapperIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_wrapper_number_of_parameters(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07yt54dn(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_wrapper_number_of_parameters)((FunctionWrapperIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_wrapper_parameter_type(FunctionWrapperIndex wrapper, int n) - */ -static PyObject * -_inP07ytGMpW(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - TypeIndex return_value = (::interrogate_wrapper_parameter_type)((FunctionWrapperIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_parameter_has_name(FunctionWrapperIndex wrapper, int n) - */ -static PyObject * -_inP07ytNuBV(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - bool return_value = (::interrogate_wrapper_parameter_has_name)((FunctionWrapperIndex)param0, (int)param1); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_wrapper_parameter_name(FunctionWrapperIndex wrapper, int n) - */ -static PyObject * -_inP07yt9UwA(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - char const *return_value = (::interrogate_wrapper_parameter_name)((FunctionWrapperIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_parameter_is_this(FunctionWrapperIndex wrapper, int n) - */ -static PyObject * -_inP07yt3FDt(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - bool return_value = (::interrogate_wrapper_parameter_is_this)((FunctionWrapperIndex)param0, (int)param1); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_parameter_is_optional(FunctionWrapperIndex wrapper, int n) - */ -static PyObject * -_inP07ytDgOY(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - bool return_value = (::interrogate_wrapper_parameter_is_optional)((FunctionWrapperIndex)param0, (int)param1); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_wrapper_has_pointer(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytf513(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_wrapper_has_pointer)((FunctionWrapperIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * void *interrogate_wrapper_pointer(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07ytsqGH(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - (::interrogate_wrapper_pointer)((FunctionWrapperIndex)param0); - return Py_BuildValue(""); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_wrapper_unique_name(FunctionWrapperIndex wrapper) - */ -static PyObject * -_inP07yt7shV(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_wrapper_unique_name)((FunctionWrapperIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionWrapperIndex interrogate_get_wrapper_by_unique_name(char const *unique_name) - */ -static PyObject * -_inP07ytA1eF(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - FunctionWrapperIndex return_value = (::interrogate_get_wrapper_by_unique_name)((char const *)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_make_seq_seq_name(MakeSeqIndex make_seq) - */ -static PyObject * -_inP07yt776V(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_make_seq_seq_name)((MakeSeqIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_make_seq_scoped_name(MakeSeqIndex make_seq) - */ -static PyObject * -_inP07ytryup(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_make_seq_scoped_name)((MakeSeqIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_make_seq_has_comment(ElementIndex element) - */ -static PyObject * -_inP07ytiytI(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_make_seq_has_comment)((ElementIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_make_seq_comment(ElementIndex element) - */ -static PyObject * -_inP07ytZc07(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_make_seq_comment)((ElementIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_make_seq_num_name(MakeSeqIndex make_seq) - */ -static PyObject * -_inP07ytfaH0(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_make_seq_num_name)((MakeSeqIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_make_seq_element_name(MakeSeqIndex make_seq) - */ -static PyObject * -_inP07ytGB9D(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_make_seq_element_name)((MakeSeqIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_make_seq_num_getter(MakeSeqIndex make_seq) - */ -static PyObject * -_inP07ytrppS(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_make_seq_num_getter)((MakeSeqIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_make_seq_element_getter(MakeSeqIndex make_seq) - */ -static PyObject * -_inP07ytO50x(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_make_seq_element_getter)((MakeSeqIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_number_of_global_types(void) - */ -static PyObject * -_inP07ytsxxs(PyObject *, PyObject *args) { - if (PyArg_ParseTuple(args, "")) { - int return_value = (::interrogate_number_of_global_types)(); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_get_global_type(int n) - */ -static PyObject * -_inP07ytMT0z(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_get_global_type)((int)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_number_of_types(void) - */ -static PyObject * -_inP07ytiW3v(PyObject *, PyObject *args) { - if (PyArg_ParseTuple(args, "")) { - int return_value = (::interrogate_number_of_types)(); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_get_type(int n) - */ -static PyObject * -_inP07yt4Px8(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_get_type)((int)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_get_type_by_name(char const *type_name) - */ -static PyObject * -_inP07ytNHcs(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - TypeIndex return_value = (::interrogate_get_type_by_name)((char const *)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_get_type_by_scoped_name(char const *type_name) - */ -static PyObject * -_inP07ytqHrb(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - TypeIndex return_value = (::interrogate_get_type_by_scoped_name)((char const *)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_get_type_by_true_name(char const *type_name) - */ -static PyObject * -_inP07ytaOqq(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - TypeIndex return_value = (::interrogate_get_type_by_true_name)((char const *)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_global(TypeIndex type) - */ -static PyObject * -_inP07ytpTBb(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_global)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_deprecated(TypeIndex type) - */ -static PyObject * -_inP07ytZUkn(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_deprecated)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_name(TypeIndex type) - */ -static PyObject * -_inP07ytqWOw(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_type_name)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_scoped_name(TypeIndex type) - */ -static PyObject * -_inP07ytHu7x(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_type_scoped_name)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_true_name(TypeIndex type) - */ -static PyObject * -_inP07ytwGnA(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_type_true_name)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_nested(TypeIndex type) - */ -static PyObject * -_inP07ytXGxx(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_nested)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_type_outer_class(TypeIndex type) - */ -static PyObject * -_inP07ytj04Z(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_type_outer_class)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_has_comment(TypeIndex type) - */ -static PyObject * -_inP07ytEOv4(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_has_comment)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_comment(TypeIndex type) - */ -static PyObject * -_inP07ytpCqJ(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_type_comment)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_has_module_name(TypeIndex type) - */ -static PyObject * -_inP07yt_Pz3(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_has_module_name)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_module_name(TypeIndex type) - */ -static PyObject * -_inP07ytt_06(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_type_module_name)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_has_library_name(TypeIndex type) - */ -static PyObject * -_inP07ytmuPs(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_has_library_name)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_library_name(TypeIndex type) - */ -static PyObject * -_inP07ytvM8B(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - char const *return_value = (::interrogate_type_library_name)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_atomic(TypeIndex type) - */ -static PyObject * -_inP07ytap97(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_atomic)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * AtomicToken interrogate_type_atomic_token(TypeIndex type) - */ -static PyObject * -_inP07yt0o8D(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - AtomicToken return_value = (::interrogate_type_atomic_token)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_unsigned(TypeIndex type) - */ -static PyObject * -_inP07ytOoQ2(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_unsigned)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_signed(TypeIndex type) - */ -static PyObject * -_inP07ytKuFh(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_signed)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_long(TypeIndex type) - */ -static PyObject * -_inP07yto5L6(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_long)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_longlong(TypeIndex type) - */ -static PyObject * -_inP07ytzgKK(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_longlong)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_short(TypeIndex type) - */ -static PyObject * -_inP07yt0FIF(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_short)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_wrapped(TypeIndex type) - */ -static PyObject * -_inP07ytZqvD(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_wrapped)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_pointer(TypeIndex type) - */ -static PyObject * -_inP07ytDyRd(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_pointer)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_const(TypeIndex type) - */ -static PyObject * -_inP07ytMnKa(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_const)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_typedef(TypeIndex type) - */ -static PyObject * -_inP07ytRtji(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_typedef)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_type_wrapped_type(TypeIndex type) - */ -static PyObject * -_inP07ytCnbQ(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - TypeIndex return_value = (::interrogate_type_wrapped_type)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_array(TypeIndex type) - */ -static PyObject * -_inP07ytoxqc(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_array)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_array_size(TypeIndex type) - */ -static PyObject * -_inP07ytZQIS(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_array_size)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_enum(TypeIndex type) - */ -static PyObject * -_inP07ytdUVN(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_enum)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_scoped_enum(TypeIndex type) - */ -static PyObject * -_inP07ytZtNk(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_scoped_enum)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_enum_values(TypeIndex type) - */ -static PyObject * -_inP07ytihbt(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_enum_values)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_enum_value_name(TypeIndex type, int n) - */ -static PyObject * -_inP07ytbyPY(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - char const *return_value = (::interrogate_type_enum_value_name)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_enum_value_scoped_name(TypeIndex type, int n) - */ -static PyObject * -_inP07ytAaT6(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - char const *return_value = (::interrogate_type_enum_value_scoped_name)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * char const *interrogate_type_enum_value_comment(TypeIndex type, int n) - */ -static PyObject * -_inP07ytgL9q(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - char const *return_value = (::interrogate_type_enum_value_comment)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromString(return_value); -#else - return PyString_FromString(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_enum_value(TypeIndex type, int n) - */ -static PyObject * -_inP07ytWB97(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - int return_value = (::interrogate_type_enum_value)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_struct(TypeIndex type) - */ -static PyObject * -_inP07ytDUAl(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_struct)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_class(TypeIndex type) - */ -static PyObject * -_inP07yt1_Kf(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_class)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_union(TypeIndex type) - */ -static PyObject * -_inP07yt98lD(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_union)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_fully_defined(TypeIndex type) - */ -static PyObject * -_inP07yt9SHr(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_fully_defined)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_unpublished(TypeIndex type) - */ -static PyObject * -_inP07ytdiZP(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_unpublished)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_constructors(TypeIndex type) - */ -static PyObject * -_inP07ytTdER(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_constructors)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_type_get_constructor(TypeIndex type, int n) - */ -static PyObject * -_inP07ytYO56(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - FunctionIndex return_value = (::interrogate_type_get_constructor)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_has_destructor(TypeIndex type) - */ -static PyObject * -_inP07ytxtCG(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_has_destructor)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_destructor_is_inherited(TypeIndex type) - */ -static PyObject * -_inP07yt_EB2(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_destructor_is_inherited)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_type_get_destructor(TypeIndex type) - */ -static PyObject * -_inP07ytEG1l(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - FunctionIndex return_value = (::interrogate_type_get_destructor)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_elements(TypeIndex type) - */ -static PyObject * -_inP07yt7tUq(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_elements)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * ElementIndex interrogate_type_get_element(TypeIndex type, int n) - */ -static PyObject * -_inP07ytyStU(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - ElementIndex return_value = (::interrogate_type_get_element)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_methods(TypeIndex type) - */ -static PyObject * -_inP07ytdM85(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_methods)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_type_get_method(TypeIndex type, int n) - */ -static PyObject * -_inP07ytk_GN(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - FunctionIndex return_value = (::interrogate_type_get_method)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_make_seqs(TypeIndex type) - */ -static PyObject * -_inP07yt8QjG(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_make_seqs)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * MakeSeqIndex interrogate_type_get_make_seq(TypeIndex type, int n) - */ -static PyObject * -_inP07ytyMtj(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - MakeSeqIndex return_value = (::interrogate_type_get_make_seq)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_casts(TypeIndex type) - */ -static PyObject * -_inP07ytHDtN(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_casts)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_type_get_cast(TypeIndex type, int n) - */ -static PyObject * -_inP07ytHFjA(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - FunctionIndex return_value = (::interrogate_type_get_cast)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_derivations(TypeIndex type) - */ -static PyObject * -_inP07yt_NPR(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_derivations)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_type_get_derivation(TypeIndex type, int n) - */ -static PyObject * -_inP07ytcTOH(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - TypeIndex return_value = (::interrogate_type_get_derivation)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_is_final(TypeIndex type) - */ -static PyObject * -_inP07ytC5Uk(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - bool return_value = (::interrogate_type_is_final)((TypeIndex)param0); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_derivation_has_upcast(TypeIndex type, int n) - */ -static PyObject * -_inP07ythdU7(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - bool return_value = (::interrogate_type_derivation_has_upcast)((TypeIndex)param0, (int)param1); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_type_get_upcast(TypeIndex type, int n) - */ -static PyObject * -_inP07ytQPxU(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - FunctionIndex return_value = (::interrogate_type_get_upcast)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_derivation_downcast_is_impossible(TypeIndex type, int n) - */ -static PyObject * -_inP07ytO7Pz(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - bool return_value = (::interrogate_type_derivation_downcast_is_impossible)((TypeIndex)param0, (int)param1); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * bool interrogate_type_derivation_has_downcast(TypeIndex type, int n) - */ -static PyObject * -_inP07ytvu_E(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - bool return_value = (::interrogate_type_derivation_has_downcast)((TypeIndex)param0, (int)param1); - return PyBool_FromLong(return_value); - } - return nullptr; -} - -/* - * Python simple wrapper for - * FunctionIndex interrogate_type_get_downcast(TypeIndex type, int n) - */ -static PyObject * -_inP07ytxGUt(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - FunctionIndex return_value = (::interrogate_type_get_downcast)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * int interrogate_type_number_of_nested_types(TypeIndex type) - */ -static PyObject * -_inP07ytzM1P(PyObject *, PyObject *args) { - int param0; - if (PyArg_ParseTuple(args, "i", ¶m0)) { - int return_value = (::interrogate_type_number_of_nested_types)((TypeIndex)param0); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * TypeIndex interrogate_type_get_nested_type(TypeIndex type, int n) - */ -static PyObject * -_inP07ytoY5L(PyObject *, PyObject *args) { - int param0; - int param1; - if (PyArg_ParseTuple(args, "ii", ¶m0, ¶m1)) { - TypeIndex return_value = (::interrogate_type_get_nested_type)((TypeIndex)param0, (int)param1); -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(return_value); -#else - return PyInt_FromLong(return_value); -#endif - } - return nullptr; -} - -/* - * Python simple wrapper for - * void interrogate_request_database(char const *database_filename) - */ -static PyObject * -_inP07yte_7S(PyObject *, PyObject *args) { - char *param0; - if (PyArg_ParseTuple(args, "s", ¶m0)) { - (::interrogate_request_database)((char const *)param0); - return Py_BuildValue(""); - } - return nullptr; -} - -/* - * Python simple wrapper for - * void interrogate_request_module(InterrogateModuleDef *def) - */ -static PyObject * -_inP07ytw_15(PyObject *, PyObject *args) { - Py_ssize_t param0; - if (PyArg_ParseTuple(args, "n", ¶m0)) { - (::interrogate_request_module)((InterrogateModuleDef *)param0); - return Py_BuildValue(""); - } - return nullptr; -} - - -static PyMethodDef python_simple_funcs[] = { - { "interrogate_add_search_directory", &_inP07yttbRf, METH_VARARGS, nullptr }, - { "interrogate_add_search_path", &_inP07ytda_g, METH_VARARGS, nullptr }, - { "interrogate_error_flag", &_inP07yt4RgX, METH_VARARGS, nullptr }, - { "interrogate_number_of_manifests", &_inP07yt3Gip, METH_VARARGS, nullptr }, - { "interrogate_get_manifest", &_inP07ytRKDz, METH_VARARGS, nullptr }, - { "interrogate_get_manifest_by_name", &_inP07ytgZ9N, METH_VARARGS, nullptr }, - { "interrogate_manifest_name", &_inP07ytFnRZ, METH_VARARGS, nullptr }, - { "interrogate_manifest_definition", &_inP07ytg0Qv, METH_VARARGS, nullptr }, - { "interrogate_manifest_has_type", &_inP07yttrqw, METH_VARARGS, nullptr }, - { "interrogate_manifest_get_type", &_inP07ytdmpW, METH_VARARGS, nullptr }, - { "interrogate_manifest_has_getter", &_inP07ytUYgQ, METH_VARARGS, nullptr }, - { "interrogate_manifest_getter", &_inP07yt0k7F, METH_VARARGS, nullptr }, - { "interrogate_manifest_has_int_value", &_inP07ytfIsr, METH_VARARGS, nullptr }, - { "interrogate_manifest_get_int_value", &_inP07ytvysR, METH_VARARGS, nullptr }, - { "interrogate_element_name", &_inP07ytYQ_2, METH_VARARGS, nullptr }, - { "interrogate_element_scoped_name", &_inP07yt3kdv, METH_VARARGS, nullptr }, - { "interrogate_element_has_comment", &_inP07ytew01, METH_VARARGS, nullptr }, - { "interrogate_element_comment", &_inP07ytQna7, METH_VARARGS, nullptr }, - { "interrogate_get_element_by_name", &_inP07ytkg95, METH_VARARGS, nullptr }, - { "interrogate_get_element_by_scoped_name", &_inP07ytluRc, METH_VARARGS, nullptr }, - { "interrogate_element_type", &_inP07yttHdM, METH_VARARGS, nullptr }, - { "interrogate_element_has_getter", &_inP07ytDId0, METH_VARARGS, nullptr }, - { "interrogate_element_getter", &_inP07ytHuAm, METH_VARARGS, nullptr }, - { "interrogate_element_has_setter", &_inP07yt_xr0, METH_VARARGS, nullptr }, - { "interrogate_element_setter", &_inP07ytH5qp, METH_VARARGS, nullptr }, - { "interrogate_element_has_has_function", &_inP07ytLfJw, METH_VARARGS, nullptr }, - { "interrogate_element_has_function", &_inP07yt_Atg, METH_VARARGS, nullptr }, - { "interrogate_element_has_clear_function", &_inP07ytlBqc, METH_VARARGS, nullptr }, - { "interrogate_element_clear_function", &_inP07ytNdUp, METH_VARARGS, nullptr }, - { "interrogate_element_has_del_function", &_inP07ytlS0p, METH_VARARGS, nullptr }, - { "interrogate_element_del_function", &_inP07ytZZe7, METH_VARARGS, nullptr }, - { "interrogate_element_has_insert_function", &_inP07ytV5S_, METH_VARARGS, nullptr }, - { "interrogate_element_insert_function", &_inP07yto9vD, METH_VARARGS, nullptr }, - { "interrogate_element_has_getkey_function", &_inP07ytv7tF, METH_VARARGS, nullptr }, - { "interrogate_element_getkey_function", &_inP07ythOg6, METH_VARARGS, nullptr }, - { "interrogate_element_length_function", &_inP07ytoZUn, METH_VARARGS, nullptr }, - { "interrogate_element_is_sequence", &_inP07ytq45U, METH_VARARGS, nullptr }, - { "interrogate_element_is_mapping", &_inP07yt6IPa, METH_VARARGS, nullptr }, - { "interrogate_number_of_globals", &_inP07ytU2_B, METH_VARARGS, nullptr }, - { "interrogate_get_global", &_inP07ytHFO2, METH_VARARGS, nullptr }, - { "interrogate_number_of_global_functions", &_inP07ytcfjm, METH_VARARGS, nullptr }, - { "interrogate_get_global_function", &_inP07yt3Sjw, METH_VARARGS, nullptr }, - { "interrogate_number_of_functions", &_inP07ytgJcX, METH_VARARGS, nullptr }, - { "interrogate_get_function", &_inP07ytYlw6, METH_VARARGS, nullptr }, - { "interrogate_function_name", &_inP07ytsmnz, METH_VARARGS, nullptr }, - { "interrogate_function_scoped_name", &_inP07ytxQ10, METH_VARARGS, nullptr }, - { "interrogate_function_has_comment", &_inP07yt6gPB, METH_VARARGS, nullptr }, - { "interrogate_function_comment", &_inP07ytISgV, METH_VARARGS, nullptr }, - { "interrogate_function_prototype", &_inP07ytH3bx, METH_VARARGS, nullptr }, - { "interrogate_function_is_method", &_inP07ytzeUk, METH_VARARGS, nullptr }, - { "interrogate_function_class", &_inP07ytUeI5, METH_VARARGS, nullptr }, - { "interrogate_function_is_unary_op", &_inP07ytbmxJ, METH_VARARGS, nullptr }, - { "interrogate_function_is_operator_typecast", &_inP07ytY8Lc, METH_VARARGS, nullptr }, - { "interrogate_function_is_constructor", &_inP07ytJAAI, METH_VARARGS, nullptr }, - { "interrogate_function_is_destructor", &_inP07yt0UXw, METH_VARARGS, nullptr }, - { "interrogate_function_has_module_name", &_inP07ytuSvx, METH_VARARGS, nullptr }, - { "interrogate_function_module_name", &_inP07ytwpYd, METH_VARARGS, nullptr }, - { "interrogate_function_has_library_name", &_inP07ytOfNh, METH_VARARGS, nullptr }, - { "interrogate_function_library_name", &_inP07ytf5_U, METH_VARARGS, nullptr }, - { "interrogate_function_is_virtual", &_inP07ytL3ZB, METH_VARARGS, nullptr }, - { "interrogate_function_number_of_c_wrappers", &_inP07ytXw0I, METH_VARARGS, nullptr }, - { "interrogate_function_c_wrapper", &_inP07yt3zru, METH_VARARGS, nullptr }, - { "interrogate_function_number_of_python_wrappers", &_inP07ytRrg2, METH_VARARGS, nullptr }, - { "interrogate_function_python_wrapper", &_inP07ytEJCx, METH_VARARGS, nullptr }, - { "interrogate_wrapper_name", &_inP07ytWAZr, METH_VARARGS, nullptr }, - { "interrogate_wrapper_function", &_inP07ytHQi6, METH_VARARGS, nullptr }, - { "interrogate_wrapper_is_callable_by_name", &_inP07ytrD_M, METH_VARARGS, nullptr }, - { "interrogate_wrapper_is_copy_constructor", &_inP07ytYaah, METH_VARARGS, nullptr }, - { "interrogate_wrapper_is_coerce_constructor", &_inP07yt2otr, METH_VARARGS, nullptr }, - { "interrogate_wrapper_is_extension", &_inP07ytNP_b, METH_VARARGS, nullptr }, - { "interrogate_wrapper_is_deprecated", &_inP07ytrrrN, METH_VARARGS, nullptr }, - { "interrogate_wrapper_has_comment", &_inP07ytjolz, METH_VARARGS, nullptr }, - { "interrogate_wrapper_comment", &_inP07ytt_JD, METH_VARARGS, nullptr }, - { "interrogate_wrapper_has_return_value", &_inP07ytwEts, METH_VARARGS, nullptr }, - { "interrogate_wrapper_return_type", &_inP07ytrJWs, METH_VARARGS, nullptr }, - { "interrogate_wrapper_caller_manages_return_value", &_inP07ytpmFD, METH_VARARGS, nullptr }, - { "interrogate_wrapper_return_value_destructor", &_inP07ytyYUX, METH_VARARGS, nullptr }, - { "interrogate_wrapper_number_of_parameters", &_inP07yt54dn, METH_VARARGS, nullptr }, - { "interrogate_wrapper_parameter_type", &_inP07ytGMpW, METH_VARARGS, nullptr }, - { "interrogate_wrapper_parameter_has_name", &_inP07ytNuBV, METH_VARARGS, nullptr }, - { "interrogate_wrapper_parameter_name", &_inP07yt9UwA, METH_VARARGS, nullptr }, - { "interrogate_wrapper_parameter_is_this", &_inP07yt3FDt, METH_VARARGS, nullptr }, - { "interrogate_wrapper_parameter_is_optional", &_inP07ytDgOY, METH_VARARGS, nullptr }, - { "interrogate_wrapper_has_pointer", &_inP07ytf513, METH_VARARGS, nullptr }, - { "interrogate_wrapper_pointer", &_inP07ytsqGH, METH_VARARGS, nullptr }, - { "interrogate_wrapper_unique_name", &_inP07yt7shV, METH_VARARGS, nullptr }, - { "interrogate_get_wrapper_by_unique_name", &_inP07ytA1eF, METH_VARARGS, nullptr }, - { "interrogate_make_seq_seq_name", &_inP07yt776V, METH_VARARGS, nullptr }, - { "interrogate_make_seq_scoped_name", &_inP07ytryup, METH_VARARGS, nullptr }, - { "interrogate_make_seq_has_comment", &_inP07ytiytI, METH_VARARGS, nullptr }, - { "interrogate_make_seq_comment", &_inP07ytZc07, METH_VARARGS, nullptr }, - { "interrogate_make_seq_num_name", &_inP07ytfaH0, METH_VARARGS, nullptr }, - { "interrogate_make_seq_element_name", &_inP07ytGB9D, METH_VARARGS, nullptr }, - { "interrogate_make_seq_num_getter", &_inP07ytrppS, METH_VARARGS, nullptr }, - { "interrogate_make_seq_element_getter", &_inP07ytO50x, METH_VARARGS, nullptr }, - { "interrogate_number_of_global_types", &_inP07ytsxxs, METH_VARARGS, nullptr }, - { "interrogate_get_global_type", &_inP07ytMT0z, METH_VARARGS, nullptr }, - { "interrogate_number_of_types", &_inP07ytiW3v, METH_VARARGS, nullptr }, - { "interrogate_get_type", &_inP07yt4Px8, METH_VARARGS, nullptr }, - { "interrogate_get_type_by_name", &_inP07ytNHcs, METH_VARARGS, nullptr }, - { "interrogate_get_type_by_scoped_name", &_inP07ytqHrb, METH_VARARGS, nullptr }, - { "interrogate_get_type_by_true_name", &_inP07ytaOqq, METH_VARARGS, nullptr }, - { "interrogate_type_is_global", &_inP07ytpTBb, METH_VARARGS, nullptr }, - { "interrogate_type_is_deprecated", &_inP07ytZUkn, METH_VARARGS, nullptr }, - { "interrogate_type_name", &_inP07ytqWOw, METH_VARARGS, nullptr }, - { "interrogate_type_scoped_name", &_inP07ytHu7x, METH_VARARGS, nullptr }, - { "interrogate_type_true_name", &_inP07ytwGnA, METH_VARARGS, nullptr }, - { "interrogate_type_is_nested", &_inP07ytXGxx, METH_VARARGS, nullptr }, - { "interrogate_type_outer_class", &_inP07ytj04Z, METH_VARARGS, nullptr }, - { "interrogate_type_has_comment", &_inP07ytEOv4, METH_VARARGS, nullptr }, - { "interrogate_type_comment", &_inP07ytpCqJ, METH_VARARGS, nullptr }, - { "interrogate_type_has_module_name", &_inP07yt_Pz3, METH_VARARGS, nullptr }, - { "interrogate_type_module_name", &_inP07ytt_06, METH_VARARGS, nullptr }, - { "interrogate_type_has_library_name", &_inP07ytmuPs, METH_VARARGS, nullptr }, - { "interrogate_type_library_name", &_inP07ytvM8B, METH_VARARGS, nullptr }, - { "interrogate_type_is_atomic", &_inP07ytap97, METH_VARARGS, nullptr }, - { "interrogate_type_atomic_token", &_inP07yt0o8D, METH_VARARGS, nullptr }, - { "interrogate_type_is_unsigned", &_inP07ytOoQ2, METH_VARARGS, nullptr }, - { "interrogate_type_is_signed", &_inP07ytKuFh, METH_VARARGS, nullptr }, - { "interrogate_type_is_long", &_inP07yto5L6, METH_VARARGS, nullptr }, - { "interrogate_type_is_longlong", &_inP07ytzgKK, METH_VARARGS, nullptr }, - { "interrogate_type_is_short", &_inP07yt0FIF, METH_VARARGS, nullptr }, - { "interrogate_type_is_wrapped", &_inP07ytZqvD, METH_VARARGS, nullptr }, - { "interrogate_type_is_pointer", &_inP07ytDyRd, METH_VARARGS, nullptr }, - { "interrogate_type_is_const", &_inP07ytMnKa, METH_VARARGS, nullptr }, - { "interrogate_type_is_typedef", &_inP07ytRtji, METH_VARARGS, nullptr }, - { "interrogate_type_wrapped_type", &_inP07ytCnbQ, METH_VARARGS, nullptr }, - { "interrogate_type_is_array", &_inP07ytoxqc, METH_VARARGS, nullptr }, - { "interrogate_type_array_size", &_inP07ytZQIS, METH_VARARGS, nullptr }, - { "interrogate_type_is_enum", &_inP07ytdUVN, METH_VARARGS, nullptr }, - { "interrogate_type_is_scoped_enum", &_inP07ytZtNk, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_enum_values", &_inP07ytihbt, METH_VARARGS, nullptr }, - { "interrogate_type_enum_value_name", &_inP07ytbyPY, METH_VARARGS, nullptr }, - { "interrogate_type_enum_value_scoped_name", &_inP07ytAaT6, METH_VARARGS, nullptr }, - { "interrogate_type_enum_value_comment", &_inP07ytgL9q, METH_VARARGS, nullptr }, - { "interrogate_type_enum_value", &_inP07ytWB97, METH_VARARGS, nullptr }, - { "interrogate_type_is_struct", &_inP07ytDUAl, METH_VARARGS, nullptr }, - { "interrogate_type_is_class", &_inP07yt1_Kf, METH_VARARGS, nullptr }, - { "interrogate_type_is_union", &_inP07yt98lD, METH_VARARGS, nullptr }, - { "interrogate_type_is_fully_defined", &_inP07yt9SHr, METH_VARARGS, nullptr }, - { "interrogate_type_is_unpublished", &_inP07ytdiZP, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_constructors", &_inP07ytTdER, METH_VARARGS, nullptr }, - { "interrogate_type_get_constructor", &_inP07ytYO56, METH_VARARGS, nullptr }, - { "interrogate_type_has_destructor", &_inP07ytxtCG, METH_VARARGS, nullptr }, - { "interrogate_type_destructor_is_inherited", &_inP07yt_EB2, METH_VARARGS, nullptr }, - { "interrogate_type_get_destructor", &_inP07ytEG1l, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_elements", &_inP07yt7tUq, METH_VARARGS, nullptr }, - { "interrogate_type_get_element", &_inP07ytyStU, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_methods", &_inP07ytdM85, METH_VARARGS, nullptr }, - { "interrogate_type_get_method", &_inP07ytk_GN, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_make_seqs", &_inP07yt8QjG, METH_VARARGS, nullptr }, - { "interrogate_type_get_make_seq", &_inP07ytyMtj, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_casts", &_inP07ytHDtN, METH_VARARGS, nullptr }, - { "interrogate_type_get_cast", &_inP07ytHFjA, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_derivations", &_inP07yt_NPR, METH_VARARGS, nullptr }, - { "interrogate_type_get_derivation", &_inP07ytcTOH, METH_VARARGS, nullptr }, - { "interrogate_type_is_final", &_inP07ytC5Uk, METH_VARARGS, nullptr }, - { "interrogate_type_derivation_has_upcast", &_inP07ythdU7, METH_VARARGS, nullptr }, - { "interrogate_type_get_upcast", &_inP07ytQPxU, METH_VARARGS, nullptr }, - { "interrogate_type_derivation_downcast_is_impossible", &_inP07ytO7Pz, METH_VARARGS, nullptr }, - { "interrogate_type_derivation_has_downcast", &_inP07ytvu_E, METH_VARARGS, nullptr }, - { "interrogate_type_get_downcast", &_inP07ytxGUt, METH_VARARGS, nullptr }, - { "interrogate_type_number_of_nested_types", &_inP07ytzM1P, METH_VARARGS, nullptr }, - { "interrogate_type_get_nested_type", &_inP07ytoY5L, METH_VARARGS, nullptr }, - { "interrogate_request_database", &_inP07yte_7S, METH_VARARGS, nullptr }, - { "interrogate_request_module", &_inP07ytw_15, METH_VARARGS, nullptr }, - { nullptr, nullptr, 0, nullptr } -}; - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef python_simple_module = { - PyModuleDef_HEAD_INIT, - "panda3d.interrogatedb", - nullptr, - -1, - python_simple_funcs, - nullptr, nullptr, nullptr, nullptr -}; - -#define INIT_FUNC PyObject *PyInit_interrogatedb -#else -#define INIT_FUNC void initinterrogatedb -#endif - -#ifdef _WIN32 -extern "C" __declspec(dllexport) INIT_FUNC(); -#elif __GNUC__ >= 4 -extern "C" __attribute__((visibility("default"))) INIT_FUNC(); -#else -extern "C" INIT_FUNC(); -#endif - -INIT_FUNC() { -#if PY_MAJOR_VERSION >= 3 - return PyModule_Create(&python_simple_module); -#else - Py_InitModule("interrogatedb", python_simple_funcs); -#endif -} - diff --git a/dtool/src/cppparser/CMakeLists.txt b/dtool/src/cppparser/CMakeLists.txt deleted file mode 100644 index 08563df5086..00000000000 --- a/dtool/src/cppparser/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -set(P3CPPPARSER_HEADERS - cppAttributeList.h - 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 - cppAttributeList.cxx - 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}) diff --git a/dtool/src/cppparser/cppArrayType.cxx b/dtool/src/cppparser/cppArrayType.cxx deleted file mode 100644 index efd06f17b67..00000000000 --- a/dtool/src/cppparser/cppArrayType.cxx +++ /dev/null @@ -1,269 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppArrayType.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppArrayType.h" -#include "cppExpression.h" -#include "cppPointerType.h" - -/** - * - */ -CPPArrayType:: -CPPArrayType(CPPType *element_type, CPPExpression *bounds) : - CPPType(CPPFile()), - _element_type(element_type), - _bounds(bounds) -{ -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPArrayType:: -is_fully_specified() const { - return CPPType::is_fully_specified() && - _element_type->is_fully_specified(); -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPArrayType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPType *ptype = _element_type->resolve_type(current_scope, global_scope); - - if (ptype != _element_type) { - CPPArrayType *rep = new CPPArrayType(*this); - rep->_element_type = ptype; - return CPPType::new_type(rep); - } - return this; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPArrayType:: -is_tbd() const { - return _element_type->is_tbd(); -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPArrayType:: -is_standard_layout() const { - return _element_type->is_standard_layout(); -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPArrayType:: -is_trivial() const { - return _element_type->is_trivial(); -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPArrayType:: -is_trivially_copyable() const { - return _element_type->is_trivially_copyable(); -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPArrayType:: -is_default_constructible() const { - return _bounds != nullptr && _element_type->is_default_constructible(); -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPArrayType:: -is_copy_constructible() const { - // This is technically not exactly true, but array data members do not - // prevent C++ implicit copy constructor generation rules, so we need to - // return true here. - // If this is a problem, we will need to create a separate method for the - // purpose of checking copyability as a data member. - return true; -} - -/** - * Returns true if the type is copy-assignable. - */ -bool CPPArrayType:: -is_copy_assignable() const { - // Same story as is_copy_constructible. - return true; -} - -/** - * This is a little more forgiving than is_equal(): it returns true if the - * types appear to be referring to the same thing, even if they may have - * different pointers or somewhat different definitions. It's useful for - * parameter matching, etc. - */ -bool CPPArrayType:: -is_equivalent(const CPPType &other) const { - const CPPArrayType *ot = ((CPPType *)&other)->as_array_type(); - if (ot == nullptr) { - return CPPType::is_equivalent(other); - } - - return _element_type->is_equivalent(*ot->_element_type); -} - -/** - * - */ -CPPDeclaration *CPPArrayType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - return (*si).second; - } - - CPPArrayType *rep = new CPPArrayType(*this); - rep->_element_type = - _element_type->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - - if (_bounds != nullptr) { - rep->_bounds = - _bounds->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - } - - if (rep->_element_type == _element_type && - rep->_bounds == _bounds) { - delete rep; - rep = this; - } - rep = CPPType::new_type(rep)->as_array_type(); - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - -/** - * - */ -void CPPArrayType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - /* - _element_type->output(out, indent_level, scope, complete); - out << "["; - if (_bounds != NULL) { - out << *_bounds; - } - out << "]"; - */ - output_instance(out, indent_level, scope, complete, "", ""); -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPArrayType:: -output_instance(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const { - std::ostringstream brackets; - brackets << "["; - if (_bounds != nullptr) { - brackets << *_bounds; - } - brackets << "]"; - - if (!_attributes.is_empty()) { - brackets << " " << _attributes; - } - - std::string bracketsstr = brackets.str(); - - _element_type->output_instance(out, indent_level, scope, complete, - prename, name + bracketsstr); -} - -/** - * - */ -CPPDeclaration::SubType CPPArrayType:: -get_subtype() const { - return ST_array; -} - -/** - * - */ -CPPArrayType *CPPArrayType:: -as_array_type() { - return this; -} - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPArrayType:: -is_equal(const CPPDeclaration *other) const { - const CPPArrayType *ot = ((CPPDeclaration *)other)->as_array_type(); - assert(ot != nullptr); - - if (_bounds != nullptr && ot->_bounds != nullptr) { - if (*_bounds != *ot->_bounds) { - return false; - } - } else if ((_bounds == nullptr) != (ot->_bounds == nullptr)) { - return false; - } - - return *_element_type == *ot->_element_type; -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPArrayType:: -is_less(const CPPDeclaration *other) const { - const CPPArrayType *ot = ((CPPDeclaration *)other)->as_array_type(); - assert(ot != nullptr); - - if (_bounds != nullptr && ot->_bounds != nullptr) { - if (*_bounds != *ot->_bounds) { - return *_bounds < *ot->_bounds; - } - } else if ((_bounds == nullptr) != (ot->_bounds == nullptr)) { - return _bounds < ot->_bounds; - } - - if (*_element_type != *ot->_element_type) { - return *_element_type < *ot->_element_type; - } - return false; -} diff --git a/dtool/src/cppparser/cppArrayType.h b/dtool/src/cppparser/cppArrayType.h deleted file mode 100644 index 56afed1cbf2..00000000000 --- a/dtool/src/cppparser/cppArrayType.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppArrayType.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPARRAYTYPE_H -#define CPPARRAYTYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" - -class CPPExpression; - -/** - * - */ -class CPPArrayType : public CPPType { -public: - CPPArrayType(CPPType *element_type, CPPExpression *bounds); - - CPPType *_element_type; - CPPExpression *_bounds; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - virtual bool is_tbd() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_copy_assignable() const; - virtual bool is_equivalent(const CPPType &other) const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const; - - virtual SubType get_subtype() const; - - virtual CPPArrayType *as_array_type(); - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppAttributeList.cxx b/dtool/src/cppparser/cppAttributeList.cxx deleted file mode 100644 index 6a280d3cd74..00000000000 --- a/dtool/src/cppparser/cppAttributeList.cxx +++ /dev/null @@ -1,196 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppAttributeList.cxx - * @author rdb - * @date 2022-10-23 - */ - -#include "cppAttributeList.h" -#include "cppExpression.h" -#include "cppIdentifier.h" -#include "cppType.h" - -/** - * Returns true if no attributes have been defined. - */ -bool CPPAttributeList:: -is_empty() const { - return _attributes.empty() && _alignas == nullptr; -} - -/** - * Returns true if the attribute list has an attribute with the given name. - */ -bool CPPAttributeList:: -has_attribute(const std::string &name) const { - for (const Attribute &attr : _attributes) { - if (attr._ident->get_fully_scoped_name() == name) { - return true; - } - } - return false; -} - -/** - * - */ -bool CPPAttributeList:: -operator == (const CPPAttributeList &other) const { - if (_attributes.size() != other._attributes.size()) { - return false; - } - if ((_alignas != nullptr) != (other._alignas != nullptr)) { - return false; - } - if (_alignas != nullptr && *_alignas != *other._alignas) { - return false; - } - for (size_t i = 0; i < _attributes.size(); ++i) { - if (_attributes[i]._ident != other._attributes[i]._ident) { - return false; - } - if (_attributes[i]._reason != other._attributes[i]._reason) { - return false; - } - } - return true; -} - -/** - * - */ -bool CPPAttributeList:: -operator != (const CPPAttributeList &other) const { - return !(*this == other); -} - -/** - * - */ -bool CPPAttributeList:: -operator < (const CPPAttributeList &other) const { - if (_attributes.size() != other._attributes.size()) { - return _attributes.size() < other._attributes.size(); - } - if ((_alignas != nullptr) != (other._alignas != nullptr)) { - return _alignas == nullptr; - } - if (_alignas != nullptr && *_alignas != *other._alignas) { - return *_alignas < *other._alignas; - } - for (size_t i = 0; i < _attributes.size(); ++i) { - if (_attributes[i]._ident != other._attributes[i]._ident) { - return _attributes[i]._ident < other._attributes[i]._ident; - } - if (_attributes[i]._reason != other._attributes[i]._reason) { - return _attributes[i]._reason < other._attributes[i]._reason; - } - } - return false; -} - -/** - * Adds an attribute. - */ -void CPPAttributeList:: -add_attribute(CPPIdentifier *ident) { - _attributes.push_back({ident}); -} - -/** - * Adds an attribute. - */ -void CPPAttributeList:: -add_attribute(CPPIdentifier *ident, std::string reason) { - _attributes.push_back({ident, std::move(reason)}); -} - -/** - * Adds an alignas specifier. - */ -void CPPAttributeList:: -add_alignas(int size) { - if (_alignas == nullptr || size >= _alignas->evaluate().as_integer()) { - _alignas = new CPPExpression(size); - } -} - -/** - * Adds an alignas specifier. - */ -void CPPAttributeList:: -add_alignas(CPPType *type) { - CPPExpression expr = CPPExpression::alignof_func(type); - if (_alignas == nullptr || expr.evaluate().as_integer() > _alignas->evaluate().as_integer()) { - _alignas = new CPPExpression(expr); - } -} - -/** - * Adds an alignas specifier. - */ -void CPPAttributeList:: -add_alignas(CPPExpression *expr) { - if (_alignas == nullptr || expr->evaluate().as_integer() > _alignas->evaluate().as_integer()) { - _alignas = expr; - } -} - -/** - * Merges the other list into this one. - */ -void CPPAttributeList:: -add_attributes_from(const CPPAttributeList &other) { - for (const Attribute &attr : other._attributes) { - _attributes.push_back(attr); - } - - if (other._alignas != nullptr) { - add_alignas(other._alignas); - } -} - -/** - * - */ -void CPPAttributeList:: -output(std::ostream &out, CPPScope *scope) const { - Attributes::const_iterator it = _attributes.begin(); - if (it != _attributes.end()) { - out << "[["; - (*it)._ident->output(out, scope); - if (!(*it)._reason.empty()) { - out << "(" << (*it)._reason << ")"; - } - - for (++it; it != _attributes.end(); ++it) { - out << ", "; - (*it)._ident->output(out, scope); - if (!(*it)._reason.empty()) { - out << "(" << (*it)._reason << ")"; - } - } - - out << "]]"; - - if (_alignas != nullptr) { - out << " "; - } - } - - if (_alignas != nullptr) { - out << "alignas("; - if (_alignas->_type == CPPExpression::T_alignof) { - _alignas->_u._typecast._to->output(out, 0, scope, false); - } else { - _alignas->output(out, 0, scope, false); - } - out << ")"; - } -} diff --git a/dtool/src/cppparser/cppAttributeList.h b/dtool/src/cppparser/cppAttributeList.h deleted file mode 100644 index 9463b2b65c8..00000000000 --- a/dtool/src/cppparser/cppAttributeList.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppAttributeList.h - * @author rdb - * @date 2022-10-23 - */ - -#ifndef CPPATTRIBUTELIST_H -#define CPPATTRIBUTELIST_H - -#include "dtoolbase.h" - -#include - -class CPPExpression; -class CPPIdentifier; -class CPPScope; -class CPPType; - -/** - * A list of square-bracket attributes and/or alignas specifiers. - */ -class CPPAttributeList { -public: - bool is_empty() const; - bool has_attribute(const std::string &name) const; - - bool operator == (const CPPAttributeList &other) const; - bool operator != (const CPPAttributeList &other) const; - bool operator < (const CPPAttributeList &other) const; - - void add_attribute(CPPIdentifier *ident); - void add_attribute(CPPIdentifier *ident, std::string reason); - - void add_alignas(int size); - void add_alignas(CPPType *type); - void add_alignas(CPPExpression *expr); - - void add_attributes_from(const CPPAttributeList &other); - - struct Attribute { - CPPIdentifier *_ident; - std::string _reason; - }; - - typedef std::vector Attributes; - Attributes _attributes; - CPPExpression *_alignas = nullptr; - - void output(std::ostream &out, CPPScope *scope) const; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPAttributeList &alist) { - alist.output(out, nullptr); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppBison.cxx.prebuilt b/dtool/src/cppparser/cppBison.cxx.prebuilt deleted file mode 100644 index 0d94f44c79a..00000000000 --- a/dtool/src/cppparser/cppBison.cxx.prebuilt +++ /dev/null @@ -1,10080 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.8.2. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, - especially those whose name start with YY_ or yy_. They are - private implementation details that can be changed or removed. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output, and Bison version. */ -#define YYBISON 30802 - -/* Bison version string. */ -#define YYBISON_VERSION "3.8.2" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 2 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - -/* Substitute the variable and function names. */ -#define yyparse cppyyparse -#define yylex cppyylex -#define yyerror cppyyerror -#define yydebug cppyydebug -#define yynerrs cppyynerrs - -/* First part of user prologue. */ -#line 7 "dtool/src/cppparser/cppBison.yxx" - - -#include "cppBisonDefs.h" -#include "cppParser.h" -#include "cppClosureType.h" -#include "cppExpression.h" -#include "cppSimpleType.h" -#include "cppExtensionType.h" -#include "cppStructType.h" -#include "cppEnumType.h" -#include "cppFunctionType.h" -#include "cppTBDType.h" -#include "cppMakeProperty.h" -#include "cppMakeSeq.h" -#include "cppParameterList.h" -#include "cppInstance.h" -#include "cppClassTemplateParameter.h" -#include "cppTemplateParameterList.h" -#include "cppInstanceIdentifier.h" -#include "cppTypedefType.h" -#include "cppTypeDeclaration.h" -#include "cppVisibility.h" -#include "cppIdentifier.h" -#include "cppScope.h" -#include "cppTemplateScope.h" -#include "cppNamespace.h" -#include "cppUsing.h" - -using std::stringstream; -using std::string; - -//////////////////////////////////////////////////////////////////// -// Defining the interface to the parser. -//////////////////////////////////////////////////////////////////// - -CPPScope *current_scope = nullptr; -CPPScope *global_scope = nullptr; -CPPPreprocessor *current_lexer = nullptr; - -static CPPStructType *current_struct = nullptr; -static CPPEnumType *current_enum = nullptr; -static int current_storage_class = 0; -static CPPType *current_type = nullptr; -static CPPExpression *current_expr = nullptr; -static CPPAttributeList current_attributes; -static int publish_nest_level = 0; -static CPPVisibility publish_previous; -static YYLTYPE publish_loc; - -static std::vector last_scopes; -static std::vector last_storage_classes; -static std::vector last_structs; - -int yyparse(); - -#define YYERROR_VERBOSE - -static void -yyerror(const string &msg) { - current_lexer->error(msg, current_lexer->_last_token_loc); -} - -static void -yyerror(YYLTYPE *loc, const string &msg) { - current_lexer->error(msg, *loc); -} - -static void -yyerror(const string &msg, YYLTYPE &loc) { - current_lexer->error(msg, loc); -} - -static void -yywarning(const string &msg, YYLTYPE &loc) { - current_lexer->warning(msg, loc); -} - -static int -yylex(YYSTYPE *lval, YYLTYPE *lloc) { - CPPToken token = current_lexer->get_next_token(); - *lval = token._lval; - *lloc = token._lloc; - return token._token; -} - -void -parse_cpp(CPPParser *cp) { - CPPScope *old_scope = current_scope; - CPPScope *old_global_scope = global_scope; - CPPPreprocessor *old_lexer = current_lexer; - - current_scope = cp; - global_scope = cp; - current_lexer = cp; - publish_nest_level = 0; - yyparse(); - - if (publish_nest_level != 0) { - yyerror("Unclosed __begin_publish", publish_loc); - publish_nest_level = 0; - } - - current_scope = old_scope; - global_scope = old_global_scope; - current_lexer = old_lexer; - -} - -CPPExpression * -parse_const_expr(CPPPreprocessor *pp, CPPScope *new_current_scope, - CPPScope *new_global_scope) { - CPPScope *old_scope = current_scope; - CPPScope *old_global_scope = global_scope; - CPPPreprocessor *old_lexer = current_lexer; - CPPExpression *old_expr = current_expr; - - current_scope = new_current_scope; - global_scope = new_global_scope; - current_expr = nullptr; - current_lexer = pp; - yyparse(); - - CPPExpression *result = current_expr; - - current_scope = old_scope; - global_scope = old_global_scope; - current_lexer = old_lexer; - current_expr = old_expr; - - return result; -} - -CPPType * -parse_type(CPPPreprocessor *pp, CPPScope *new_current_scope, - CPPScope *new_global_scope) { - CPPScope *old_scope = current_scope; - CPPScope *old_global_scope = global_scope; - CPPPreprocessor *old_lexer = current_lexer; - CPPType *old_type = current_type; - - current_scope = new_current_scope; - global_scope = new_global_scope; - current_type = nullptr; - current_lexer = pp; - yyparse(); - - CPPType *result = current_type; - - current_scope = old_scope; - global_scope = old_global_scope; - current_lexer = old_lexer; - current_type = old_type; - - return result; -} - -static void -push_scope(CPPScope *new_scope) { - last_scopes.push_back(current_scope); - if (new_scope != nullptr) { - current_scope = new_scope; - } -} - -static void -pop_scope() { - assert(!last_scopes.empty()); - current_scope = last_scopes.back(); - last_scopes.pop_back(); -} - -static void -push_storage_class(int new_storage_class) { - last_storage_classes.push_back(current_storage_class); - current_storage_class = new_storage_class; -} - -static void -pop_storage_class() { - assert(!last_storage_classes.empty()); - current_storage_class = last_storage_classes.back(); - last_storage_classes.pop_back(); -} - -static void -push_struct(CPPStructType *new_struct) { - last_structs.push_back(current_struct); - current_struct = new_struct; -} - -static void -pop_struct() { - assert(!last_structs.empty()); - current_struct = last_structs.back(); - last_structs.pop_back(); -} - - -#line 275 "built/tmp/cppBison.yxx.c" - -# ifndef YY_CAST -# ifdef __cplusplus -# define YY_CAST(Type, Val) static_cast (Val) -# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) -# else -# define YY_CAST(Type, Val) ((Type) (Val)) -# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) -# endif -# endif -# ifndef YY_NULLPTR -# if defined __cplusplus -# if 201103L <= __cplusplus -# define YY_NULLPTR nullptr -# else -# define YY_NULLPTR 0 -# endif -# else -# define YY_NULLPTR ((void*)0) -# endif -# endif - -#include "cppBison.yxx.h" -/* Symbol kind. */ -enum yysymbol_kind_t -{ - YYSYMBOL_YYEMPTY = -2, - YYSYMBOL_YYEOF = 0, /* "end of file" */ - YYSYMBOL_YYerror = 1, /* error */ - YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ - YYSYMBOL_REAL = 3, /* REAL */ - YYSYMBOL_INTEGER = 4, /* INTEGER */ - YYSYMBOL_CHAR_TOK = 5, /* CHAR_TOK */ - YYSYMBOL_SIMPLE_STRING = 6, /* SIMPLE_STRING */ - YYSYMBOL_SIMPLE_IDENTIFIER = 7, /* SIMPLE_IDENTIFIER */ - YYSYMBOL_STRING_LITERAL = 8, /* STRING_LITERAL */ - YYSYMBOL_CUSTOM_LITERAL = 9, /* CUSTOM_LITERAL */ - YYSYMBOL_IDENTIFIER = 10, /* IDENTIFIER */ - YYSYMBOL_TYPENAME_IDENTIFIER = 11, /* TYPENAME_IDENTIFIER */ - YYSYMBOL_TYPEPACK_IDENTIFIER = 12, /* TYPEPACK_IDENTIFIER */ - YYSYMBOL_SCOPING = 13, /* SCOPING */ - YYSYMBOL_TYPEDEFNAME = 14, /* TYPEDEFNAME */ - YYSYMBOL_ELLIPSIS = 15, /* ELLIPSIS */ - YYSYMBOL_OROR = 16, /* OROR */ - YYSYMBOL_ANDAND = 17, /* ANDAND */ - YYSYMBOL_EQCOMPARE = 18, /* EQCOMPARE */ - YYSYMBOL_NECOMPARE = 19, /* NECOMPARE */ - YYSYMBOL_LECOMPARE = 20, /* LECOMPARE */ - YYSYMBOL_GECOMPARE = 21, /* GECOMPARE */ - YYSYMBOL_SPACESHIP = 22, /* SPACESHIP */ - YYSYMBOL_LSHIFT = 23, /* LSHIFT */ - YYSYMBOL_RSHIFT = 24, /* RSHIFT */ - YYSYMBOL_POINTSAT_STAR = 25, /* POINTSAT_STAR */ - YYSYMBOL_DOT_STAR = 26, /* DOT_STAR */ - YYSYMBOL_UNARY = 27, /* UNARY */ - YYSYMBOL_UNARY_NOT = 28, /* UNARY_NOT */ - YYSYMBOL_UNARY_NEGATE = 29, /* UNARY_NEGATE */ - YYSYMBOL_UNARY_MINUS = 30, /* UNARY_MINUS */ - YYSYMBOL_UNARY_PLUS = 31, /* UNARY_PLUS */ - YYSYMBOL_UNARY_STAR = 32, /* UNARY_STAR */ - YYSYMBOL_UNARY_REF = 33, /* UNARY_REF */ - YYSYMBOL_POINTSAT = 34, /* POINTSAT */ - YYSYMBOL_SCOPE = 35, /* SCOPE */ - YYSYMBOL_PLUSPLUS = 36, /* PLUSPLUS */ - YYSYMBOL_MINUSMINUS = 37, /* MINUSMINUS */ - YYSYMBOL_TIMESEQUAL = 38, /* TIMESEQUAL */ - YYSYMBOL_DIVIDEEQUAL = 39, /* DIVIDEEQUAL */ - YYSYMBOL_MODEQUAL = 40, /* MODEQUAL */ - YYSYMBOL_PLUSEQUAL = 41, /* PLUSEQUAL */ - YYSYMBOL_MINUSEQUAL = 42, /* MINUSEQUAL */ - YYSYMBOL_OREQUAL = 43, /* OREQUAL */ - YYSYMBOL_ANDEQUAL = 44, /* ANDEQUAL */ - YYSYMBOL_XOREQUAL = 45, /* XOREQUAL */ - YYSYMBOL_LSHIFTEQUAL = 46, /* LSHIFTEQUAL */ - YYSYMBOL_RSHIFTEQUAL = 47, /* RSHIFTEQUAL */ - YYSYMBOL_ATTR_LEFT = 48, /* ATTR_LEFT */ - YYSYMBOL_ATTR_RIGHT = 49, /* ATTR_RIGHT */ - YYSYMBOL_KW_ALIGNAS = 50, /* KW_ALIGNAS */ - YYSYMBOL_KW_ALIGNOF = 51, /* KW_ALIGNOF */ - YYSYMBOL_KW_AUTO = 52, /* KW_AUTO */ - YYSYMBOL_KW_BEGIN_PUBLISH = 53, /* KW_BEGIN_PUBLISH */ - YYSYMBOL_KW_BLOCKING = 54, /* KW_BLOCKING */ - YYSYMBOL_KW_BOOL = 55, /* KW_BOOL */ - YYSYMBOL_KW_BUILTIN_VA_LIST = 56, /* KW_BUILTIN_VA_LIST */ - YYSYMBOL_KW_CATCH = 57, /* KW_CATCH */ - YYSYMBOL_KW_CHAR = 58, /* KW_CHAR */ - YYSYMBOL_KW_CHAR8_T = 59, /* KW_CHAR8_T */ - YYSYMBOL_KW_CHAR16_T = 60, /* KW_CHAR16_T */ - YYSYMBOL_KW_CHAR32_T = 61, /* KW_CHAR32_T */ - YYSYMBOL_KW_CLASS = 62, /* KW_CLASS */ - YYSYMBOL_KW_CONST = 63, /* KW_CONST */ - YYSYMBOL_KW_CONSTEVAL = 64, /* KW_CONSTEVAL */ - YYSYMBOL_KW_CONSTEXPR = 65, /* KW_CONSTEXPR */ - YYSYMBOL_KW_CONSTINIT = 66, /* KW_CONSTINIT */ - YYSYMBOL_KW_CONST_CAST = 67, /* KW_CONST_CAST */ - YYSYMBOL_KW_DECLTYPE = 68, /* KW_DECLTYPE */ - YYSYMBOL_KW_DEFAULT = 69, /* KW_DEFAULT */ - YYSYMBOL_KW_DELETE = 70, /* KW_DELETE */ - YYSYMBOL_KW_DOUBLE = 71, /* KW_DOUBLE */ - YYSYMBOL_KW_DYNAMIC_CAST = 72, /* KW_DYNAMIC_CAST */ - YYSYMBOL_KW_ELSE = 73, /* KW_ELSE */ - YYSYMBOL_KW_END_PUBLISH = 74, /* KW_END_PUBLISH */ - YYSYMBOL_KW_ENUM = 75, /* KW_ENUM */ - YYSYMBOL_KW_EXTENSION = 76, /* KW_EXTENSION */ - YYSYMBOL_KW_EXTERN = 77, /* KW_EXTERN */ - YYSYMBOL_KW_EXPLICIT = 78, /* KW_EXPLICIT */ - YYSYMBOL_KW_EXPLICIT_LPAREN = 79, /* KW_EXPLICIT_LPAREN */ - YYSYMBOL_KW_PUBLISHED = 80, /* KW_PUBLISHED */ - YYSYMBOL_KW_FALSE = 81, /* KW_FALSE */ - YYSYMBOL_KW_FINAL = 82, /* KW_FINAL */ - YYSYMBOL_KW_FLOAT = 83, /* KW_FLOAT */ - YYSYMBOL_KW_FRIEND = 84, /* KW_FRIEND */ - YYSYMBOL_KW_FOR = 85, /* KW_FOR */ - YYSYMBOL_KW_GOTO = 86, /* KW_GOTO */ - YYSYMBOL_KW_HAS_VIRTUAL_DESTRUCTOR = 87, /* KW_HAS_VIRTUAL_DESTRUCTOR */ - YYSYMBOL_KW_IF = 88, /* KW_IF */ - YYSYMBOL_KW_INLINE = 89, /* KW_INLINE */ - YYSYMBOL_KW_INT = 90, /* KW_INT */ - YYSYMBOL_KW_IS_ABSTRACT = 91, /* KW_IS_ABSTRACT */ - YYSYMBOL_KW_IS_BASE_OF = 92, /* KW_IS_BASE_OF */ - YYSYMBOL_KW_IS_CLASS = 93, /* KW_IS_CLASS */ - YYSYMBOL_KW_IS_CONSTRUCTIBLE = 94, /* KW_IS_CONSTRUCTIBLE */ - YYSYMBOL_KW_IS_CONVERTIBLE_TO = 95, /* KW_IS_CONVERTIBLE_TO */ - YYSYMBOL_KW_IS_DESTRUCTIBLE = 96, /* KW_IS_DESTRUCTIBLE */ - YYSYMBOL_KW_IS_EMPTY = 97, /* KW_IS_EMPTY */ - YYSYMBOL_KW_IS_ENUM = 98, /* KW_IS_ENUM */ - YYSYMBOL_KW_IS_FINAL = 99, /* KW_IS_FINAL */ - YYSYMBOL_KW_IS_FUNDAMENTAL = 100, /* KW_IS_FUNDAMENTAL */ - YYSYMBOL_KW_IS_POD = 101, /* KW_IS_POD */ - YYSYMBOL_KW_IS_POLYMORPHIC = 102, /* KW_IS_POLYMORPHIC */ - YYSYMBOL_KW_IS_STANDARD_LAYOUT = 103, /* KW_IS_STANDARD_LAYOUT */ - YYSYMBOL_KW_IS_TRIVIAL = 104, /* KW_IS_TRIVIAL */ - YYSYMBOL_KW_IS_TRIVIALLY_COPYABLE = 105, /* KW_IS_TRIVIALLY_COPYABLE */ - YYSYMBOL_KW_IS_UNION = 106, /* KW_IS_UNION */ - YYSYMBOL_KW_LONG = 107, /* KW_LONG */ - YYSYMBOL_KW_MAKE_MAP_KEYS_SEQ = 108, /* KW_MAKE_MAP_KEYS_SEQ */ - YYSYMBOL_KW_MAKE_MAP_PROPERTY = 109, /* KW_MAKE_MAP_PROPERTY */ - YYSYMBOL_KW_MAKE_PROPERTY = 110, /* KW_MAKE_PROPERTY */ - YYSYMBOL_KW_MAKE_PROPERTY2 = 111, /* KW_MAKE_PROPERTY2 */ - YYSYMBOL_KW_MAKE_SEQ = 112, /* KW_MAKE_SEQ */ - YYSYMBOL_KW_MAKE_SEQ_PROPERTY = 113, /* KW_MAKE_SEQ_PROPERTY */ - YYSYMBOL_KW_MUTABLE = 114, /* KW_MUTABLE */ - YYSYMBOL_KW_NAMESPACE = 115, /* KW_NAMESPACE */ - YYSYMBOL_KW_NEW = 116, /* KW_NEW */ - YYSYMBOL_KW_NOEXCEPT = 117, /* KW_NOEXCEPT */ - YYSYMBOL_KW_NOEXCEPT_LPAREN = 118, /* KW_NOEXCEPT_LPAREN */ - YYSYMBOL_KW_NULLPTR = 119, /* KW_NULLPTR */ - YYSYMBOL_KW_OPERATOR = 120, /* KW_OPERATOR */ - YYSYMBOL_KW_OVERRIDE = 121, /* KW_OVERRIDE */ - YYSYMBOL_KW_PRIVATE = 122, /* KW_PRIVATE */ - YYSYMBOL_KW_PROTECTED = 123, /* KW_PROTECTED */ - YYSYMBOL_KW_PUBLIC = 124, /* KW_PUBLIC */ - YYSYMBOL_KW_REGISTER = 125, /* KW_REGISTER */ - YYSYMBOL_KW_REINTERPRET_CAST = 126, /* KW_REINTERPRET_CAST */ - YYSYMBOL_KW_RESTRICT = 127, /* KW_RESTRICT */ - YYSYMBOL_KW_RETURN = 128, /* KW_RETURN */ - YYSYMBOL_KW_SHORT = 129, /* KW_SHORT */ - YYSYMBOL_KW_SIGNED = 130, /* KW_SIGNED */ - YYSYMBOL_KW_SIZEOF = 131, /* KW_SIZEOF */ - YYSYMBOL_KW_STATIC = 132, /* KW_STATIC */ - YYSYMBOL_KW_STATIC_ASSERT = 133, /* KW_STATIC_ASSERT */ - YYSYMBOL_KW_STATIC_CAST = 134, /* KW_STATIC_CAST */ - YYSYMBOL_KW_STRUCT = 135, /* KW_STRUCT */ - YYSYMBOL_KW_TEMPLATE = 136, /* KW_TEMPLATE */ - YYSYMBOL_KW_THREAD_LOCAL = 137, /* KW_THREAD_LOCAL */ - YYSYMBOL_KW_THROW = 138, /* KW_THROW */ - YYSYMBOL_KW_TRUE = 139, /* KW_TRUE */ - YYSYMBOL_KW_TRY = 140, /* KW_TRY */ - YYSYMBOL_KW_TYPEDEF = 141, /* KW_TYPEDEF */ - YYSYMBOL_KW_TYPEID = 142, /* KW_TYPEID */ - YYSYMBOL_KW_TYPENAME = 143, /* KW_TYPENAME */ - YYSYMBOL_KW_UNDERLYING_TYPE = 144, /* KW_UNDERLYING_TYPE */ - YYSYMBOL_KW_UNION = 145, /* KW_UNION */ - YYSYMBOL_KW_UNSIGNED = 146, /* KW_UNSIGNED */ - YYSYMBOL_KW_USING = 147, /* KW_USING */ - YYSYMBOL_KW_VIRTUAL = 148, /* KW_VIRTUAL */ - YYSYMBOL_KW_VOID = 149, /* KW_VOID */ - YYSYMBOL_KW_VOLATILE = 150, /* KW_VOLATILE */ - YYSYMBOL_KW_WCHAR_T = 151, /* KW_WCHAR_T */ - YYSYMBOL_KW_WHILE = 152, /* KW_WHILE */ - YYSYMBOL_START_CPP = 153, /* START_CPP */ - YYSYMBOL_START_CONST_EXPR = 154, /* START_CONST_EXPR */ - YYSYMBOL_START_TYPE = 155, /* START_TYPE */ - YYSYMBOL_156_ = 156, /* '{' */ - YYSYMBOL_157_ = 157, /* ',' */ - YYSYMBOL_158_ = 158, /* ';' */ - YYSYMBOL_159_ = 159, /* ':' */ - YYSYMBOL_160_ = 160, /* '=' */ - YYSYMBOL_161_ = 161, /* '?' */ - YYSYMBOL_162_ = 162, /* '|' */ - YYSYMBOL_163_ = 163, /* '^' */ - YYSYMBOL_164_ = 164, /* '&' */ - YYSYMBOL_165_ = 165, /* '<' */ - YYSYMBOL_166_ = 166, /* '>' */ - YYSYMBOL_167_ = 167, /* '+' */ - YYSYMBOL_168_ = 168, /* '-' */ - YYSYMBOL_169_ = 169, /* '*' */ - YYSYMBOL_170_ = 170, /* '/' */ - YYSYMBOL_171_ = 171, /* '%' */ - YYSYMBOL_172_ = 172, /* '~' */ - YYSYMBOL_173_ = 173, /* '.' */ - YYSYMBOL_174_ = 174, /* '(' */ - YYSYMBOL_175_ = 175, /* '[' */ - YYSYMBOL_176_ = 176, /* ')' */ - YYSYMBOL_177_ = 177, /* '}' */ - YYSYMBOL_178_ = 178, /* '!' */ - YYSYMBOL_179_ = 179, /* ']' */ - YYSYMBOL_YYACCEPT = 180, /* $accept */ - YYSYMBOL_grammar = 181, /* grammar */ - YYSYMBOL_cpp = 182, /* cpp */ - YYSYMBOL_183_1 = 183, /* $@1 */ - YYSYMBOL_constructor_inits = 184, /* constructor_inits */ - YYSYMBOL_constructor_init = 185, /* constructor_init */ - YYSYMBOL_extern_c = 186, /* extern_c */ - YYSYMBOL_187_2 = 187, /* $@2 */ - YYSYMBOL_declaration = 188, /* declaration */ - YYSYMBOL_friend_declaration = 189, /* friend_declaration */ - YYSYMBOL_190_3 = 190, /* $@3 */ - YYSYMBOL_storage_class = 191, /* storage_class */ - YYSYMBOL_optional_attributes = 192, /* optional_attributes */ - YYSYMBOL_attribute_specifiers = 193, /* attribute_specifiers */ - YYSYMBOL_attribute_specifier = 194, /* attribute_specifier */ - YYSYMBOL_type_like_declaration = 195, /* type_like_declaration */ - YYSYMBOL_196_4 = 196, /* $@4 */ - YYSYMBOL_197_5 = 197, /* $@5 */ - YYSYMBOL_multiple_instance_identifiers = 198, /* multiple_instance_identifiers */ - YYSYMBOL_typedef_declaration = 199, /* typedef_declaration */ - YYSYMBOL_200_6 = 200, /* $@6 */ - YYSYMBOL_typedef_instance_identifiers = 201, /* typedef_instance_identifiers */ - YYSYMBOL_constructor_prototype = 202, /* constructor_prototype */ - YYSYMBOL_203_7 = 203, /* $@7 */ - YYSYMBOL_204_8 = 204, /* $@8 */ - YYSYMBOL_205_9 = 205, /* $@9 */ - YYSYMBOL_function_prototype = 206, /* function_prototype */ - YYSYMBOL_207_10 = 207, /* $@10 */ - YYSYMBOL_208_11 = 208, /* $@11 */ - YYSYMBOL_209_12 = 209, /* $@12 */ - YYSYMBOL_210_13 = 210, /* $@13 */ - YYSYMBOL_211_14 = 211, /* $@14 */ - YYSYMBOL_function_post = 212, /* function_post */ - YYSYMBOL_function_operator = 213, /* function_operator */ - YYSYMBOL_more_template_declaration = 214, /* more_template_declaration */ - YYSYMBOL_template_declaration = 215, /* template_declaration */ - YYSYMBOL_216_15 = 216, /* $@15 */ - YYSYMBOL_template_formal_parameters = 217, /* template_formal_parameters */ - YYSYMBOL_template_nonempty_formal_parameters = 218, /* template_nonempty_formal_parameters */ - YYSYMBOL_typename_keyword = 219, /* typename_keyword */ - YYSYMBOL_template_formal_parameter = 220, /* template_formal_parameter */ - YYSYMBOL_template_formal_parameter_type = 221, /* template_formal_parameter_type */ - YYSYMBOL_instance_identifier = 222, /* instance_identifier */ - YYSYMBOL_223_16 = 223, /* $@16 */ - YYSYMBOL_instance_identifier_and_maybe_trailing_return_type = 224, /* instance_identifier_and_maybe_trailing_return_type */ - YYSYMBOL_maybe_trailing_return_type = 225, /* maybe_trailing_return_type */ - YYSYMBOL_maybe_comma_identifier = 226, /* maybe_comma_identifier */ - YYSYMBOL_function_parameter_list = 227, /* function_parameter_list */ - YYSYMBOL_function_parameters = 228, /* function_parameters */ - YYSYMBOL_formal_parameter_list = 229, /* formal_parameter_list */ - YYSYMBOL_formal_parameters = 230, /* formal_parameters */ - YYSYMBOL_template_parameter_maybe_initialize = 231, /* template_parameter_maybe_initialize */ - YYSYMBOL_maybe_initialize = 232, /* maybe_initialize */ - YYSYMBOL_maybe_initialize_or_constructor_body = 233, /* maybe_initialize_or_constructor_body */ - YYSYMBOL_maybe_initialize_or_function_body = 234, /* maybe_initialize_or_function_body */ - YYSYMBOL_structure_init = 235, /* structure_init */ - YYSYMBOL_structure_init_body = 236, /* structure_init_body */ - YYSYMBOL_function_parameter = 237, /* function_parameter */ - YYSYMBOL_formal_parameter = 238, /* formal_parameter */ - YYSYMBOL_not_paren_formal_parameter_identifier = 239, /* not_paren_formal_parameter_identifier */ - YYSYMBOL_formal_parameter_identifier = 240, /* formal_parameter_identifier */ - YYSYMBOL_parameter_pack_identifier = 241, /* parameter_pack_identifier */ - YYSYMBOL_not_paren_empty_instance_identifier = 242, /* not_paren_empty_instance_identifier */ - YYSYMBOL_empty_instance_identifier = 243, /* empty_instance_identifier */ - YYSYMBOL_type = 244, /* type */ - YYSYMBOL_type_pack = 245, /* type_pack */ - YYSYMBOL_type_decl = 246, /* type_decl */ - YYSYMBOL_predefined_type = 247, /* predefined_type */ - YYSYMBOL_var_type_decl = 248, /* var_type_decl */ - YYSYMBOL_full_type = 249, /* full_type */ - YYSYMBOL_anonymous_struct = 250, /* anonymous_struct */ - YYSYMBOL_251_17 = 251, /* $@17 */ - YYSYMBOL_named_struct = 252, /* named_struct */ - YYSYMBOL_253_18 = 253, /* $@18 */ - YYSYMBOL_maybe_final = 254, /* maybe_final */ - YYSYMBOL_maybe_class_derivation = 255, /* maybe_class_derivation */ - YYSYMBOL_class_derivation = 256, /* class_derivation */ - YYSYMBOL_base_specification = 257, /* base_specification */ - YYSYMBOL_enum = 258, /* enum */ - YYSYMBOL_259_19 = 259, /* $@19 */ - YYSYMBOL_enum_decl = 260, /* enum_decl */ - YYSYMBOL_enum_element_type = 261, /* enum_element_type */ - YYSYMBOL_enum_body_trailing_comma = 262, /* enum_body_trailing_comma */ - YYSYMBOL_enum_body = 263, /* enum_body */ - YYSYMBOL_enum_keyword = 264, /* enum_keyword */ - YYSYMBOL_struct_keyword = 265, /* struct_keyword */ - YYSYMBOL_namespace_declaration = 266, /* namespace_declaration */ - YYSYMBOL_267_20 = 267, /* $@20 */ - YYSYMBOL_268_21 = 268, /* $@21 */ - YYSYMBOL_using_declaration = 269, /* using_declaration */ - YYSYMBOL_simple_type = 270, /* simple_type */ - YYSYMBOL_simple_int_type = 271, /* simple_int_type */ - YYSYMBOL_simple_float_type = 272, /* simple_float_type */ - YYSYMBOL_simple_void_type = 273, /* simple_void_type */ - YYSYMBOL_code = 274, /* code */ - YYSYMBOL_275_22 = 275, /* $@22 */ - YYSYMBOL_code_block = 276, /* code_block */ - YYSYMBOL_element = 277, /* element */ - YYSYMBOL_optional_const_expr = 278, /* optional_const_expr */ - YYSYMBOL_optional_const_expr_comma = 279, /* optional_const_expr_comma */ - YYSYMBOL_const_expr_comma = 280, /* const_expr_comma */ - YYSYMBOL_no_angle_bracket_const_expr = 281, /* no_angle_bracket_const_expr */ - YYSYMBOL_const_expr = 282, /* const_expr */ - YYSYMBOL_const_operand = 283, /* const_operand */ - YYSYMBOL_formal_const_expr = 284, /* formal_const_expr */ - YYSYMBOL_formal_const_operand = 285, /* formal_const_operand */ - YYSYMBOL_capture_list = 286, /* capture_list */ - YYSYMBOL_capture = 287, /* capture */ - YYSYMBOL_class_derivation_name = 288, /* class_derivation_name */ - YYSYMBOL_name = 289, /* name */ - YYSYMBOL_name_no_final = 290, /* name_no_final */ - YYSYMBOL_string_literal = 291, /* string_literal */ - YYSYMBOL_empty = 292 /* empty */ -}; -typedef enum yysymbol_kind_t yysymbol_kind_t; - - - - -#ifdef short -# undef short -#endif - -/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure - and (if available) are included - so that the code can choose integer types of a good width. */ - -#ifndef __PTRDIFF_MAX__ -# include /* INFRINGES ON USER NAME SPACE */ -# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_STDINT_H -# endif -#endif - -/* Narrow types that promote to a signed type and that can represent a - signed or unsigned integer of at least N bits. In tables they can - save space and decrease cache pressure. Promoting to a signed type - helps avoid bugs in integer arithmetic. */ - -#ifdef __INT_LEAST8_MAX__ -typedef __INT_LEAST8_TYPE__ yytype_int8; -#elif defined YY_STDINT_H -typedef int_least8_t yytype_int8; -#else -typedef signed char yytype_int8; -#endif - -#ifdef __INT_LEAST16_MAX__ -typedef __INT_LEAST16_TYPE__ yytype_int16; -#elif defined YY_STDINT_H -typedef int_least16_t yytype_int16; -#else -typedef short yytype_int16; -#endif - -/* Work around bug in HP-UX 11.23, which defines these macros - incorrectly for preprocessor constants. This workaround can likely - be removed in 2023, as HPE has promised support for HP-UX 11.23 - (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of - . */ -#ifdef __hpux -# undef UINT_LEAST8_MAX -# undef UINT_LEAST16_MAX -# define UINT_LEAST8_MAX 255 -# define UINT_LEAST16_MAX 65535 -#endif - -#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ -typedef __UINT_LEAST8_TYPE__ yytype_uint8; -#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ - && UINT_LEAST8_MAX <= INT_MAX) -typedef uint_least8_t yytype_uint8; -#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX -typedef unsigned char yytype_uint8; -#else -typedef short yytype_uint8; -#endif - -#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ -typedef __UINT_LEAST16_TYPE__ yytype_uint16; -#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ - && UINT_LEAST16_MAX <= INT_MAX) -typedef uint_least16_t yytype_uint16; -#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX -typedef unsigned short yytype_uint16; -#else -typedef int yytype_uint16; -#endif - -#ifndef YYPTRDIFF_T -# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ -# define YYPTRDIFF_T __PTRDIFF_TYPE__ -# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ -# elif defined PTRDIFF_MAX -# ifndef ptrdiff_t -# include /* INFRINGES ON USER NAME SPACE */ -# endif -# define YYPTRDIFF_T ptrdiff_t -# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX -# else -# define YYPTRDIFF_T long -# define YYPTRDIFF_MAXIMUM LONG_MAX -# endif -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned -# endif -#endif - -#define YYSIZE_MAXIMUM \ - YY_CAST (YYPTRDIFF_T, \ - (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ - ? YYPTRDIFF_MAXIMUM \ - : YY_CAST (YYSIZE_T, -1))) - -#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) - - -/* Stored state numbers (used for stacks). */ -typedef yytype_int16 yy_state_t; - -/* State numbers in computations. */ -typedef int yy_state_fast_t; - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) -# endif -# endif -# ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - - -#ifndef YY_ATTRIBUTE_PURE -# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) -# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) -# else -# define YY_ATTRIBUTE_PURE -# endif -#endif - -#ifndef YY_ATTRIBUTE_UNUSED -# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) -# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -# else -# define YY_ATTRIBUTE_UNUSED -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YY_USE(E) ((void) (E)) -#else -# define YY_USE(E) /* empty */ -#endif - -/* Suppress an incorrect diagnostic about yylval being uninitialized. */ -#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ -# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") -# else -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ - _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# endif -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ - _Pragma ("GCC diagnostic pop") -#else -# define YY_INITIAL_VALUE(Value) Value -#endif -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - -#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ -# define YY_IGNORE_USELESS_CAST_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") -# define YY_IGNORE_USELESS_CAST_END \ - _Pragma ("GCC diagnostic pop") -#endif -#ifndef YY_IGNORE_USELESS_CAST_BEGIN -# define YY_IGNORE_USELESS_CAST_BEGIN -# define YY_IGNORE_USELESS_CAST_END -#endif - - -#define YY_ASSERT(E) ((void) (0 && (E))) - -#if !defined yyoverflow - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's 'empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* !defined yyoverflow */ - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ - && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yy_state_t yyss_alloc; - YYSTYPE yyvs_alloc; - YYLTYPE yyls_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ - + YYSIZEOF (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYPTRDIFF_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / YYSIZEOF (*yyptr); \ - } \ - while (0) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYPTRDIFF_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (0) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 109 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 6863 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 180 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 113 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 789 -/* YYNSTATES -- Number of states. */ -#define YYNSTATES 1678 - -/* YYMAXUTOK -- Last valid token kind. */ -#define YYMAXUTOK 410 - - -/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, with out-of-bounds checking. */ -#define YYTRANSLATE(YYX) \ - (0 <= (YYX) && (YYX) <= YYMAXUTOK \ - ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ - : YYSYMBOL_YYUNDEF) - -/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 178, 2, 2, 2, 171, 164, 2, - 174, 176, 169, 167, 157, 168, 173, 170, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 159, 158, - 165, 160, 166, 161, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 175, 2, 179, 163, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 156, 162, 177, 172, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155 -}; - -#if YYDEBUG -/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_int16 yyrline[] = -{ - 0, 466, 466, 467, 471, 478, 479, 486, 485, 496, - 497, 501, 505, 509, 522, 521, 533, 534, 535, 536, - 537, 538, 539, 552, 561, 565, 573, 577, 581, 602, - 629, 650, 679, 715, 758, 770, 791, 827, 861, 883, - 919, 941, 952, 966, 965, 980, 984, 989, 993, 1004, - 1008, 1012, 1016, 1020, 1029, 1033, 1037, 1041, 1045, 1049, - 1053, 1057, 1061, 1068, 1072, 1077, 1085, 1090, 1098, 1102, - 1110, 1115, 1124, 1123, 1139, 1149, 1148, 1165, 1173, 1181, - 1193, 1210, 1209, 1224, 1239, 1249, 1265, 1264, 1307, 1306, - 1335, 1334, 1372, 1371, 1403, 1402, 1422, 1421, 1443, 1442, - 1475, 1474, 1501, 1514, 1518, 1522, 1526, 1530, 1539, 1543, - 1547, 1551, 1555, 1560, 1565, 1569, 1573, 1580, 1584, 1588, - 1592, 1596, 1600, 1604, 1608, 1612, 1616, 1620, 1624, 1628, - 1632, 1636, 1640, 1644, 1648, 1652, 1656, 1660, 1664, 1668, - 1672, 1676, 1680, 1684, 1688, 1692, 1696, 1700, 1704, 1708, - 1712, 1716, 1720, 1724, 1728, 1732, 1736, 1743, 1744, 1745, - 1749, 1751, 1750, 1758, 1759, 1763, 1764, 1768, 1774, 1783, - 1784, 1788, 1792, 1796, 1800, 1806, 1812, 1818, 1825, 1830, - 1836, 1843, 1852, 1856, 1861, 1869, 1881, 1885, 1899, 1914, - 1919, 1924, 1929, 1934, 1939, 1944, 1949, 1955, 1954, 1985, - 1995, 2005, 2009, 2013, 2022, 2026, 2034, 2038, 2043, 2047, - 2052, 2060, 2065, 2073, 2077, 2082, 2086, 2091, 2099, 2104, - 2112, 2116, 2123, 2127, 2134, 2138, 2142, 2146, 2150, 2157, - 2161, 2165, 2169, 2173, 2177, 2184, 2185, 2186, 2190, 2193, - 2194, 2195, 2199, 2211, 2230, 2234, 2244, 2248, 2252, 2257, - 2262, 2267, 2272, 2277, 2282, 2287, 2295, 2299, 2303, 2308, - 2313, 2318, 2323, 2328, 2333, 2338, 2343, 2349, 2357, 2362, - 2367, 2372, 2377, 2382, 2387, 2392, 2397, 2402, 2407, 2413, - 2421, 2425, 2430, 2435, 2440, 2445, 2450, 2455, 2460, 2465, - 2470, 2478, 2482, 2487, 2492, 2497, 2502, 2507, 2512, 2517, - 2522, 2527, 2532, 2538, 2545, 2552, 2562, 2566, 2574, 2578, - 2582, 2586, 2590, 2606, 2622, 2631, 2635, 2645, 2649, 2656, - 2667, 2671, 2679, 2683, 2687, 2691, 2695, 2711, 2727, 2745, - 2754, 2758, 2768, 2772, 2779, 2783, 2791, 2795, 2811, 2827, - 2836, 2846, 2850, 2857, 2861, 2869, 2873, 2878, 2882, 2891, - 2890, 2915, 2914, 2944, 2945, 2952, 2953, 2957, 2958, 2962, - 2966, 2970, 2974, 2978, 2982, 2986, 2990, 2994, 2998, 3006, - 3005, 3022, 3026, 3030, 3035, 3043, 3047, 3054, 3055, 3060, - 3067, 3068, 3073, 3081, 3085, 3089, 3096, 3100, 3104, 3112, - 3111, 3134, 3133, 3156, 3157, 3161, 3167, 3174, 3180, 3189, - 3190, 3191, 3195, 3199, 3203, 3207, 3211, 3215, 3219, 3224, - 3229, 3234, 3239, 3243, 3248, 3257, 3262, 3270, 3274, 3278, - 3286, 3296, 3296, 3306, 3307, 3311, 3312, 3313, 3314, 3315, - 3316, 3317, 3318, 3319, 3320, 3321, 3322, 3322, 3322, 3323, - 3323, 3323, 3323, 3323, 3324, 3324, 3324, 3324, 3324, 3325, - 3325, 3325, 3326, 3326, 3326, 3326, 3326, 3327, 3327, 3327, - 3327, 3327, 3328, 3328, 3329, 3329, 3329, 3329, 3329, 3330, - 3330, 3330, 3330, 3330, 3330, 3331, 3331, 3331, 3331, 3331, - 3332, 3332, 3332, 3332, 3332, 3333, 3333, 3333, 3333, 3333, - 3334, 3334, 3334, 3334, 3334, 3335, 3335, 3335, 3335, 3335, - 3335, 3336, 3336, 3336, 3336, 3336, 3337, 3337, 3337, 3337, - 3338, 3338, 3338, 3338, 3339, 3339, 3339, 3339, 3339, 3339, - 3340, 3340, 3340, 3340, 3341, 3341, 3341, 3341, 3341, 3342, - 3342, 3342, 3342, 3343, 3343, 3343, 3343, 3343, 3344, 3344, - 3347, 3347, 3347, 3347, 3347, 3347, 3347, 3347, 3347, 3347, - 3347, 3348, 3348, 3348, 3348, 3348, 3348, 3348, 3348, 3348, - 3348, 3349, 3349, 3353, 3357, 3364, 3368, 3375, 3379, 3386, - 3390, 3394, 3398, 3402, 3406, 3410, 3414, 3418, 3422, 3426, - 3430, 3434, 3438, 3442, 3446, 3450, 3454, 3458, 3462, 3466, - 3470, 3474, 3478, 3482, 3486, 3490, 3494, 3498, 3502, 3506, - 3510, 3514, 3518, 3522, 3526, 3530, 3534, 3538, 3542, 3550, - 3554, 3558, 3562, 3566, 3570, 3574, 3584, 3594, 3600, 3606, - 3612, 3618, 3624, 3630, 3636, 3643, 3650, 3657, 3664, 3670, - 3676, 3680, 3684, 3688, 3692, 3696, 3700, 3711, 3722, 3726, - 3730, 3734, 3738, 3742, 3746, 3750, 3754, 3758, 3762, 3766, - 3770, 3774, 3778, 3782, 3786, 3790, 3794, 3798, 3802, 3806, - 3810, 3814, 3818, 3822, 3826, 3830, 3834, 3838, 3842, 3846, - 3850, 3857, 3861, 3865, 3869, 3873, 3877, 3881, 3885, 3889, - 3895, 3901, 3905, 3912, 3920, 3924, 3928, 3932, 3936, 3940, - 3944, 3948, 3952, 3956, 3960, 3964, 3968, 3972, 3976, 3980, - 3984, 3988, 4002, 4006, 4010, 4014, 4018, 4022, 4026, 4030, - 4034, 4038, 4042, 4046, 4050, 4061, 4072, 4076, 4080, 4084, - 4088, 4092, 4096, 4100, 4104, 4108, 4112, 4116, 4120, 4124, - 4128, 4132, 4136, 4140, 4144, 4148, 4152, 4156, 4160, 4164, - 4168, 4172, 4176, 4180, 4184, 4188, 4192, 4199, 4203, 4207, - 4211, 4215, 4219, 4223, 4227, 4231, 4237, 4243, 4251, 4255, - 4259, 4263, 4270, 4280, 4286, 4292, 4302, 4314, 4322, 4326, - 4356, 4360, 4364, 4368, 4372, 4376, 4382, 4386, 4390, 4394, - 4398, 4409, 4413, 4417, 4421, 4429, 4433, 4437, 4443, 4454 -}; -#endif - -/** Accessing symbol of state STATE. */ -#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) - -#if YYDEBUG || 0 -/* The user-facing name of the symbol whose (internal) number is - YYSYMBOL. No bounds checking. */ -static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; - -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "\"end of file\"", "error", "\"invalid token\"", "REAL", "INTEGER", - "CHAR_TOK", "SIMPLE_STRING", "SIMPLE_IDENTIFIER", "STRING_LITERAL", - "CUSTOM_LITERAL", "IDENTIFIER", "TYPENAME_IDENTIFIER", - "TYPEPACK_IDENTIFIER", "SCOPING", "TYPEDEFNAME", "ELLIPSIS", "OROR", - "ANDAND", "EQCOMPARE", "NECOMPARE", "LECOMPARE", "GECOMPARE", - "SPACESHIP", "LSHIFT", "RSHIFT", "POINTSAT_STAR", "DOT_STAR", "UNARY", - "UNARY_NOT", "UNARY_NEGATE", "UNARY_MINUS", "UNARY_PLUS", "UNARY_STAR", - "UNARY_REF", "POINTSAT", "SCOPE", "PLUSPLUS", "MINUSMINUS", "TIMESEQUAL", - "DIVIDEEQUAL", "MODEQUAL", "PLUSEQUAL", "MINUSEQUAL", "OREQUAL", - "ANDEQUAL", "XOREQUAL", "LSHIFTEQUAL", "RSHIFTEQUAL", "ATTR_LEFT", - "ATTR_RIGHT", "KW_ALIGNAS", "KW_ALIGNOF", "KW_AUTO", "KW_BEGIN_PUBLISH", - "KW_BLOCKING", "KW_BOOL", "KW_BUILTIN_VA_LIST", "KW_CATCH", "KW_CHAR", - "KW_CHAR8_T", "KW_CHAR16_T", "KW_CHAR32_T", "KW_CLASS", "KW_CONST", - "KW_CONSTEVAL", "KW_CONSTEXPR", "KW_CONSTINIT", "KW_CONST_CAST", - "KW_DECLTYPE", "KW_DEFAULT", "KW_DELETE", "KW_DOUBLE", "KW_DYNAMIC_CAST", - "KW_ELSE", "KW_END_PUBLISH", "KW_ENUM", "KW_EXTENSION", "KW_EXTERN", - "KW_EXPLICIT", "KW_EXPLICIT_LPAREN", "KW_PUBLISHED", "KW_FALSE", - "KW_FINAL", "KW_FLOAT", "KW_FRIEND", "KW_FOR", "KW_GOTO", - "KW_HAS_VIRTUAL_DESTRUCTOR", "KW_IF", "KW_INLINE", "KW_INT", - "KW_IS_ABSTRACT", "KW_IS_BASE_OF", "KW_IS_CLASS", "KW_IS_CONSTRUCTIBLE", - "KW_IS_CONVERTIBLE_TO", "KW_IS_DESTRUCTIBLE", "KW_IS_EMPTY", - "KW_IS_ENUM", "KW_IS_FINAL", "KW_IS_FUNDAMENTAL", "KW_IS_POD", - "KW_IS_POLYMORPHIC", "KW_IS_STANDARD_LAYOUT", "KW_IS_TRIVIAL", - "KW_IS_TRIVIALLY_COPYABLE", "KW_IS_UNION", "KW_LONG", - "KW_MAKE_MAP_KEYS_SEQ", "KW_MAKE_MAP_PROPERTY", "KW_MAKE_PROPERTY", - "KW_MAKE_PROPERTY2", "KW_MAKE_SEQ", "KW_MAKE_SEQ_PROPERTY", "KW_MUTABLE", - "KW_NAMESPACE", "KW_NEW", "KW_NOEXCEPT", "KW_NOEXCEPT_LPAREN", - "KW_NULLPTR", "KW_OPERATOR", "KW_OVERRIDE", "KW_PRIVATE", "KW_PROTECTED", - "KW_PUBLIC", "KW_REGISTER", "KW_REINTERPRET_CAST", "KW_RESTRICT", - "KW_RETURN", "KW_SHORT", "KW_SIGNED", "KW_SIZEOF", "KW_STATIC", - "KW_STATIC_ASSERT", "KW_STATIC_CAST", "KW_STRUCT", "KW_TEMPLATE", - "KW_THREAD_LOCAL", "KW_THROW", "KW_TRUE", "KW_TRY", "KW_TYPEDEF", - "KW_TYPEID", "KW_TYPENAME", "KW_UNDERLYING_TYPE", "KW_UNION", - "KW_UNSIGNED", "KW_USING", "KW_VIRTUAL", "KW_VOID", "KW_VOLATILE", - "KW_WCHAR_T", "KW_WHILE", "START_CPP", "START_CONST_EXPR", "START_TYPE", - "'{'", "','", "';'", "':'", "'='", "'?'", "'|'", "'^'", "'&'", "'<'", - "'>'", "'+'", "'-'", "'*'", "'/'", "'%'", "'~'", "'.'", "'('", "'['", - "')'", "'}'", "'!'", "']'", "$accept", "grammar", "cpp", "$@1", - "constructor_inits", "constructor_init", "extern_c", "$@2", - "declaration", "friend_declaration", "$@3", "storage_class", - "optional_attributes", "attribute_specifiers", "attribute_specifier", - "type_like_declaration", "$@4", "$@5", "multiple_instance_identifiers", - "typedef_declaration", "$@6", "typedef_instance_identifiers", - "constructor_prototype", "$@7", "$@8", "$@9", "function_prototype", - "$@10", "$@11", "$@12", "$@13", "$@14", "function_post", - "function_operator", "more_template_declaration", "template_declaration", - "$@15", "template_formal_parameters", - "template_nonempty_formal_parameters", "typename_keyword", - "template_formal_parameter", "template_formal_parameter_type", - "instance_identifier", "$@16", - "instance_identifier_and_maybe_trailing_return_type", - "maybe_trailing_return_type", "maybe_comma_identifier", - "function_parameter_list", "function_parameters", - "formal_parameter_list", "formal_parameters", - "template_parameter_maybe_initialize", "maybe_initialize", - "maybe_initialize_or_constructor_body", - "maybe_initialize_or_function_body", "structure_init", - "structure_init_body", "function_parameter", "formal_parameter", - "not_paren_formal_parameter_identifier", "formal_parameter_identifier", - "parameter_pack_identifier", "not_paren_empty_instance_identifier", - "empty_instance_identifier", "type", "type_pack", "type_decl", - "predefined_type", "var_type_decl", "full_type", "anonymous_struct", - "$@17", "named_struct", "$@18", "maybe_final", "maybe_class_derivation", - "class_derivation", "base_specification", "enum", "$@19", "enum_decl", - "enum_element_type", "enum_body_trailing_comma", "enum_body", - "enum_keyword", "struct_keyword", "namespace_declaration", "$@20", - "$@21", "using_declaration", "simple_type", "simple_int_type", - "simple_float_type", "simple_void_type", "code", "$@22", "code_block", - "element", "optional_const_expr", "optional_const_expr_comma", - "const_expr_comma", "no_angle_bracket_const_expr", "const_expr", - "const_operand", "formal_const_expr", "formal_const_operand", - "capture_list", "capture", "class_derivation_name", "name", - "name_no_final", "string_literal", "empty", YY_NULLPTR -}; - -static const char * -yysymbol_name (yysymbol_kind_t yysymbol) -{ - return yytname[yysymbol]; -} -#endif - -#define YYPACT_NINF (-1062) - -#define yypact_value_is_default(Yyn) \ - ((Yyn) == YYPACT_NINF) - -#define YYTABLE_NINF (-785) - -#define yytable_value_is_error(Yyn) \ - 0 - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -static const yytype_int16 yypact[] = -{ - 188, -1062, 4339, 6032, 93, 349, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, 81, -70, -59, -43, -23, -2, - 24, 44, 60, 91, -1062, -1062, 92, 100, 109, 143, - 146, 154, 177, 180, 192, 200, 243, 251, 255, 264, - 272, 275, 279, 283, 290, 317, 6228, 4339, -1062, -1062, - 216, 324, 346, 3187, 221, -1062, 351, 368, 387, 4339, - 4339, 4339, 4339, 4339, 2888, 581, 4339, 4754, -1062, 119, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - 6097, 389, -1062, 6, -1062, -1062, 1578, 2508, 2508, -1062, - 5064, 414, -1062, 2508, -1062, -1062, 833, 833, -1062, -1062, - -1062, -1062, -1062, 223, 223, -1062, -1062, -1062, -1062, -1062, - 2565, 416, 274, -1062, 4339, 4339, 6032, 4339, 4339, 4339, - 4339, 4339, 6032, 4339, 6032, 4339, 6032, 4339, 6032, 6032, - 6032, 6032, 6032, 6032, 6032, 6032, 6032, 6032, 6032, 6032, - 6032, 6032, 6032, 6032, 4339, -1062, -1062, -1062, 421, 5064, - 423, 433, 223, 223, -1062, 5284, 6032, 4339, 4339, 453, - 2888, 68, 6032, 2888, 4339, 4339, 68, 68, 68, 68, - 68, 81, -59, -43, -23, -2, 24, 60, 92, 109, - 5288, 6413, 6437, 6513, 387, 376, -36, 4754, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - 5064, 5064, -104, 397, -1062, -1062, 68, 4339, 4339, 4339, - 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, - 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, 5064, 3331, - 4339, -1062, -1062, 833, 833, 3475, -1062, -1062, -1062, 2508, - -1062, -1062, -1062, -1062, 6032, -1062, 432, 564, 223, 833, - 833, 833, 223, 223, 59, 462, -1062, 463, -1062, 473, - 87, 2050, 5064, 583, 487, 474, 3037, -1062, 6616, 465, - 500, -1062, 494, 496, 506, 511, 516, 525, 528, 483, - 530, 495, 531, 532, 533, 534, 536, 543, -15, 563, - 551, 556, 562, 566, 567, 568, 572, 573, 576, 582, - 584, 587, 4339, -1062, 6032, 4339, 5064, 5064, -1062, 546, - 589, 590, 5064, 592, 574, 593, 5303, 596, 597, 4339, - 4339, -1062, 732, -1062, 1631, 600, 4339, -1062, -1062, 1881, - 4935, 5120, 5120, 555, 555, 485, 298, 298, -1062, 3642, - 5661, 1606, 1809, 555, 555, 132, 132, 68, 68, 68, - -1062, -1062, 28, 2457, -1062, -1062, 604, 5345, 613, 223, - 223, 1104, 462, -1062, 462, -1062, 462, -1062, 1104, 1104, - -1062, 223, 223, 223, 6713, 621, 30, -1062, 622, 4339, - -1062, -1062, -1062, -1062, -1062, 2131, 634, 3, 41, 57, - 106, -1062, -1062, -1062, 640, 223, 5064, 2062, 81, -1062, - -1062, 628, 5064, 632, 638, -1062, -1062, -1062, 223, 223, - -1062, 5366, -1062, 6713, 6713, 6713, 6713, 6713, -1062, 6713, - 5814, 6713, 4339, 656, -1062, 6656, 644, 645, 646, 647, - 648, 649, 6713, 62, 667, 669, 673, 6713, 6713, 660, - 6551, 6713, 6713, 4685, 6713, 6713, -1062, -1062, -1062, 2526, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, 663, -1062, 664, -1062, -1062, -1062, -1062, - 6032, -1062, 6032, -1062, 6032, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, 5385, 665, 671, - -1062, -1062, 666, -1062, -1062, 675, 4483, 678, -1062, -1062, - -1062, -1062, 68, 4754, -1062, 5064, 397, 55, 5806, -1062, - 4754, 4339, -1062, -1062, -1062, -1062, -1062, 1104, 668, 670, - 5064, 223, 1104, 1104, 1104, 223, 223, 674, -1062, 674, - 674, 1104, 1104, 1104, 5889, 6713, 6097, -1062, -1062, 117, - 679, 4754, -1062, 5064, 676, -1062, -1062, -1062, -1062, 2131, - -1062, 763, 5064, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, 686, 697, 701, -1062, -1062, 6228, -1062, -1062, 702, - 4880, 710, -1062, 695, 4339, 4339, 4339, 4339, 2888, 4339, - 700, 42, -1062, -1062, 5644, -1062, 119, 703, 3619, -1062, - 6032, 223, 2581, 2050, 223, -1062, -1062, -1062, -1062, -1062, - -1062, 6713, -1062, -1062, -1062, 5404, -1062, 6616, 3389, -1062, - 5064, 5064, 5064, 5064, 5064, 5064, -1062, -1062, 5064, -1062, - -1062, -1062, -1062, -1062, 4339, -1062, 5109, -1062, 712, -1062, - 5209, -1062, 5064, 5064, 2, -1062, -1062, 457, 706, 6130, - -1062, 5064, -1062, 224, 723, -1062, 4339, 4339, 709, 711, - 713, -1062, -1062, -1062, 4339, -1062, 4339, -1062, 715, -1062, - -1062, -1062, -1062, -1062, -1062, 4339, -1062, 708, -1062, -1062, - 852, 4754, 674, 223, 223, 1104, 674, 674, 674, 1104, - 1104, 4339, -103, 85, 133, 977, 946, 5806, -1062, -1062, - 223, 223, -1062, 736, 58, -1062, 729, -1062, 844, 6032, - 6032, 6032, 721, 6032, 725, 2888, 95, 6032, 2888, 68, - 68, 68, 68, 726, 101, 68, -1062, -1062, 4863, 4339, - 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, - 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, 4339, - 5064, 3763, 4339, 727, 5464, 731, -1062, -1062, 746, -1062, - -1062, -1062, 6713, -1062, -1062, 753, 757, 759, 760, 764, - 769, 770, 80, 772, 4506, 5921, 395, 755, 224, -1062, - -1062, 773, 774, -1062, 775, -1062, 22, 6293, 1248, -1062, - 756, 517, -1062, -1062, 2204, -1062, -1062, 704, 124, 183, - -1062, -1062, -1062, 189, 196, -1062, 5565, 365, 6195, 777, - -1062, 1104, -1062, 674, 674, 674, 762, 778, 784, 788, - 765, 223, 977, 977, 977, 223, 223, 977, -81, 223, - -1062, 767, 5064, 223, 946, 946, 946, 223, 223, 946, - 8, 852, 771, 36, -1062, 6311, 791, 794, -1062, 223, - 790, 782, 798, 4339, 801, 5064, 792, 809, 800, 5584, - 4339, -1062, -1062, -1062, 1881, 4935, 5120, 5120, 555, 555, - 485, 298, 298, -1062, 3930, 5661, 1606, 1809, 555, 555, - 132, 132, 68, 68, 68, -1062, -1062, 207, 2907, -1062, - -1062, -1062, 2131, -1062, 98, -1062, 969, 971, 972, 974, - 975, 976, -1062, -1062, 427, 835, -1062, -1062, -1062, -1062, - 5975, -1062, 5975, 825, 838, 6470, -1062, 744, -1062, -1062, - 20, -1062, 704, -1062, -1062, 6032, 55, 820, 829, 704, - 55, 1248, 830, 223, 1248, 1248, 1248, 223, 223, 56, - 223, -1062, 99, -1062, -1062, -1062, 5064, 405, -1062, 826, - -1062, 848, 850, 3907, 4214, 842, 223, 704, 5043, 704, - 223, 223, 704, -1062, 77, 454, 223, -1062, -1062, -1062, - -1062, 5806, -1062, -1062, 14, 6228, 833, -1062, 674, 223, - 55, 55, 55, 223, 977, 837, 837, 837, 977, 977, - 328, 4339, -1062, -1062, 223, 223, 946, 840, 840, 840, - 946, 946, 336, 4339, -1062, -1062, -1062, 4339, 6378, 6393, - 6408, 5064, 498, -1062, -1062, 998, -1062, 6311, -1062, -1062, - 843, 849, 846, 854, 856, 4483, 865, -1062, -1062, 68, - 4339, -1062, -1062, 736, -1062, -1062, 861, 212, 873, 884, - 889, 895, -1062, 43, -1062, 744, 744, 6696, 5921, 5064, - 885, 897, 223, 744, 744, 744, 223, 223, 744, 65, - 840, -1062, 454, 910, 893, 898, 704, 492, 899, 410, - 223, 1248, 901, 901, 901, 1248, 1248, -1062, 4339, -1062, - -1062, 55, 900, 468, -1062, 89, 916, 920, -1062, 2711, - -1062, -1062, -1062, 3907, 902, 923, 4754, -1062, -1062, 223, - 704, 460, 1071, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - 909, 907, -1062, 223, 460, 704, 704, 515, 4339, -1062, - 4339, -1062, 2204, 931, -1062, -1062, 852, 913, -1062, 833, - -1062, 914, -1062, 917, 919, 924, 977, 837, 837, 837, - 918, 911, 946, -1062, 840, 840, 840, 925, 922, 5625, - 1336, -1062, 1336, -1062, 1336, -1062, -1062, 1336, 1336, 1336, - -1062, 102, -1062, 4339, 4339, -1062, 4339, -1062, 4339, 4754, - 134, 1092, 1093, 948, 1097, 932, -1062, 1099, 1106, 1108, - 157, 956, 65, 840, 65, 840, -1062, -1062, -1062, -1062, - -1062, -1062, 6032, 223, 744, 744, 744, 1788, -1062, -1062, - 965, -1062, -1062, -1062, -1062, 523, 951, -1062, -1062, 1248, - 901, 901, 901, 55, 952, 958, -1062, -1062, 5064, 4339, - 4339, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - -1062, -1062, 955, -1062, 4051, 704, 460, 223, -1062, -1062, - -1062, 460, 460, -1062, 4754, 2062, 964, 4214, 704, 979, - -1062, -1062, -1062, -1062, -1062, -1062, 837, 55, 223, 840, - 55, 223, -1062, -1062, -1062, -1062, -1062, -1062, -1062, -1062, - 230, 252, 254, 266, -1062, 968, 304, -1062, 990, 991, - 325, 982, 339, -1062, -1062, -1062, -1062, -1062, 744, 978, - 985, 988, 994, 4627, 997, 1788, 1788, 1788, 1788, 1788, - 2888, 1788, 1343, -1062, 704, 5806, 55, 989, -1062, 5806, - 55, 901, 992, 223, -1062, 987, -1062, 993, 996, 2382, - -1062, 3907, 4754, 460, -1062, 999, 223, -1062, -1062, 5806, - 5806, 5806, 1000, -1062, 1001, -1062, -1062, -1062, -1062, -1062, - 1011, 1163, 1016, 1168, -1062, 1170, 1023, 1024, 1174, 1027, - 6032, 6032, 6032, 6032, 1012, 2888, 152, 6032, 152, 152, - 152, 152, 152, 1013, 367, 152, 1788, 1788, 1788, 1788, - 1788, 1788, 1788, 1788, 1788, 1788, 1788, 1788, 1788, 1788, - 1788, 1788, 1788, 1788, 1788, 5064, 4195, 4339, -1062, -1062, - 1014, -1062, 55, -1062, 1015, -1062, -1062, 5806, -1062, -1062, - 1172, -1062, 1019, -1062, -1062, 1021, 852, 852, 852, -1062, - -1062, -1062, 1036, -1062, 1026, 1042, -1062, -1062, 369, -1062, - 1028, 1034, 1039, 1041, 5064, 1032, 1043, 1788, -1062, 1911, - 4954, 1257, 1257, 888, 888, 1441, 617, 617, -1062, 1363, - 5678, 5743, 4478, 281, 281, 152, 152, 152, -1062, -1062, - 370, 3205, -1062, 55, 1035, -1062, 3534, -1062, -1062, -1062, - 5806, -1062, -1062, -1062, -1062, 5806, 5806, 1200, 1040, 1054, - 1208, 1209, 1062, -1062, 1047, 1049, 1050, 1051, 4731, 1055, - 152, 1788, -1062, -1062, 5806, 1057, -1062, 3534, -1062, -1062, - -1062, -1062, 1067, -1062, 1058, 371, -1062, 4339, 4339, 4339, - -1062, 4339, 1343, -1062, -1062, 5806, -1062, 1072, 1225, 1078, - 372, 378, 380, 383, 5806, 852, -1062, 1064, -1062, -1062, - -1062, -1062, -1062, 852, -1062, 1083, -1062, -1062 -}; - -/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ -static const yytype_int16 yydefact[] = -{ - 0, 789, 0, 0, 0, 789, 5, 675, 671, 674, - 785, 786, 677, 678, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 673, 679, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 681, 680, - 0, 0, 0, 0, 0, 672, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 789, 0, 3, 609, 676, - 307, 319, 317, 402, 318, 403, 405, 406, 407, 386, - 0, 0, 418, 383, 417, 412, 409, 408, 411, 387, - 0, 0, 388, 410, 420, 404, 789, 789, 4, 309, - 310, 311, 369, 789, 789, 306, 399, 400, 401, 1, - 0, 0, 7, 63, 789, 789, 0, 789, 789, 789, - 789, 789, 0, 789, 0, 789, 0, 789, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 789, 335, 341, 342, 0, 0, - 0, 634, 789, 789, 334, 0, 0, 789, 789, 0, - 0, 631, 0, 0, 789, 789, 643, 641, 640, 642, - 639, 307, 402, 403, 405, 406, 407, 418, 417, 412, - 409, 408, 411, 410, 404, 0, 0, 567, 770, 771, - 772, 780, 773, 776, 774, 778, 777, 775, 779, 759, - 760, 0, 0, 789, 765, 758, 638, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 787, 788, 789, 789, 0, 384, 385, 419, 409, - 414, 413, 416, 308, 0, 415, 0, 292, 789, 789, - 789, 789, 789, 789, 789, 0, 345, 291, 347, 0, - 372, 0, 0, 0, 68, 70, 0, 6, 789, 0, - 566, 565, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 336, 0, 789, 0, 0, 667, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 670, 763, 766, 0, 789, 0, 761, 222, 652, - 653, 654, 655, 656, 657, 658, 661, 662, 669, 0, - 649, 650, 651, 659, 660, 647, 648, 644, 645, 646, - 668, 666, 0, 0, 346, 348, 0, 0, 0, 789, - 789, 789, 0, 294, 0, 296, 0, 295, 789, 789, - 207, 789, 789, 789, 789, 0, 208, 211, 63, 789, - 789, 781, 782, 783, 784, 0, 374, 770, 771, 772, - 774, 349, 312, 351, 0, 789, 0, 789, 321, 332, - 333, 0, 0, 0, 0, 323, 324, 325, 789, 789, - 320, 0, 22, 789, 789, 789, 789, 789, 23, 789, - 789, 789, 0, 0, 43, 789, 0, 0, 0, 0, - 0, 0, 789, 789, 0, 0, 0, 789, 789, 0, - 789, 789, 789, 0, 789, 789, 18, 8, 20, 0, - 16, 17, 19, 78, 45, 616, 615, 633, 623, 618, - 620, 621, 622, 0, 629, 0, 628, 684, 617, 685, - 0, 687, 0, 688, 0, 691, 692, 693, 694, 695, - 696, 697, 698, 699, 700, 701, 625, 0, 0, 0, - 338, 337, 0, 624, 627, 0, 630, 0, 636, 637, - 626, 619, 610, 568, 764, 0, 789, 789, 789, 103, - 223, 0, 665, 664, 315, 314, 316, 789, 293, 0, - 281, 789, 789, 789, 789, 789, 789, 299, 280, 298, - 297, 789, 789, 789, 789, 789, 0, 789, 210, 789, - 0, 564, 563, 380, 0, 377, 376, 371, 375, 0, - 789, 789, 0, 64, 69, 751, 747, 750, 753, 754, - 214, 0, 0, 0, 749, 755, 0, 757, 756, 0, - 0, 0, 748, 0, 0, 0, 0, 0, 0, 0, - 0, 215, 244, 218, 245, 702, 752, 63, 0, 322, - 0, 789, 372, 0, 789, 60, 46, 57, 58, 59, - 61, 789, 47, 160, 52, 0, 24, 789, 0, 50, - 0, 0, 0, 0, 0, 0, 56, 789, 0, 27, - 26, 25, 54, 49, 0, 164, 0, 163, 0, 62, - 0, 21, 0, 0, 789, 51, 55, 344, 321, 0, - 14, 0, 75, 0, 343, 72, 0, 0, 0, 0, - 0, 339, 340, 635, 0, 632, 0, 762, 0, 111, - 104, 113, 108, 112, 106, 0, 109, 0, 105, 110, - 789, 663, 300, 789, 789, 789, 283, 285, 284, 789, - 789, 789, 0, 0, 0, 789, 0, 789, 209, 212, - 789, 789, 370, 313, 789, 354, 789, 353, 0, 0, - 0, 0, 712, 0, 0, 0, 709, 0, 0, 720, - 719, 718, 717, 0, 0, 716, 71, 217, 789, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 67, 328, 374, 326, - 66, 48, 789, 44, 789, 0, 0, 0, 0, 0, - 0, 0, 789, 0, 0, 789, 344, 321, 0, 343, - 81, 0, 0, 395, 0, 86, 90, 0, 789, 789, - 0, 0, 421, 229, 0, 77, 74, 0, 0, 0, - 686, 689, 690, 0, 0, 789, 0, 0, 0, 0, - 201, 789, 282, 288, 287, 286, 0, 0, 0, 0, - 0, 789, 789, 789, 789, 789, 789, 789, 789, 789, - 256, 0, 268, 789, 0, 0, 0, 789, 789, 0, - 789, 789, 301, 381, 350, 0, 0, 356, 355, 789, - 0, 0, 0, 789, 0, 0, 0, 0, 0, 0, - 0, 746, 216, 219, 729, 730, 731, 732, 733, 734, - 735, 738, 739, 745, 0, 726, 727, 728, 736, 737, - 724, 725, 721, 722, 723, 744, 743, 0, 0, 330, - 329, 331, 0, 53, 789, 391, 0, 0, 0, 0, - 0, 0, 393, 389, 0, 0, 183, 184, 185, 169, - 0, 170, 0, 0, 166, 171, 167, 789, 182, 165, - 0, 83, 0, 398, 397, 0, 789, 0, 0, 0, - 789, 789, 0, 789, 789, 789, 789, 789, 789, 0, - 789, 246, 789, 92, 421, 224, 0, 0, 76, 0, - 789, 0, 0, 789, 0, 0, 789, 0, 0, 0, - 789, 789, 0, 73, 789, 789, 789, 613, 612, 614, - 611, 789, 107, 114, 0, 0, 789, 421, 289, 789, - 789, 789, 789, 789, 789, 258, 260, 259, 789, 789, - 0, 789, 242, 257, 789, 789, 0, 270, 272, 271, - 0, 0, 0, 789, 243, 302, 378, 0, 778, 0, - 777, 0, 0, 357, 359, 767, 789, 0, 65, 711, - 0, 0, 0, 0, 0, 708, 0, 714, 715, 703, - 0, 742, 741, 327, 394, 789, 0, 0, 789, 0, - 0, 0, 789, 0, 42, 789, 789, 789, 0, 174, - 172, 0, 789, 789, 789, 789, 789, 789, 789, 789, - 178, 82, 789, 0, 0, 0, 0, 0, 0, 0, - 789, 789, 248, 250, 249, 789, 789, 98, 789, 247, - 15, 789, 0, 0, 9, 0, 0, 0, 230, 422, - 423, 232, 233, 789, 0, 236, 238, 235, 231, 789, - 0, 189, 0, 127, 128, 129, 130, 131, 132, 135, - 136, 137, 152, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 156, 155, 139, 138, 124, - 126, 125, 133, 134, 122, 123, 119, 120, 121, 118, - 0, 0, 117, 789, 190, 0, 0, 0, 0, 197, - 789, 199, 0, 0, 79, 186, 789, 0, 115, 789, - 202, 0, 290, 0, 0, 0, 789, 263, 262, 261, - 267, 0, 0, 269, 275, 274, 273, 279, 0, 382, - 0, 362, 0, 361, 0, 360, 768, 0, 0, 0, - 769, 789, 358, 0, 0, 713, 0, 710, 0, 740, - 789, 0, 0, 0, 0, 0, 204, 0, 0, 0, - 789, 0, 789, 179, 789, 181, 159, 157, 162, 158, - 168, 175, 0, 789, 789, 789, 789, 0, 176, 220, - 0, 84, 396, 789, 88, 0, 0, 789, 100, 789, - 253, 252, 251, 789, 0, 0, 225, 421, 0, 789, - 789, 227, 228, 425, 426, 430, 427, 435, 428, 429, - 431, 432, 433, 434, 436, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, - 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, - 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, - 482, 483, 484, 485, 486, 487, 488, 489, 511, 490, - 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, - 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, - 532, 533, 534, 535, 536, 537, 538, 539, 789, 556, - 557, 558, 549, 561, 545, 546, 544, 551, 552, 540, - 541, 542, 543, 550, 548, 555, 553, 559, 554, 547, - 560, 424, 0, 234, 237, 0, 193, 789, 154, 153, - 187, 192, 191, 196, 200, 789, 0, 223, 0, 0, - 116, 203, 682, 789, 789, 789, 264, 789, 789, 276, - 789, 789, 379, 368, 367, 366, 365, 364, 363, 352, - 0, 0, 0, 0, 392, 0, 0, 34, 205, 0, - 0, 0, 0, 390, 41, 177, 180, 173, 789, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 221, 569, 0, 789, 789, 0, 94, 789, - 789, 254, 0, 789, 789, 0, 10, 0, 0, 0, - 239, 789, 240, 194, 188, 0, 789, 80, 421, 789, - 789, 789, 0, 265, 0, 277, 706, 705, 707, 704, - 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 576, 0, 584, 582, - 581, 583, 580, 0, 0, 579, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 85, 87, - 0, 96, 789, 91, 0, 789, 255, 789, 226, 13, - 11, 562, 0, 789, 195, 0, 789, 789, 789, 789, - 789, 37, 789, 35, 0, 0, 38, 40, 0, 30, - 0, 0, 0, 0, 0, 0, 0, 0, 608, 593, - 594, 595, 596, 597, 598, 599, 600, 601, 607, 0, - 590, 591, 592, 588, 589, 585, 586, 587, 606, 605, - 0, 0, 789, 789, 0, 789, 99, 93, 12, 241, - 789, 683, 305, 304, 303, 789, 789, 0, 0, 0, - 0, 0, 0, 578, 0, 0, 0, 0, 575, 0, - 570, 0, 604, 603, 789, 0, 789, 101, 198, 266, - 278, 205, 0, 29, 0, 0, 31, 0, 0, 0, - 577, 0, 602, 89, 789, 789, 36, 0, 0, 0, - 0, 0, 0, 0, 789, 789, 39, 0, 32, 573, - 572, 574, 571, 789, 95, 0, 97, 33 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -1062, -1062, -525, -1062, -1062, 4, -1062, -1062, 636, -428, - -1062, -354, 210, -358, -1062, -426, -1062, -1062, -153, -1062, - -1062, -208, -1062, -1062, -1062, -1062, 620, -1062, -1062, -1062, - -1062, -1062, -448, -1062, -1062, -414, -1062, -1062, -1062, -1062, - 209, -412, -746, -1062, -886, -775, -311, -406, -1062, -142, - -1062, -644, -485, -1062, -731, -1061, -1062, -381, 537, -844, - -643, 258, -39, -96, -77, -57, -236, -539, 633, 156, - -235, -1062, -223, -1062, -1062, -1062, -1062, 257, -222, -1062, - -1062, -521, -1062, -1062, -27, -22, -1062, -1062, -1062, -1062, - -28, -47, -1062, -1062, -898, -1062, -92, -1062, -623, -110, - -60, 571, 1273, 285, 692, -1062, -1062, 943, -822, 1127, - -116, -395, -1 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - 0, 4, 5, 268, 1073, 1074, 446, 779, 447, 448, - 607, 449, 374, 263, 264, 450, 787, 781, 953, 631, - 912, 1051, 642, 916, 1456, 920, 643, 1071, 1542, 1603, - 1233, 1460, 508, 1133, 1208, 451, 628, 903, 904, 905, - 906, 907, 954, 1395, 955, 799, 1195, 375, 376, 580, - 581, 1218, 327, 938, 785, 1084, 1085, 377, 583, 929, - 975, 987, 255, 256, 96, 97, 644, 151, 645, 98, - 99, 550, 100, 551, 696, 836, 837, 1003, 101, 259, - 102, 547, 543, 544, 103, 104, 452, 1032, 1025, 453, - 105, 106, 107, 108, 939, 940, 1079, 1381, 540, 269, - 270, 1630, 187, 68, 584, 585, 202, 203, 1004, 1005, - 819, 69, 113 -}; - -/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_int16 yytable[] = -{ - 6, 258, 586, 233, 186, 272, 603, 274, 275, 276, - 277, 278, 625, 280, 627, 282, 582, 284, 154, 152, - 536, 657, 1382, 234, 153, 694, 1052, 702, 693, 1147, - 404, 405, 917, 918, 301, 918, 1072, 911, 554, 240, - 241, 242, 818, 406, 407, 538, 245, 310, 311, 231, - 110, 232, 111, 324, 317, 318, 995, 717, 806, 595, - 596, 597, 598, 599, 205, 600, 602, 604, 236, 1151, - 370, 609, 681, 807, 370, 325, 371, 1059, 616, 326, - 1062, 1063, 1064, 622, 623, -781, 626, 629, 630, 687, - 635, 636, 762, 109, 981, 257, 257, 381, 382, 383, - 186, 658, 216, 110, 116, 111, 110, 110, 111, 111, - 110, 798, 111, 271, 271, 117, 271, 271, 271, 271, - 271, 320, 271, -782, 271, 231, 271, 232, 110, 728, - 111, 118, 688, 240, 241, 242, 245, 354, 355, -783, - 321, 237, 472, 271, 386, 393, 110, 110, 111, 111, - 110, 119, 111, 363, 365, 367, 271, 271, 689, -781, - 773, 473, -781, 271, 271, 110, 216, 111, 326, 352, - 976, 977, 120, 1057, 980, 586, 1171, 1173, 1175, 1141, - 602, 609, 110, 993, 111, 320, 1525, 539, -784, 919, - 1148, 919, 240, 996, 698, 489, 997, -782, 121, 718, - -782, 1091, 328, 1134, 512, 110, 1137, 111, 384, 122, - 362, 364, 366, -783, 405, 112, -783, 1230, 617, 1201, - 185, 1231, 1232, 372, 1144, 1217, 406, 407, 373, 884, - 1067, 1068, 257, 257, 123, 834, 1138, 114, 410, 408, - 981, 228, 229, 230, 409, 1239, 385, 751, 257, 257, - 257, 1139, 1140, 378, 932, 115, 124, 892, 320, 966, - 681, 808, -784, 1240, 1049, -784, 125, 454, 740, 741, - 742, 110, 273, 111, 126, 1024, 1070, 851, 279, 1419, - 281, 320, 283, 127, 285, 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, - 957, 225, 226, 227, 271, 228, 229, 230, 681, 809, - 1225, 1424, 309, 260, 261, 1525, 313, 128, 314, 315, - 129, 1221, 527, 586, 509, 1535, 1536, 1537, 130, 529, - 530, 1157, 216, 982, 1433, 1158, 1159, 582, 548, 1465, - 320, 1, 2, 3, 1386, 994, 320, 961, 1413, -2, - 1414, 131, 1415, 320, 132, 1416, 1417, 1418, 1161, 958, - 528, 1023, 306, 307, 320, 959, 133, 528, 528, 1192, - 1168, 1399, 960, 454, 134, 188, 189, 190, 542, 545, - 782, 156, 783, 1021, 784, 1461, 162, 320, 1193, 1391, - 1392, 405, 1202, 1204, 769, 405, 587, 110, 883, 111, - 358, 976, 977, 406, 407, 980, 1486, 406, 407, 320, - 1552, 320, 454, 454, 454, 454, 454, 135, 454, 454, - 454, 410, 408, 320, 454, 136, 1149, 409, 1487, 137, - 1488, 454, 267, 10, 191, 11, 454, 454, 138, 454, - 454, 454, 1489, 454, 454, 1234, 139, 192, 193, 140, - 1532, 1533, 1534, 141, 1535, 1536, 1537, 142, 361, 685, - 488, 1491, 368, 369, 143, 223, 224, 225, 226, 227, - 1143, 228, 229, 230, 1076, 1077, 748, 393, 672, 686, - 1492, 1181, 1495, 676, 677, 678, 194, 195, 1035, 196, - 1036, 144, 682, 683, 684, 197, 1498, 198, 157, 1033, - 1190, 1496, 548, 981, 1160, 328, 378, 1200, 214, 215, - 1054, 993, 1167, 1406, 1058, 1499, 528, 1396, 714, 216, - 158, 528, 528, 528, 320, 163, 1621, 320, 1658, 320, - 528, 528, 528, 454, 454, 320, 509, 320, 154, 152, - 320, 963, 164, 1578, 153, 1622, 1632, 1659, 1669, 6, - 697, -102, 319, -102, 1670, -102, 1671, 326, 1435, 1672, - 1436, 165, 778, 235, 1153, 1154, 1155, 1220, 1052, 517, - 518, 1157, 1158, 1159, 188, 189, 190, 213, 214, 215, - 1555, 531, 532, 533, 1228, 1068, 788, 789, 244, 216, - 266, 188, 189, 190, 793, 302, 794, 304, 410, 408, - 454, 359, 410, 408, 409, 553, 454, 305, 409, 1206, - 782, 1207, 783, -102, 1142, -102, 6, -102, 592, 593, - 1177, 1178, 1179, 1209, 1237, 1238, 648, 312, 649, 380, - 650, 775, 395, 191, 1139, 1140, 803, 379, -280, 1473, - 804, 805, 455, 618, 396, 714, 192, 193, 397, 463, - 191, 1525, 223, 224, 225, 226, 227, 320, 228, 229, - 230, 465, 930, 192, 193, 1235, 1139, 1140, 1226, 800, - 456, 956, 457, 934, 528, 935, 936, 937, 528, 528, - 542, 877, 458, 626, 820, 194, 195, 459, 196, 1139, - 1140, 1393, 460, 470, 197, 838, 198, 1139, 1140, 1457, - 921, 461, 194, 195, 462, 196, 464, 466, 467, 468, - 469, 197, 492, 198, 381, 382, 383, 945, 670, 471, - 474, 946, 223, 224, 225, 226, 227, 475, 228, 229, - 230, 675, 476, 1012, 713, 679, 680, 908, 477, -281, - 497, 199, 478, 479, 480, 200, 745, 504, 481, 482, - 201, 454, 483, 6, 381, 382, 383, 1041, 484, 822, - 485, 1042, 968, 486, 909, 493, 494, 947, 496, 498, - 154, 152, 500, 501, 507, 1455, 153, 931, 6, 1459, - 514, 1612, 1613, 1614, 1530, 1531, 1532, 1533, 1534, 516, - 1535, 1536, 1537, 549, 509, 1406, 956, 537, -206, 552, - 528, 746, 588, 956, 750, 930, 590, 1043, 930, 930, - 930, 820, 820, 820, 591, 606, 820, 328, 610, 611, - 612, 613, 614, 615, 948, 384, 619, 1462, 620, 328, - 800, 956, 621, 956, 624, 548, 956, 646, 647, 673, - 654, 652, 271, -282, 774, 695, 246, 653, 247, 681, - 248, 655, 656, 692, 949, 840, 841, 842, 690, 844, - 699, 846, 700, 847, 848, 384, 701, 703, 950, 708, - 1150, 1044, 908, 951, 908, 707, 716, 765, 952, -213, - 776, 786, 797, 801, 802, 790, 798, 791, 835, 792, - 1674, 795, -373, 839, 1045, 843, 249, 831, 1676, 845, - 832, 833, 850, 879, 112, 882, 820, 881, 1046, 885, - 1522, 1523, 1524, 1047, 886, 378, 887, 888, 1048, 378, - 931, 889, 1525, 931, 931, 931, 890, 891, 893, 910, - 933, 913, 914, 967, 973, 915, 984, 154, 152, 1080, - 956, 969, 1087, 153, 830, 930, -290, 1006, 1010, 930, - 930, 1007, 970, 800, 328, 1479, 1480, 1481, 971, 821, - 250, 822, 972, 823, 1011, 257, 1009, 1013, 1015, 378, - 378, 378, 112, 820, 956, 1016, 1017, 820, 820, 1026, - 542, 1027, 1028, 251, 1029, 1030, 1031, 381, 382, 383, - 810, 1037, 542, 1034, 811, 1038, 1055, 252, 1056, 1060, - 586, 1482, 253, 1078, 1484, 6, 1081, 254, 1082, 824, - 908, 1089, 981, 1180, 582, 993, 1547, 1183, 1191, 956, - 956, 974, 1185, 1184, 6, 978, 979, 1196, 1186, 983, - 1194, 6, 1187, 986, 820, 820, 454, 990, 991, 1188, - 812, 1197, 820, 820, 820, 1212, 1198, 820, 1219, 1008, - 1540, 328, 1199, 1401, 1544, 1530, 1531, 1532, 1533, 1534, - 931, 1535, 1536, 1537, 931, 931, 1213, 542, 1222, 1223, - 378, 1053, 1224, 825, 1241, 1227, 1068, 1236, 1242, 1383, - 1384, 1387, 1087, 988, 989, 1388, 1389, 992, 1398, 1400, - 1408, 1402, 1407, 1403, 112, 1404, 826, 1606, 384, 1410, - 1405, 1411, 1425, 1426, 813, 1610, 1427, 1428, 1429, 1430, - 827, 1615, 1616, 930, 1434, 828, 1431, 519, 1432, 520, - 829, 521, 1454, 1420, 1421, 1458, 1422, 814, 1423, 1467, - 1468, 1463, 1470, 1061, 1464, 1478, 1604, 1065, 1066, 542, - 1069, 815, 112, 1476, 1490, 800, 816, 1493, 257, 1494, - 1501, 817, 1500, 1502, 1634, 820, 1090, 1637, 1497, 1503, - 1135, 1136, 1507, 1541, 1548, 1050, 1145, 522, 1545, 1561, - 1549, 1146, 1550, 1562, 1563, 1553, 1559, 1560, 1564, 1152, - 1565, 1566, 1567, 1156, 1568, 1569, 1574, 1608, 1655, 1577, - 1602, 1605, 204, 1617, 1162, 1163, 1609, 1635, 1611, 1620, - 1624, 1219, 1619, 1219, 1623, 1625, 1664, 1626, 1628, 1629, - 1641, 1636, 1643, 820, 820, 820, 1642, 243, 1644, 1645, - 1646, 1647, 509, 1648, 1649, 1656, 509, 1650, 931, 1651, - 1666, 523, 378, 1654, 1657, 1667, 1668, 265, 271, 271, - 1675, 1677, 1466, 753, 1164, 1477, 1538, 1210, 1165, 1166, - 768, 1618, 1214, 1475, 524, 853, 1215, 1216, 381, 382, - 383, 922, 706, 770, 1182, 923, 1469, 506, 525, 956, - 1229, 0, 0, 526, 0, 67, 303, 1520, 1521, 1522, - 1523, 1524, 956, 0, 0, 0, 0, 0, 0, 0, - 0, 1525, 0, 1203, 1205, 0, 0, 0, 0, 1385, - 0, 0, 988, 989, 0, 0, 992, 0, 0, 0, - 0, 924, 0, 0, 0, 0, 0, 0, 0, 0, - 155, 0, 0, 0, 0, 0, 161, 322, 323, 0, - 0, 0, 166, 167, 168, 169, 170, 0, 956, 206, - 0, 0, 0, 1390, 0, 0, 188, 189, 190, 0, - 0, 0, 0, 0, 0, 350, 0, 1080, 0, 1516, - 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1437, 384, - 0, 0, 0, 0, 360, 925, 0, 1525, 0, 1516, - 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 392, 394, - 1514, 112, 0, 0, 587, 0, 0, 1525, 926, 0, - 112, 0, 509, 509, 509, 191, 378, 0, 0, 378, - 112, 0, 927, 0, 0, 0, 0, 928, 192, 193, - 1409, 0, 0, 1438, 1530, 1531, 1532, 1533, 1534, 0, - 1535, 1536, 1537, 490, 491, 0, 316, 820, 0, 495, - 0, 0, 0, 0, 0, 1514, 0, 0, 0, 0, - 0, 204, 0, 0, 0, 378, 0, 194, 195, 378, - 196, 0, 0, 509, 1523, 1524, 197, 0, 198, 0, - 1087, 0, 1164, 1165, 1166, 1525, 1600, 0, 0, 1001, - 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, - 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, - 349, 0, 1453, 353, 1526, 1527, 1528, 1529, 357, 0, - 1530, 1531, 1532, 1533, 1534, 0, 1535, 1536, 1537, 0, - 0, 0, 1631, 265, 1526, 1527, 1528, 1529, 0, 589, - 1530, 1531, 1532, 1533, 1534, 0, 1535, 1536, 1537, 411, - 0, 378, 0, 0, 509, 0, 0, 0, 0, 0, - 0, 0, 509, 0, 0, 800, 800, 800, 509, 509, - 0, 1196, 0, 0, 0, 0, 0, 0, 0, 0, - 634, 0, 0, 0, 0, 487, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1660, 1661, 1662, - 0, 1663, 502, 503, 0, 0, 0, 1474, 0, 510, - 0, 509, 378, 0, 509, 0, 1513, 0, 1530, 1531, - 1532, 1533, 1534, 0, 1535, 1536, 1537, 0, 1483, 0, - 0, 1485, 0, 0, 209, 210, 211, 212, 213, 214, - 215, 0, 322, 73, 0, 509, 75, 76, 77, 78, - 216, 188, 189, 190, 0, 0, 0, 674, 0, 238, - 0, 0, 541, 509, 0, 0, 1570, 1571, 1572, 1573, - 0, 1575, 0, 1576, 800, 1539, 0, 0, 85, 1543, - 691, 0, 800, 1546, 0, 0, 0, 0, 0, 265, - 0, 0, 0, 0, 0, 239, 1554, 0, 0, 1556, - 1557, 1558, 0, 0, 0, 605, 1409, 0, 0, 0, - 191, 0, 0, 0, 0, 0, 0, 87, 88, 0, - 0, 0, 0, 192, 193, 0, 0, 0, 0, 747, - 749, 0, 0, 0, 93, 0, 0, 0, 1453, 95, - 1453, 1453, 1453, 1453, 1453, 755, 1453, 756, 757, 758, - 759, 760, 761, 0, 0, 763, 0, 0, 0, 0, - 0, 0, 194, 195, 0, 196, 0, 1607, 0, 771, - 772, 197, 0, 198, 0, 0, 0, 0, 780, 502, - 220, 221, 222, 223, 224, 225, 226, 227, 0, 228, - 229, 230, 0, 0, 671, 0, 0, 0, 1452, 0, - 0, 7, 8, 9, 10, 505, 11, 12, 13, 0, - 201, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, - 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, - 1638, 0, 0, 0, 0, 1639, 1640, 209, 210, 211, - 212, 213, 214, 215, 0, 0, 0, 0, 0, 1439, - 0, 0, 0, 216, 1653, 0, 0, 709, 710, 711, - 712, 0, 715, 0, 0, 1440, 0, 0, 0, 0, - 1441, 744, 1453, 0, 0, 1665, 0, 875, 0, 24, - 25, 0, 0, 0, 1673, 27, 0, 0, 0, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 0, 0, 764, 208, 209, - 210, 211, 212, 213, 214, 215, 0, 48, 0, 49, - 0, 0, 0, 1453, 1442, 216, 1453, 0, 0, 1443, - 0, 0, 1444, 0, 964, 0, 0, 55, 1517, 1518, - 1519, 1520, 1521, 1522, 1523, 1524, 0, 0, 796, 0, - 0, 0, 0, 0, 0, 1525, 0, 0, 0, 985, - 0, 0, 1445, 0, 541, 1446, 1447, 1448, 0, 0, - 1449, 0, 1450, 65, 0, 0, 1451, 0, 0, 0, - 0, 0, 1014, 0, 221, 222, 223, 224, 225, 226, - 227, 849, 228, 229, 230, 0, 0, 0, 0, 0, - 0, 0, 854, 855, 856, 857, 858, 859, 860, 861, - 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, - 872, 873, 874, 0, 1506, 878, 1508, 1509, 1510, 1511, - 1512, 0, 1515, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1040, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 0, 228, 229, 230, 944, 0, 0, - 387, 388, 389, 1075, 0, 555, 556, 557, 10, 0, - 11, 558, 559, 1527, 1528, 1529, 0, 560, 1530, 1531, - 1532, 1533, 1534, 0, 1535, 1536, 1537, 1579, 1580, 1581, - 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, - 1592, 1593, 1594, 1595, 1596, 1597, 0, 0, 0, 0, - 110, 0, 111, 561, 0, 0, 0, 0, 0, 191, - 0, 0, 0, 1019, 0, 0, 0, 0, 1176, 562, - 0, 0, 192, 193, 563, 0, 0, 0, 0, 0, - 0, 0, 546, 564, 565, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1211, 0, 0, 0, - 0, 390, 195, 0, 196, 0, 0, 0, 566, 0, - 197, 567, 198, 568, 0, 0, 73, 0, 569, 75, - 76, 77, 78, 570, 0, 0, 571, 0, 0, 0, - 0, 572, 1652, 0, 573, 0, 391, 7, 8, 9, - 10, 0, 11, 12, 13, 14, 1086, 0, 0, 0, - 0, 85, 0, 0, 0, 0, 574, 0, 0, 575, - 576, 0, 0, 0, 577, 0, 578, 0, 239, 0, - 579, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 541, 15, 0, 0, 0, 16, - 87, 88, 17, 18, 19, 20, 541, 0, 0, 0, - 1169, 21, 0, 941, 942, 22, 23, 93, 0, 0, - 0, 0, 95, 0, 0, 24, 25, 26, 1019, 0, - 0, 27, 0, 1189, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 0, 0, 0, 0, 0, 0, 0, 0, - 46, 0, 47, 48, 0, 49, 0, 0, 0, 0, - 50, 0, 0, 51, 52, 53, 0, 0, 54, 0, - 0, 541, 0, 55, 0, 0, 56, 0, 0, 0, - 57, 0, 0, 0, 0, 58, 1086, 0, 0, 0, - 943, 0, 0, 0, 0, 1075, 0, 0, 59, 0, - 0, 60, 61, 62, 0, 0, 63, 0, 64, 65, - 0, 0, 66, 0, 0, 1243, 1244, 1245, 1246, 1247, - 1248, 1249, 1250, 1251, 1252, 1253, 0, 1254, 1255, 1256, - 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 0, - 0, 1394, 0, 541, 0, 1397, 1266, 1267, 1268, 1269, - 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, - 1280, 1281, 1282, 1283, 1284, 0, 0, 1285, 1286, 1287, - 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, - 1298, 1299, 1300, 1301, 1302, 1303, 0, 1304, 0, 1305, - 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 0, - 1315, 1316, 1317, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 0, 0, 0, 0, 0, 0, 0, 1318, - 0, 216, 0, 0, 0, 0, 1319, 1320, 1321, 1322, - 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, - 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, - 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, - 1353, 1354, 1355, 1356, 1357, 0, 637, 638, 1358, 1359, - 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, - 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1551, - 1379, 1380, 0, 73, 0, 0, 75, 76, 77, 78, - 0, 0, 0, 0, 0, 188, 189, 190, 399, 0, - 0, 73, 400, 0, 75, 76, 77, 78, 79, 0, - 0, 387, 388, 389, 401, 0, 0, 82, 85, 0, - 0, 83, 0, 0, 0, 0, 0, 0, 0, 84, - 0, 0, 0, 0, 0, 239, 85, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 0, - 228, 229, 230, 86, 191, 0, 513, 87, 88, 0, - 0, 0, 0, 0, 0, 0, 639, 192, 193, 0, - 191, 0, 0, 0, 93, 87, 88, 1472, 0, 95, - 0, 89, 1598, 192, 193, 0, 0, 0, 0, 402, - 403, 92, 93, 0, 0, 94, 0, 95, 0, 0, - 0, 0, 640, 0, 0, 0, 194, 195, 0, 196, - 0, 0, 0, 0, 0, 197, 0, 198, 641, 0, - 0, 1627, 390, 195, 0, 196, 0, 0, 0, 0, - 0, 197, 262, 198, 1243, 1244, 1245, 1246, 1247, 1248, - 1249, 1250, 1251, 1252, 1253, 0, 1254, 1255, 1256, 1257, - 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 0, 0, - 385, 0, 0, 0, 1086, 1266, 1267, 1268, 1269, 1270, - 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280, - 1281, 1282, 1283, 1284, 0, 0, 1285, 1286, 1287, 1288, - 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, - 1299, 1300, 1301, 1302, 1303, 0, 1304, 0, 1305, 1306, - 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 0, 1315, - 1316, 1317, 0, 0, 0, 0, 0, 0, 0, 0, - 1601, 0, 0, 0, 0, 0, 0, 0, 1318, 0, - 0, 0, 0, 0, 0, 1319, 1320, 1321, 1322, 1323, - 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, - 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, - 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, - 1354, 1355, 1356, 1357, 0, 0, 0, 1358, 1359, 1360, - 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, - 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 0, 1379, - 1380, 7, 8, 9, 10, 0, 11, 12, 13, 171, - 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 0, 0, 0, 0, 0, 0, 0, 15, - 72, 216, 0, 172, 74, 0, 173, 174, 175, 176, - 79, 80, 0, 0, 0, 21, 81, 0, 0, 177, - 23, 0, 0, 83, 0, 0, 0, 0, 0, 24, - 25, 178, 0, 0, 0, 27, 0, 0, 179, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 180, 0, 0, 0, 0, - 0, 0, 0, 0, 46, 0, 47, 48, 0, 49, - 0, 0, 0, 0, 50, 0, 0, 181, 182, 53, - 0, 0, 54, 89, 0, 0, 0, 55, 0, 0, - 56, 90, 91, 92, 183, 0, 0, 94, 0, 184, - 7, 8, 9, 10, 0, 11, 12, 13, 398, 0, - 0, 0, 59, 0, 0, 60, 61, 62, 0, 0, - 63, 0, 64, 65, 0, 0, 66, 0, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 0, - 228, 229, 230, 0, 0, 0, 1022, 0, 15, 399, - 0, 0, 172, 400, 0, 173, 174, 175, 176, 79, - 0, 0, 0, 0, 21, 401, 0, 0, 177, 23, - 0, 0, 83, 0, 0, 0, 0, 0, 24, 25, - 178, 0, 0, 0, 27, 0, 0, 179, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 180, 0, 0, 0, 0, 0, - 0, 0, 0, 46, 0, 47, 48, 0, 49, 0, - 0, 0, 0, 50, 0, 0, 181, 182, 53, 0, - 0, 54, 89, 0, 0, 0, 55, 0, 0, 56, - 402, 403, 92, 183, 0, 0, 94, 0, 184, 0, - 7, 8, 9, 10, 0, 11, 12, 13, 14, 0, - 0, 59, 159, 0, 60, 61, 62, 0, 0, 63, - 0, 64, 65, 0, 0, 66, 0, 0, 0, 0, - 0, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 0, 0, 0, 0, 0, 0, 0, 0, 15, 216, - 0, 0, 16, 0, 0, 17, 18, 19, 20, 0, - 0, 0, 0, 0, 21, 0, 0, 0, 22, 23, - 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, - 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 46, 0, 47, 48, 0, 49, 0, - 0, 0, 0, 50, 0, 0, 51, 52, 53, 0, - 0, 54, 0, 0, 0, 0, 55, 0, 0, 56, - 0, 0, 0, 57, 7, 8, 9, 10, 58, 11, - 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, - 0, 59, 0, 0, 60, 61, 62, 0, 0, 63, - 0, 160, 65, 0, 0, 66, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 0, 228, 229, - 230, 0, 15, 0, 1633, 0, 16, 0, 0, 17, - 18, 19, 20, 0, 0, 0, 0, 0, 21, 188, - 189, 190, 22, 23, 0, 0, 0, 0, 0, 0, - 0, 0, 24, 25, 26, 0, 0, 0, 27, 0, - 0, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 0, - 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, - 48, 0, 49, 0, 0, 0, 0, 50, 191, 0, - 51, 52, 53, 0, 0, 54, 0, 0, 0, 0, - 55, 192, 193, 56, 0, 0, 0, 57, 7, 8, - 9, 10, 58, 11, 12, 13, 14, 0, 0, 0, - 0, 0, 0, 0, 0, 59, 0, 0, 60, 61, - 62, 0, 0, 63, 0, 64, 65, 351, 0, 66, - 194, 195, 0, 196, 0, 0, 0, 0, 0, 197, - 0, 198, 0, 0, 0, 0, 15, 356, 0, 0, - 16, 0, 0, 17, 18, 19, 20, 0, 0, 0, - 0, 0, 21, 0, 0, 754, 22, 23, 0, 0, - 0, 659, 0, 0, 0, 0, 24, 25, 26, 0, - 0, 0, 27, 0, 0, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, - 0, 46, 0, 47, 48, 0, 49, 660, 0, 661, - 0, 50, 0, 0, 51, 52, 53, 0, 0, 54, - 0, 0, 0, 0, 55, 0, 662, 56, 0, 0, - 0, 57, 7, 8, 9, 10, 58, 11, 12, 13, - 14, 0, 0, 0, 0, 0, 0, 0, 0, 59, - 0, 0, 60, 61, 62, 0, 0, 63, 663, 64, - 65, 664, 665, 66, 0, 666, 0, 0, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 0, 0, 0, - 15, 743, 667, 0, 16, 0, 216, 17, 18, 19, - 20, 0, 0, 0, 668, 0, 21, 0, 0, 0, - 22, 23, 0, 0, 0, 0, 0, 0, 669, 0, - 24, 25, 26, 0, 0, 0, 27, 0, 0, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 0, 0, 0, - 0, 0, 0, 0, 0, 46, 0, 47, 48, 0, - 49, 0, 0, 0, 0, 50, 0, 0, 51, 52, - 53, 0, 0, 54, 0, 0, 0, 0, 55, 0, - 0, 56, 0, 0, 0, 57, 7, 8, 9, 10, - 58, 11, 12, 13, 14, 0, 0, 0, 0, 0, - 0, 0, 0, 59, 0, 0, 60, 61, 62, 0, - 0, 63, 0, 64, 65, 0, 0, 66, 0, 0, - 0, 511, 0, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 15, 228, 229, 230, 16, 0, - 0, 17, 18, 19, 20, 0, 0, 0, 0, 0, - 21, 0, 0, 0, 22, 23, 0, 0, 0, 0, - 0, 0, 0, 0, 24, 25, 26, 0, 0, 0, - 27, 0, 0, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, - 0, 47, 48, 0, 49, 0, 0, 0, 0, 50, - 0, 0, 51, 52, 53, 0, 0, 54, 0, 0, - 0, 0, 55, 0, 0, 56, 0, 0, 0, 57, - 7, 8, 9, 10, 58, 11, 12, 13, 14, 0, - 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, - 60, 61, 62, 0, 0, 63, 0, 64, 65, 876, - 0, 66, 0, 0, 0, 0, 207, 208, 209, 210, - 211, 212, 213, 214, 215, 0, 0, 0, 15, 0, - 0, 0, 16, 0, 216, 17, 18, 19, 20, 0, - 0, 0, 0, 0, 21, 0, 0, 0, 22, 23, - 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, - 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 0, 0, 0, 0, 0, - 0, 0, 0, 46, 0, 47, 48, 0, 49, 0, - 0, 0, 0, 50, 0, 0, 51, 52, 53, 0, - 0, 54, 0, 0, 0, 0, 55, 0, 0, 56, - 0, 0, 0, 57, 7, 8, 9, 10, 58, 11, - 12, 13, 14, 1083, 0, 0, 0, 0, 0, 0, - 0, 59, 0, 0, 60, 61, 62, 0, 0, 63, - 0, 64, 65, 0, 0, 66, 0, 0, 0, 1020, - 0, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 15, 228, 229, 230, 16, 0, 0, 17, - 18, 19, 20, 0, 0, 0, 0, 0, 21, 0, - 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, - 0, 0, 24, 25, 26, 0, 0, 0, 27, 0, - 0, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 0, - 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, - 48, 0, 49, 0, 0, 0, 0, 50, 0, 0, - 51, 52, 53, 0, 0, 54, 0, 0, 0, 0, - 55, 0, 0, 56, 0, 0, 0, 57, 7, 8, - 9, 10, 58, 11, 12, 13, 14, 1471, 0, 0, - 0, 0, 0, 0, 0, 59, 0, 0, 60, 61, - 62, 0, 0, 63, 0, 64, 65, 0, 0, 66, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 0, - 0, 0, 0, 0, 0, 0, 15, 0, 216, 0, - 16, 0, 0, 17, 18, 19, 20, 0, 0, 0, - 0, 0, 21, 0, 0, 0, 22, 23, 0, 0, - 0, 0, 0, 0, 0, 0, 24, 25, 26, 0, - 0, 0, 27, 0, 0, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, - 0, 46, 0, 47, 48, 0, 49, 0, 0, 0, - 0, 50, 0, 0, 51, 52, 53, 0, 0, 54, - 0, 0, 0, 0, 55, 0, 0, 56, 0, 0, - 0, 57, 7, 8, 9, 10, 58, 11, 12, 13, - 14, 0, 0, 0, 0, 0, 0, 0, 0, 59, - 0, 0, 60, 61, 62, 0, 0, 63, 0, 64, - 65, 1599, 1088, 66, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 0, 228, 229, 230, - 15, 0, 0, 0, 16, 0, 0, 17, 18, 19, - 20, 0, 0, 0, 0, 0, 21, 0, 0, 0, - 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 25, 26, 0, 0, 0, 27, 0, 0, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 0, 0, 0, - 0, 0, 0, 0, 0, 46, 0, 47, 48, 0, - 49, 0, 0, 0, 0, 50, 0, 0, 51, 52, - 53, 0, 0, 54, 0, 0, 0, 0, 55, 0, - 0, 56, 0, 0, 0, 57, 7, 8, 9, 10, - 58, 11, 12, 13, 14, 0, 1518, 1519, 1520, 1521, - 1522, 1523, 1524, 59, 0, 0, 60, 61, 62, 0, - 0, 63, 1525, 64, 65, 0, 0, 66, 0, 0, - 0, 0, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 0, 0, 0, 15, 0, 0, 0, 16, 0, - 216, 17, 18, 19, 20, 0, 0, 0, 0, 0, - 21, 0, 0, 0, 22, 23, 0, 0, 0, 0, - 0, 0, 0, 0, 24, 25, 26, 0, 0, 0, - 27, 0, 0, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 0, 0, 0, 0, 0, 0, 0, 0, 46, - 0, 47, 48, 0, 49, 0, 0, 0, 0, 50, - 0, 0, 51, 52, 53, 0, 0, 54, 0, 0, - 0, 0, 55, 0, 0, 56, 0, 0, 0, 57, - 7, 8, 9, 10, 58, 11, 12, 13, 0, 0, - 0, 0, 1504, 0, 0, 1530, 1531, 1532, 1533, 1534, - 0, 1535, 1536, 1537, 0, 63, 0, 64, 65, 0, - 0, 66, 0, 894, 0, 0, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 1439, 228, - 229, 230, 895, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1440, 188, 189, 190, 0, 1441, - 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, - 0, 0, 0, 0, 27, 0, 0, 0, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 7, 8, 9, 10, 0, 11, - 12, 13, 0, 0, 0, 0, 48, 0, 49, 0, - 0, 0, 0, 1442, 191, 0, 0, 0, 1443, 0, - 632, 1444, 0, 0, 0, 0, 55, 192, 193, 0, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 0, - 0, 0, 1439, 0, 0, 0, 0, 0, 216, 0, - 0, 1445, 0, 0, 1446, 1447, 1448, 0, 1440, 1449, - 633, 1505, 65, 1441, 0, 1451, 194, 195, 0, 196, - 0, 0, 24, 25, 0, 197, 0, 198, 27, 0, - 0, 0, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 48, 0, 49, 0, 0, 0, 0, 1442, 0, 0, - 0, 0, 1443, 0, 0, 1444, 555, 556, 557, 10, - 55, 11, 558, 559, 0, 0, 0, 0, 852, 0, - 0, 0, 0, 555, 556, 557, 10, 0, 11, 558, - 559, 0, 0, 0, 0, 704, 0, 0, 0, 0, - 0, 0, 0, 1449, 0, 1450, 65, 0, 0, 1451, - 0, 110, 0, 111, 561, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 0, 228, 229, 230, - 562, 561, 0, 0, 0, 563, 0, 0, 0, 0, - 0, 0, 0, 0, 564, 565, 0, 562, 0, 0, - 0, 0, 563, 209, 210, 211, 212, 213, 214, 215, - 0, 564, 565, 0, 0, 0, 0, 0, 0, 216, - 0, 0, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 566, - 0, 0, 567, 0, 568, 0, 0, 0, 1525, 569, - 0, 0, 0, 0, 570, 0, 566, 571, 0, 567, - 0, 568, 572, 0, 0, 573, 569, 0, 0, 0, - 0, 570, 0, 0, 571, 0, 0, 0, 0, 572, - 0, 0, 573, 0, 0, 0, 0, 574, 0, 0, - 575, 576, 0, 0, 0, 577, 0, 578, 0, 0, - 0, 579, 0, 0, 574, 0, 0, 575, 576, 1092, - 0, 0, 577, 0, 705, 0, 0, 0, 579, 1093, - 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 0, 0, - 0, 0, 0, 0, 188, 189, 190, 1102, 0, 1103, - 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, - 1114, 0, 0, 0, 0, 0, 0, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 0, 228, 229, - 230, 0, 0, 1115, 0, 0, 1527, 1528, 1529, 637, - 638, 1530, 1531, 1532, 1533, 1534, 0, 1535, 1536, 1537, - 0, 0, 0, 191, 0, 0, 0, 0, 0, 0, - 211, 212, 213, 214, 215, 0, 192, 193, 0, 0, - 0, 0, 0, 0, 216, 0, 0, 0, 0, 1116, - 0, 399, 0, 0, 73, 400, 0, 75, 76, 77, - 78, 79, 0, 0, 0, 0, 0, 401, 0, 0, - 82, 0, 0, 0, 83, 194, 195, 0, 196, 0, - 0, 0, 84, 0, 197, 0, 198, 0, 0, 85, - 1117, 0, 0, 1118, 0, 1119, 1120, 1121, 1122, 1123, - 1124, 1125, 1126, 1127, 1128, 1129, 86, 1130, 1131, 766, - 767, 1132, 0, 0, 0, 0, 0, 0, 0, 639, - 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, - 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, - 0, 0, 402, 403, 92, 93, 0, 0, 94, 0, - 95, 399, 0, 0, 73, 400, 0, 75, 76, 77, - 78, 79, 0, 0, 0, 0, 0, 401, 0, 0, - 82, 641, 0, 0, 83, 221, 222, 223, 224, 225, - 226, 227, 84, 228, 229, 230, 0, 0, 0, 85, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 0, - 0, 0, 0, 0, 0, 0, 86, 0, 216, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 0, 639, - 0, 0, 0, 0, 0, 0, 0, 216, 87, 88, - 0, 0, 0, 73, 89, 0, 75, 76, 77, 78, - 0, 0, 402, 403, 92, 93, 0, 0, 94, 238, - 95, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 0, 0, 0, 0, 0, 0, 0, 0, 85, 216, - 0, 641, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 0, 0, 0, 0, 239, 0, 0, 0, 0, - 216, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 0, 0, 0, 0, 0, 0, 0, 87, 88, 216, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 0, - 0, 0, 0, 0, 93, 0, 0, 0, 216, 95, - 0, 0, 0, 0, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 0, 228, 229, 230, - 308, 0, 144, 0, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 0, 228, 229, 230, 499, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 216, 0, - 0, 0, 0, 0, 0, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 0, 228, 229, - 230, 515, 0, 0, 0, 0, 0, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 0, 228, - 229, 230, 594, 0, 0, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 0, 228, 229, - 230, 651, 0, 0, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 0, 228, 229, 230, - 752, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 216, 0, - 0, 0, 0, 0, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 0, 228, 229, 230, - 880, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, - 719, 720, 721, 722, 723, 724, 725, 726, 727, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 728, 209, - 210, 211, 212, 213, 214, 215, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 216, 1518, 1519, 1520, 1521, - 1522, 1523, 1524, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1525, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 0, 228, 229, - 230, 962, 0, 0, 0, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 0, 228, 229, 230, - 1018, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1525, 0, 0, - 0, 0, 1412, 0, 0, 0, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 0, 228, 229, - 230, 0, 0, 0, 0, 729, 730, 731, 732, 733, - 734, 735, 736, 737, 738, 739, 0, 740, 741, 742, - 601, 0, 0, 659, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 0, 228, 229, 230, 0, 0, 0, - 0, 1528, 1529, 0, 0, 1530, 1531, 1532, 1533, 1534, - 0, 1535, 1536, 1537, 110, 0, 111, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 413, 660, - 0, 661, 0, 0, 0, 0, 0, 414, 415, 416, - 417, 0, 0, 0, 0, 0, 0, 0, 662, 0, - 419, 420, 421, 422, 0, 601, 0, 0, 0, 0, - 0, 0, 0, 535, 0, 0, 0, 1529, 0, 0, - 1530, 1531, 1532, 1533, 1534, 0, 1535, 1536, 1537, 0, - 663, 0, 0, 664, 665, 0, 0, 666, 432, 0, - 0, 896, 897, 898, 0, 0, 0, 0, 0, 437, - 0, 0, 0, 413, 667, 0, 438, 0, 0, 0, - 440, 441, 414, 415, 416, 417, 668, 0, 0, 0, - 0, 0, 444, 0, 445, 419, 534, 421, 422, 0, - 669, 0, 0, 0, 0, 0, 73, 0, 535, 75, - 76, 77, 78, 899, 900, 896, 897, 898, 0, 0, - 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 432, 84, 0, 0, 0, 0, 0, - 0, 85, 0, 0, 437, 0, 0, 0, 0, 0, - 0, 438, 0, 0, 0, 0, 441, 0, 86, 0, - 73, 0, 0, 75, 76, 77, 78, 444, 0, 445, - 0, 0, 0, 70, 71, 0, 82, 0, 0, 0, - 87, 88, 0, 0, 0, 0, 0, 0, 84, 0, - 0, 0, 0, 0, 901, 85, 0, 93, 0, 0, - 94, 902, 95, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 86, 0, 72, 0, 0, 73, 74, 0, - 75, 76, 77, 78, 79, 80, 0, 0, 0, 0, - 81, 0, 0, 82, 87, 88, 0, 83, 70, 71, - 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, - 0, 93, 85, 0, 94, 0, 95, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, - 0, 70, 0, 0, 0, 0, 0, 0, 0, 72, - 0, 0, 73, 74, 0, 75, 76, 77, 78, 79, - 0, 87, 88, 0, 0, 81, 0, 89, 82, 0, - 0, 0, 83, 0, 0, 90, 91, 92, 93, 0, - 84, 94, 72, 95, 0, 73, 74, 85, 75, 76, - 77, 78, 79, 777, 0, 0, 0, 0, 81, 0, - 0, 82, 0, 0, 86, 83, 145, 0, 0, 0, - 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, - 85, 0, 0, 0, 0, 0, 87, 88, 0, 0, - 0, 0, 89, 0, 0, 0, 0, 86, 0, 145, - 90, 91, 92, 93, 0, 0, 94, 146, 95, 0, - 73, 147, 0, 75, 76, 77, 78, 79, 965, 87, - 88, 0, 0, 148, 0, 89, 82, 0, 0, 0, - 83, 0, 0, 90, 91, 92, 93, 0, 84, 94, - 146, 95, 0, 73, 147, 85, 75, 76, 77, 78, - 79, 0, 0, 0, 0, 0, 148, 0, 0, 82, - 0, 0, 86, 83, 70, 0, 0, 0, 0, 0, - 0, 84, 0, 0, 0, 0, 0, 0, 85, 0, - 0, 188, 189, 190, 87, 88, 0, 0, 0, 0, - 89, 0, 0, 0, 0, 86, 0, 0, 149, 150, - 92, 93, 0, 0, 94, 72, 95, 0, 73, 74, - 0, 75, 76, 77, 78, 79, 0, 87, 88, 0, - 0, 81, 0, 89, 82, 0, 0, 0, 83, 0, - 0, 149, 150, 92, 93, 0, 84, 94, 0, 95, - 191, 0, 0, 85, 0, 0, 0, 0, 188, 189, - 190, 0, 0, 192, 193, 0, 0, 0, 0, 0, - 86, 0, 0, 188, 189, 190, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 188, 189, - 190, 0, 87, 88, 0, 0, 0, 0, 89, 0, - 0, 0, 194, 998, 999, 1000, 90, 91, 92, 93, - 0, 197, 94, 198, 95, 0, 0, 191, 0, 0, - 0, 0, 0, 0, 1001, 0, 0, 0, 0, 1002, - 192, 193, 191, 0, 0, 0, 0, 0, 73, 0, - 0, 75, 76, 77, 78, 192, 193, 191, 0, 0, - 188, 189, 190, 0, 0, 1039, 0, 0, 0, 0, - 192, 193, 73, 0, 0, 75, 76, 77, 78, 194, - 195, 0, 196, 85, 0, 0, 0, 0, 197, 0, - 198, 0, 0, 0, 194, 195, 0, 196, 0, 0, - 239, 1001, 0, 197, 0, 198, 1170, 85, 0, 194, - 195, 0, 196, 0, 0, 0, 1001, 0, 197, 191, - 198, 1172, 87, 88, 239, 0, 0, 0, 0, 0, - 0, 1001, 192, 193, 0, 0, 1174, 0, 0, 93, - 0, 0, 0, 0, 95, 0, 87, 88, 73, 0, - 0, 75, 76, 77, 78, 0, 0, 0, 0, 0, - 0, 0, 0, 93, 0, 0, 0, 157, 95, 0, - 0, 194, 195, 0, 196, 0, 0, 0, 0, 0, - 197, 0, 198, 85, 0, 413, 0, 0, 0, 0, - 0, 158, 0, 0, 414, 415, 416, 417, 0, 0, - 239, 0, 0, 0, 0, 0, 0, 419, 534, 421, - 422, 0, 0, 0, 0, 424, 0, 0, 0, 0, - 535, 0, 87, 88, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, - 0, 0, 0, 0, 95, 432, 0, 0, 0, 412, - 413, 0, 0, 0, 0, 0, 437, 0, 0, 414, - 415, 416, 417, 438, 0, 0, 0, 164, 441, 0, - 418, 0, 419, 420, 421, 422, 423, 0, 443, 444, - 424, 445, 0, 0, 0, 425, 0, 0, 0, 0, - 413, 0, 0, 0, 0, 0, -161, 0, 0, 414, - 415, 416, 417, 0, 426, 427, 428, 429, 430, 431, - 432, 433, 419, 534, 421, 422, 0, 0, 434, 435, - 436, 437, 0, 0, 0, 535, 0, 0, 438, 439, - 413, 0, 440, 441, 0, 0, 0, 442, 0, 414, - 415, 416, 417, 443, 444, 0, 445, 413, 0, 0, - 432, 608, 419, 420, 421, 422, 414, 415, 416, 417, - 424, 437, 0, 0, 0, 535, 0, 0, 438, 419, - 534, 421, 422, 441, 0, 0, 0, 0, 0, 0, - 0, 0, 535, 0, 444, 0, 445, 0, 0, 0, - 432, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 437, 0, 0, 0, 0, 0, 432, 438, 0, - 0, 0, 440, 441, 0, 0, 0, 0, 437, 0, - 0, 0, 0, 443, 444, 438, 445, 0, 0, 0, - 441, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 444, 0, 445 -}; - -static const yytype_int16 yycheck[] = -{ - 1, 97, 397, 80, 64, 115, 420, 117, 118, 119, - 120, 121, 440, 123, 440, 125, 397, 127, 46, 46, - 374, 506, 1083, 80, 46, 550, 912, 566, 549, 15, - 266, 266, 10, 13, 144, 13, 934, 768, 396, 86, - 87, 88, 685, 266, 266, 15, 93, 157, 158, 6, - 48, 8, 50, 157, 164, 165, 831, 15, 681, 413, - 414, 415, 416, 417, 65, 419, 420, 421, 62, 967, - 15, 425, 175, 176, 15, 179, 17, 921, 432, 160, - 924, 925, 926, 437, 438, 82, 440, 441, 442, 537, - 444, 445, 617, 0, 175, 96, 97, 10, 11, 12, - 160, 507, 34, 48, 174, 50, 48, 48, 50, 50, - 48, 34, 50, 114, 115, 174, 117, 118, 119, 120, - 121, 157, 123, 82, 125, 6, 127, 8, 48, 34, - 50, 174, 15, 180, 181, 182, 183, 233, 234, 82, - 176, 135, 157, 144, 260, 261, 48, 48, 50, 50, - 48, 174, 50, 249, 250, 251, 157, 158, 539, 156, - 158, 176, 159, 164, 165, 48, 34, 50, 160, 229, - 813, 814, 174, 919, 817, 570, 998, 999, 1000, 954, - 534, 535, 48, 175, 50, 157, 34, 157, 82, 169, - 176, 169, 239, 157, 552, 305, 160, 156, 174, 157, - 159, 947, 203, 949, 176, 48, 952, 50, 121, 165, - 249, 250, 251, 156, 449, 5, 159, 1061, 156, 176, - 64, 1065, 1066, 164, 955, 160, 449, 449, 169, 754, - 174, 175, 233, 234, 174, 177, 159, 156, 266, 266, - 175, 173, 174, 175, 266, 156, 159, 601, 249, 250, - 251, 174, 175, 254, 779, 174, 165, 177, 157, 798, - 175, 176, 156, 174, 907, 159, 174, 268, 173, 174, - 175, 48, 116, 50, 174, 177, 177, 176, 122, 177, - 124, 157, 126, 174, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 176, 169, 170, 171, 305, 173, 174, 175, 175, 176, - 1056, 177, 156, 103, 104, 34, 160, 174, 162, 163, - 174, 1052, 361, 718, 325, 173, 174, 175, 174, 368, - 369, 974, 34, 818, 177, 978, 979, 718, 385, 1237, - 157, 153, 154, 155, 1090, 830, 157, 795, 1170, 0, - 1172, 174, 1174, 157, 174, 1177, 1178, 1179, 981, 176, - 361, 882, 152, 153, 157, 176, 174, 368, 369, 157, - 993, 1146, 176, 374, 174, 10, 11, 12, 379, 380, - 156, 165, 158, 176, 160, 1229, 165, 157, 176, 1135, - 1136, 626, 1035, 1036, 630, 630, 397, 48, 752, 50, - 244, 1044, 1045, 626, 626, 1048, 176, 630, 630, 157, - 1471, 157, 413, 414, 415, 416, 417, 174, 419, 420, - 421, 449, 449, 157, 425, 174, 965, 449, 176, 174, - 176, 432, 158, 6, 69, 8, 437, 438, 174, 440, - 441, 442, 176, 444, 445, 1068, 174, 82, 83, 174, - 169, 170, 171, 174, 173, 174, 175, 174, 248, 536, - 304, 157, 252, 253, 174, 167, 168, 169, 170, 171, - 955, 173, 174, 175, 69, 70, 592, 593, 517, 536, - 176, 1006, 157, 522, 523, 524, 121, 122, 900, 124, - 902, 174, 531, 532, 533, 130, 157, 132, 174, 894, - 1025, 176, 549, 175, 176, 506, 507, 1032, 23, 24, - 916, 175, 176, 1156, 920, 176, 517, 1140, 578, 34, - 174, 522, 523, 524, 157, 174, 157, 157, 157, 157, - 531, 532, 533, 534, 535, 157, 537, 157, 566, 566, - 157, 176, 174, 176, 566, 176, 176, 176, 176, 550, - 551, 156, 176, 158, 176, 160, 176, 160, 1202, 176, - 1204, 174, 639, 174, 970, 971, 972, 1052, 1454, 359, - 360, 1214, 1215, 1216, 10, 11, 12, 22, 23, 24, - 1478, 371, 372, 373, 174, 175, 646, 647, 174, 34, - 174, 10, 11, 12, 654, 174, 656, 174, 626, 626, - 601, 169, 630, 630, 626, 395, 607, 174, 630, 1037, - 156, 1037, 158, 156, 160, 158, 617, 160, 408, 409, - 122, 123, 124, 1037, 156, 157, 470, 174, 472, 156, - 474, 174, 49, 69, 174, 175, 675, 175, 175, 1385, - 679, 680, 177, 433, 157, 705, 82, 83, 174, 166, - 69, 34, 167, 168, 169, 170, 171, 157, 173, 174, - 175, 166, 778, 82, 83, 1071, 174, 175, 176, 670, - 176, 787, 176, 156, 675, 158, 159, 160, 679, 680, - 681, 741, 176, 1037, 685, 121, 122, 176, 124, 174, - 175, 176, 176, 157, 130, 696, 132, 174, 175, 176, - 777, 176, 121, 122, 176, 124, 176, 176, 176, 176, - 176, 130, 166, 132, 10, 11, 12, 13, 508, 176, - 157, 17, 167, 168, 169, 170, 171, 176, 173, 174, - 175, 521, 176, 843, 578, 525, 526, 765, 176, 175, - 166, 160, 176, 176, 176, 164, 590, 15, 176, 176, - 169, 752, 176, 754, 10, 11, 12, 13, 176, 15, - 176, 17, 801, 176, 765, 176, 176, 63, 176, 176, - 798, 798, 176, 176, 174, 1223, 798, 778, 779, 1227, - 176, 1556, 1557, 1558, 167, 168, 169, 170, 171, 176, - 173, 174, 175, 159, 795, 1438, 912, 176, 176, 159, - 801, 591, 174, 919, 594, 921, 174, 63, 924, 925, - 926, 812, 813, 814, 176, 159, 817, 818, 174, 174, - 174, 174, 174, 174, 120, 121, 159, 1233, 159, 830, - 831, 947, 159, 949, 174, 882, 952, 174, 174, 169, - 174, 176, 843, 175, 634, 82, 13, 176, 15, 175, - 17, 176, 174, 177, 150, 699, 700, 701, 179, 703, - 174, 705, 165, 707, 708, 121, 165, 165, 164, 174, - 966, 127, 900, 169, 902, 165, 176, 165, 174, 176, - 174, 158, 174, 673, 674, 176, 34, 176, 159, 176, - 1665, 176, 156, 49, 150, 174, 63, 687, 1673, 174, - 690, 691, 176, 176, 694, 159, 907, 176, 164, 156, - 22, 23, 24, 169, 157, 916, 157, 157, 174, 920, - 921, 157, 34, 924, 925, 926, 157, 157, 156, 174, - 174, 158, 158, 156, 169, 160, 169, 965, 965, 940, - 1056, 179, 943, 965, 686, 1061, 175, 156, 166, 1065, - 1066, 157, 174, 954, 955, 1403, 1404, 1405, 174, 13, - 127, 15, 174, 17, 166, 966, 176, 166, 176, 970, - 971, 972, 762, 974, 1090, 166, 176, 978, 979, 10, - 981, 10, 10, 150, 10, 10, 10, 10, 11, 12, - 13, 166, 993, 158, 17, 157, 176, 164, 169, 169, - 1395, 1407, 169, 177, 1410, 1006, 158, 174, 158, 63, - 1038, 169, 175, 15, 1395, 175, 1464, 174, 157, 1135, - 1136, 811, 176, 174, 1025, 815, 816, 1028, 174, 819, - 157, 1032, 176, 823, 1035, 1036, 1037, 827, 828, 174, - 63, 157, 1043, 1044, 1045, 160, 157, 1048, 1049, 839, - 1456, 1052, 157, 1149, 1460, 167, 168, 169, 170, 171, - 1061, 173, 174, 175, 1065, 1066, 169, 1068, 158, 176, - 1071, 915, 174, 127, 158, 176, 175, 177, 158, 177, - 157, 10, 1083, 825, 826, 176, 179, 829, 157, 176, - 179, 177, 174, 176, 884, 176, 150, 1545, 121, 174, - 176, 179, 10, 10, 127, 1553, 158, 10, 176, 10, - 164, 1559, 1560, 1229, 158, 169, 10, 13, 10, 15, - 174, 17, 157, 1183, 1184, 174, 1186, 150, 1188, 1239, - 1240, 179, 177, 923, 176, 156, 1542, 927, 928, 1140, - 930, 164, 932, 179, 176, 1146, 169, 157, 1149, 158, - 165, 174, 174, 165, 1602, 1156, 946, 1605, 176, 165, - 950, 951, 165, 174, 177, 907, 956, 63, 176, 158, - 177, 961, 176, 10, 158, 176, 176, 176, 10, 969, - 10, 158, 158, 973, 10, 158, 174, 15, 1636, 176, - 176, 176, 65, 157, 984, 985, 177, 1603, 177, 157, - 166, 1202, 176, 1204, 176, 166, 1654, 166, 176, 166, - 10, 176, 158, 1214, 1215, 1216, 176, 90, 10, 10, - 158, 174, 1223, 174, 174, 158, 1227, 176, 1229, 174, - 158, 127, 1233, 176, 176, 10, 158, 110, 1239, 1240, - 176, 158, 1238, 607, 986, 1398, 1454, 1038, 990, 991, - 630, 1562, 1042, 1395, 150, 718, 1046, 1047, 10, 11, - 12, 13, 570, 630, 1007, 17, 1358, 324, 164, 1385, - 1060, -1, -1, 169, -1, 2, 149, 20, 21, 22, - 23, 24, 1398, -1, -1, -1, -1, -1, -1, -1, - -1, 34, -1, 1035, 1036, -1, -1, -1, -1, 1089, - -1, -1, 1044, 1045, -1, -1, 1048, -1, -1, -1, - -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, - 47, -1, -1, -1, -1, -1, 53, 200, 201, -1, - -1, -1, 59, 60, 61, 62, 63, -1, 1454, 66, - -1, -1, -1, 1133, -1, -1, 10, 11, 12, -1, - -1, -1, -1, -1, -1, 228, -1, 1358, -1, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 1212, 121, - -1, -1, -1, -1, 247, 127, -1, 34, -1, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 261, 262, - 1450, 1181, -1, -1, 1395, -1, -1, 34, 150, -1, - 1190, -1, 1403, 1404, 1405, 69, 1407, -1, -1, 1410, - 1200, -1, 164, -1, -1, -1, -1, 169, 82, 83, - 1162, -1, -1, 1213, 167, 168, 169, 170, 171, -1, - 173, 174, 175, 306, 307, -1, 163, 1438, -1, 312, - -1, -1, -1, -1, -1, 1505, -1, -1, -1, -1, - -1, 324, -1, -1, -1, 1456, -1, 121, 122, 1460, - 124, -1, -1, 1464, 23, 24, 130, -1, 132, -1, - 1471, -1, 1214, 1215, 1216, 34, 1536, -1, -1, 143, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, -1, 1217, 230, 161, 162, 163, 164, 235, -1, - 167, 168, 169, 170, 171, -1, 173, 174, 175, -1, - -1, -1, 159, 396, 161, 162, 163, 164, -1, 402, - 167, 168, 169, 170, 171, -1, 173, 174, 175, 266, - -1, 1542, -1, -1, 1545, -1, -1, -1, -1, -1, - -1, -1, 1553, -1, -1, 1556, 1557, 1558, 1559, 1560, - -1, 1562, -1, -1, -1, -1, -1, -1, -1, -1, - 443, -1, -1, -1, -1, 302, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1647, 1648, 1649, - -1, 1651, 319, 320, -1, -1, -1, 1387, -1, 326, - -1, 1602, 1603, -1, 1605, -1, 1450, -1, 167, 168, - 169, 170, 171, -1, 173, 174, 175, -1, 1408, -1, - -1, 1411, -1, -1, 18, 19, 20, 21, 22, 23, - 24, -1, 505, 55, -1, 1636, 58, 59, 60, 61, - 34, 10, 11, 12, -1, -1, -1, 520, -1, 71, - -1, -1, 379, 1654, -1, -1, 1500, 1501, 1502, 1503, - -1, 1505, -1, 1507, 1665, 1455, -1, -1, 90, 1459, - 543, -1, 1673, 1463, -1, -1, -1, -1, -1, 552, - -1, -1, -1, -1, -1, 107, 1476, -1, -1, 1479, - 1480, 1481, -1, -1, -1, 422, 1438, -1, -1, -1, - 69, -1, -1, -1, -1, -1, -1, 129, 130, -1, - -1, -1, -1, 82, 83, -1, -1, -1, -1, 592, - 593, -1, -1, -1, 146, -1, -1, -1, 1443, 151, - 1445, 1446, 1447, 1448, 1449, 608, 1451, 610, 611, 612, - 613, 614, 615, -1, -1, 618, -1, -1, -1, -1, - -1, -1, 121, 122, -1, 124, -1, 1547, -1, 632, - 633, 130, -1, 132, -1, -1, -1, -1, 641, 496, - 164, 165, 166, 167, 168, 169, 170, 171, -1, 173, - 174, 175, -1, -1, 511, -1, -1, -1, 1217, -1, - -1, 3, 4, 5, 6, 164, 8, 9, 10, -1, - 169, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, - 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1532, 1533, 1534, - 1610, -1, -1, -1, -1, 1615, 1616, 18, 19, 20, - 21, 22, 23, 24, -1, -1, -1, -1, -1, 51, - -1, -1, -1, 34, 1634, -1, -1, 574, 575, 576, - 577, -1, 579, -1, -1, 67, -1, -1, -1, -1, - 72, 588, 1577, -1, -1, 1655, -1, 740, -1, 81, - 82, -1, -1, -1, 1664, 87, -1, -1, -1, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, -1, -1, 624, 17, 18, - 19, 20, 21, 22, 23, 24, -1, 119, -1, 121, - -1, -1, -1, 1628, 126, 34, 1631, -1, -1, 131, - -1, -1, 134, -1, 797, -1, -1, 139, 17, 18, - 19, 20, 21, 22, 23, 24, -1, -1, 665, -1, - -1, -1, -1, -1, -1, 34, -1, -1, -1, 822, - -1, -1, 164, -1, 681, 167, 168, 169, -1, -1, - 172, -1, 174, 175, -1, -1, 178, -1, -1, -1, - -1, -1, 845, -1, 165, 166, 167, 168, 169, 170, - 171, 708, 173, 174, 175, -1, -1, -1, -1, -1, - -1, -1, 719, 720, 721, 722, 723, 724, 725, 726, - 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, - 737, 738, 739, -1, 1443, 742, 1445, 1446, 1447, 1448, - 1449, -1, 1451, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 905, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, -1, 173, 174, 175, 784, -1, -1, - 10, 11, 12, 936, -1, 3, 4, 5, 6, -1, - 8, 9, 10, 162, 163, 164, -1, 15, 167, 168, - 169, 170, 171, -1, 173, 174, 175, 1516, 1517, 1518, - 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, - 1529, 1530, 1531, 1532, 1533, 1534, -1, -1, -1, -1, - 48, -1, 50, 51, -1, -1, -1, -1, -1, 69, - -1, -1, -1, 850, -1, -1, -1, -1, 1001, 67, - -1, -1, 82, 83, 72, -1, -1, -1, -1, -1, - -1, -1, 11, 81, 82, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 1039, -1, -1, -1, - -1, 121, 122, -1, 124, -1, -1, -1, 116, -1, - 130, 119, 132, 121, -1, -1, 55, -1, 126, 58, - 59, 60, 61, 131, -1, -1, 134, -1, -1, -1, - -1, 139, 1631, -1, 142, -1, 156, 3, 4, 5, - 6, -1, 8, 9, 10, 11, 943, -1, -1, -1, - -1, 90, -1, -1, -1, -1, 164, -1, -1, 167, - 168, -1, -1, -1, 172, -1, 174, -1, 107, -1, - 178, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 981, 51, -1, -1, -1, 55, - 129, 130, 58, 59, 60, 61, 993, -1, -1, -1, - 997, 67, -1, 69, 70, 71, 72, 146, -1, -1, - -1, -1, 151, -1, -1, 81, 82, 83, 1015, -1, - -1, 87, -1, 1020, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, -1, -1, -1, -1, -1, -1, -1, -1, - 116, -1, 118, 119, -1, 121, -1, -1, -1, -1, - 126, -1, -1, 129, 130, 131, -1, -1, 134, -1, - -1, 1068, -1, 139, -1, -1, 142, -1, -1, -1, - 146, -1, -1, -1, -1, 151, 1083, -1, -1, -1, - 156, -1, -1, -1, -1, 1238, -1, -1, 164, -1, - -1, 167, 168, 169, -1, -1, 172, -1, 174, 175, - -1, -1, 178, -1, -1, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, -1, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, -1, - -1, 1138, -1, 1140, -1, 1142, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, -1, -1, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, -1, 75, -1, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, -1, - 88, 89, 90, 16, 17, 18, 19, 20, 21, 22, - 23, 24, -1, -1, -1, -1, -1, -1, -1, 107, - -1, 34, -1, -1, -1, -1, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, -1, 10, 11, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, -1, 55, -1, -1, 58, 59, 60, 61, - -1, -1, -1, -1, -1, 10, 11, 12, 52, -1, - -1, 55, 56, -1, 58, 59, 60, 61, 62, -1, - -1, 10, 11, 12, 68, -1, -1, 71, 90, -1, - -1, 75, -1, -1, -1, -1, -1, -1, -1, 83, - -1, -1, -1, -1, -1, 107, 90, -1, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, -1, - 173, 174, 175, 107, 69, -1, 179, 129, 130, -1, - -1, -1, -1, -1, -1, -1, 120, 82, 83, -1, - 69, -1, -1, -1, 146, 129, 130, 1384, -1, 151, - -1, 135, 1535, 82, 83, -1, -1, -1, -1, 143, - 144, 145, 146, -1, -1, 149, -1, 151, -1, -1, - -1, -1, 156, -1, -1, -1, 121, 122, -1, 124, - -1, -1, -1, -1, -1, 130, -1, 132, 172, -1, - -1, 1574, 121, 122, -1, 124, -1, -1, -1, -1, - -1, 130, 147, 132, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, -1, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, -1, -1, - 159, -1, -1, -1, 1471, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, -1, -1, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, -1, 75, -1, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, -1, 88, - 89, 90, -1, -1, -1, -1, -1, -1, -1, -1, - 1537, -1, -1, -1, -1, -1, -1, -1, 107, -1, - -1, -1, -1, -1, -1, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, -1, -1, -1, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, -1, 178, - 179, 3, 4, 5, 6, -1, 8, 9, 10, 11, - 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 16, 17, 18, 19, 20, 21, 22, - 23, 24, -1, -1, -1, -1, -1, -1, -1, 51, - 52, 34, -1, 55, 56, -1, 58, 59, 60, 61, - 62, 63, -1, -1, -1, 67, 68, -1, -1, 71, - 72, -1, -1, 75, -1, -1, -1, -1, -1, 81, - 82, 83, -1, -1, -1, 87, -1, -1, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, -1, -1, -1, -1, - -1, -1, -1, -1, 116, -1, 118, 119, -1, 121, - -1, -1, -1, -1, 126, -1, -1, 129, 130, 131, - -1, -1, 134, 135, -1, -1, -1, 139, -1, -1, - 142, 143, 144, 145, 146, -1, -1, 149, -1, 151, - 3, 4, 5, 6, -1, 8, 9, 10, 11, -1, - -1, -1, 164, -1, -1, 167, 168, 169, -1, -1, - 172, -1, 174, 175, -1, -1, 178, -1, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, -1, - 173, 174, 175, -1, -1, -1, 179, -1, 51, 52, - -1, -1, 55, 56, -1, 58, 59, 60, 61, 62, - -1, -1, -1, -1, 67, 68, -1, -1, 71, 72, - -1, -1, 75, -1, -1, -1, -1, -1, 81, 82, - 83, -1, -1, -1, 87, -1, -1, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, -1, -1, -1, -1, -1, - -1, -1, -1, 116, -1, 118, 119, -1, 121, -1, - -1, -1, -1, 126, -1, -1, 129, 130, 131, -1, - -1, 134, 135, -1, -1, -1, 139, -1, -1, 142, - 143, 144, 145, 146, -1, -1, 149, -1, 151, -1, - 3, 4, 5, 6, -1, 8, 9, 10, 11, -1, - -1, 164, 15, -1, 167, 168, 169, -1, -1, 172, - -1, 174, 175, -1, -1, 178, -1, -1, -1, -1, - -1, 16, 17, 18, 19, 20, 21, 22, 23, 24, - -1, -1, -1, -1, -1, -1, -1, -1, 51, 34, - -1, -1, 55, -1, -1, 58, 59, 60, 61, -1, - -1, -1, -1, -1, 67, -1, -1, -1, 71, 72, - -1, -1, -1, -1, -1, -1, -1, -1, 81, 82, - 83, -1, -1, -1, 87, -1, -1, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, -1, -1, -1, -1, -1, - -1, -1, -1, 116, -1, 118, 119, -1, 121, -1, - -1, -1, -1, 126, -1, -1, 129, 130, 131, -1, - -1, 134, -1, -1, -1, -1, 139, -1, -1, 142, - -1, -1, -1, 146, 3, 4, 5, 6, 151, 8, - 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, - -1, 164, -1, -1, 167, 168, 169, -1, -1, 172, - -1, 174, 175, -1, -1, 178, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, -1, 173, 174, - 175, -1, 51, -1, 179, -1, 55, -1, -1, 58, - 59, 60, 61, -1, -1, -1, -1, -1, 67, 10, - 11, 12, 71, 72, -1, -1, -1, -1, -1, -1, - -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, - -1, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, -1, - -1, -1, -1, -1, -1, -1, -1, 116, -1, 118, - 119, -1, 121, -1, -1, -1, -1, 126, 69, -1, - 129, 130, 131, -1, -1, 134, -1, -1, -1, -1, - 139, 82, 83, 142, -1, -1, -1, 146, 3, 4, - 5, 6, 151, 8, 9, 10, 11, -1, -1, -1, - -1, -1, -1, -1, -1, 164, -1, -1, 167, 168, - 169, -1, -1, 172, -1, 174, 175, 176, -1, 178, - 121, 122, -1, 124, -1, -1, -1, -1, -1, 130, - -1, 132, -1, -1, -1, -1, 51, 52, -1, -1, - 55, -1, -1, 58, 59, 60, 61, -1, -1, -1, - -1, -1, 67, -1, -1, 156, 71, 72, -1, -1, - -1, 17, -1, -1, -1, -1, 81, 82, 83, -1, - -1, -1, 87, -1, -1, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, -1, -1, -1, -1, -1, -1, -1, - -1, 116, -1, 118, 119, -1, 121, 63, -1, 65, - -1, 126, -1, -1, 129, 130, 131, -1, -1, 134, - -1, -1, -1, -1, 139, -1, 82, 142, -1, -1, - -1, 146, 3, 4, 5, 6, 151, 8, 9, 10, - 11, -1, -1, -1, -1, -1, -1, -1, -1, 164, - -1, -1, 167, 168, 169, -1, -1, 172, 114, 174, - 175, 117, 118, 178, -1, 121, -1, -1, 16, 17, - 18, 19, 20, 21, 22, 23, 24, -1, -1, -1, - 51, 52, 138, -1, 55, -1, 34, 58, 59, 60, - 61, -1, -1, -1, 150, -1, 67, -1, -1, -1, - 71, 72, -1, -1, -1, -1, -1, -1, 164, -1, - 81, 82, 83, -1, -1, -1, 87, -1, -1, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, -1, -1, -1, - -1, -1, -1, -1, -1, 116, -1, 118, 119, -1, - 121, -1, -1, -1, -1, 126, -1, -1, 129, 130, - 131, -1, -1, 134, -1, -1, -1, -1, 139, -1, - -1, 142, -1, -1, -1, 146, 3, 4, 5, 6, - 151, 8, 9, 10, 11, -1, -1, -1, -1, -1, - -1, -1, -1, 164, -1, -1, 167, 168, 169, -1, - -1, 172, -1, 174, 175, -1, -1, 178, -1, -1, - -1, 159, -1, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 51, 173, 174, 175, 55, -1, - -1, 58, 59, 60, 61, -1, -1, -1, -1, -1, - 67, -1, -1, -1, 71, 72, -1, -1, -1, -1, - -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, - 87, -1, -1, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, -1, -1, -1, -1, -1, -1, -1, -1, 116, - -1, 118, 119, -1, 121, -1, -1, -1, -1, 126, - -1, -1, 129, 130, 131, -1, -1, 134, -1, -1, - -1, -1, 139, -1, -1, 142, -1, -1, -1, 146, - 3, 4, 5, 6, 151, 8, 9, 10, 11, -1, - -1, -1, -1, -1, -1, -1, -1, 164, -1, -1, - 167, 168, 169, -1, -1, 172, -1, 174, 175, 176, - -1, 178, -1, -1, -1, -1, 16, 17, 18, 19, - 20, 21, 22, 23, 24, -1, -1, -1, 51, -1, - -1, -1, 55, -1, 34, 58, 59, 60, 61, -1, - -1, -1, -1, -1, 67, -1, -1, -1, 71, 72, - -1, -1, -1, -1, -1, -1, -1, -1, 81, 82, - 83, -1, -1, -1, 87, -1, -1, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, -1, -1, -1, -1, -1, - -1, -1, -1, 116, -1, 118, 119, -1, 121, -1, - -1, -1, -1, 126, -1, -1, 129, 130, 131, -1, - -1, 134, -1, -1, -1, -1, 139, -1, -1, 142, - -1, -1, -1, 146, 3, 4, 5, 6, 151, 8, - 9, 10, 11, 156, -1, -1, -1, -1, -1, -1, - -1, 164, -1, -1, 167, 168, 169, -1, -1, 172, - -1, 174, 175, -1, -1, 178, -1, -1, -1, 159, - -1, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 51, 173, 174, 175, 55, -1, -1, 58, - 59, 60, 61, -1, -1, -1, -1, -1, 67, -1, - -1, -1, 71, 72, -1, -1, -1, -1, -1, -1, - -1, -1, 81, 82, 83, -1, -1, -1, 87, -1, - -1, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, -1, - -1, -1, -1, -1, -1, -1, -1, 116, -1, 118, - 119, -1, 121, -1, -1, -1, -1, 126, -1, -1, - 129, 130, 131, -1, -1, 134, -1, -1, -1, -1, - 139, -1, -1, 142, -1, -1, -1, 146, 3, 4, - 5, 6, 151, 8, 9, 10, 11, 156, -1, -1, - -1, -1, -1, -1, -1, 164, -1, -1, 167, 168, - 169, -1, -1, 172, -1, 174, 175, -1, -1, 178, - 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, - -1, -1, -1, -1, -1, -1, 51, -1, 34, -1, - 55, -1, -1, 58, 59, 60, 61, -1, -1, -1, - -1, -1, 67, -1, -1, -1, 71, 72, -1, -1, - -1, -1, -1, -1, -1, -1, 81, 82, 83, -1, - -1, -1, 87, -1, -1, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, -1, -1, -1, -1, -1, -1, -1, - -1, 116, -1, 118, 119, -1, 121, -1, -1, -1, - -1, 126, -1, -1, 129, 130, 131, -1, -1, 134, - -1, -1, -1, -1, 139, -1, -1, 142, -1, -1, - -1, 146, 3, 4, 5, 6, 151, 8, 9, 10, - 11, -1, -1, -1, -1, -1, -1, -1, -1, 164, - -1, -1, 167, 168, 169, -1, -1, 172, -1, 174, - 175, 176, 158, 178, -1, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, -1, 173, 174, 175, - 51, -1, -1, -1, 55, -1, -1, 58, 59, 60, - 61, -1, -1, -1, -1, -1, 67, -1, -1, -1, - 71, 72, -1, -1, -1, -1, -1, -1, -1, -1, - 81, 82, 83, -1, -1, -1, 87, -1, -1, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, -1, -1, -1, - -1, -1, -1, -1, -1, 116, -1, 118, 119, -1, - 121, -1, -1, -1, -1, 126, -1, -1, 129, 130, - 131, -1, -1, 134, -1, -1, -1, -1, 139, -1, - -1, 142, -1, -1, -1, 146, 3, 4, 5, 6, - 151, 8, 9, 10, 11, -1, 18, 19, 20, 21, - 22, 23, 24, 164, -1, -1, 167, 168, 169, -1, - -1, 172, 34, 174, 175, -1, -1, 178, -1, -1, - -1, -1, 16, 17, 18, 19, 20, 21, 22, 23, - 24, -1, -1, -1, 51, -1, -1, -1, 55, -1, - 34, 58, 59, 60, 61, -1, -1, -1, -1, -1, - 67, -1, -1, -1, 71, 72, -1, -1, -1, -1, - -1, -1, -1, -1, 81, 82, 83, -1, -1, -1, - 87, -1, -1, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, -1, -1, -1, -1, -1, -1, -1, -1, 116, - -1, 118, 119, -1, 121, -1, -1, -1, -1, 126, - -1, -1, 129, 130, 131, -1, -1, 134, -1, -1, - -1, -1, 139, -1, -1, 142, -1, -1, -1, 146, - 3, 4, 5, 6, 151, 8, 9, 10, -1, -1, - -1, -1, 15, -1, -1, 167, 168, 169, 170, 171, - -1, 173, 174, 175, -1, 172, -1, 174, 175, -1, - -1, 178, -1, 157, -1, -1, -1, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 51, 173, - 174, 175, 176, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 67, 10, 11, 12, -1, 72, - -1, -1, -1, -1, -1, -1, -1, -1, 81, 82, - -1, -1, -1, -1, 87, -1, -1, -1, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 3, 4, 5, 6, -1, 8, - 9, 10, -1, -1, -1, -1, 119, -1, 121, -1, - -1, -1, -1, 126, 69, -1, -1, -1, 131, -1, - 75, 134, -1, -1, -1, -1, 139, 82, 83, -1, - 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, - -1, -1, 51, -1, -1, -1, -1, -1, 34, -1, - -1, 164, -1, -1, 167, 168, 169, -1, 67, 172, - 115, 174, 175, 72, -1, 178, 121, 122, -1, 124, - -1, -1, 81, 82, -1, 130, -1, 132, 87, -1, - -1, -1, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 119, -1, 121, -1, -1, -1, -1, 126, -1, -1, - -1, -1, 131, -1, -1, 134, 3, 4, 5, 6, - 139, 8, 9, 10, -1, -1, -1, -1, 15, -1, - -1, -1, -1, 3, 4, 5, 6, -1, 8, 9, - 10, -1, -1, -1, -1, 15, -1, -1, -1, -1, - -1, -1, -1, 172, -1, 174, 175, -1, -1, 178, - -1, 48, -1, 50, 51, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, -1, 173, 174, 175, - 67, 51, -1, -1, -1, 72, -1, -1, -1, -1, - -1, -1, -1, -1, 81, 82, -1, 67, -1, -1, - -1, -1, 72, 18, 19, 20, 21, 22, 23, 24, - -1, 81, 82, -1, -1, -1, -1, -1, -1, 34, - -1, -1, 18, 19, 20, 21, 22, 23, 24, 116, - -1, -1, 119, -1, 121, -1, -1, -1, 34, 126, - -1, -1, -1, -1, 131, -1, 116, 134, -1, 119, - -1, 121, 139, -1, -1, 142, 126, -1, -1, -1, - -1, 131, -1, -1, 134, -1, -1, -1, -1, 139, - -1, -1, 142, -1, -1, -1, -1, 164, -1, -1, - 167, 168, -1, -1, -1, 172, -1, 174, -1, -1, - -1, 178, -1, -1, 164, -1, -1, 167, 168, 6, - -1, -1, 172, -1, 174, -1, -1, -1, 178, 16, - 17, 18, 19, 20, 21, 22, 23, 24, -1, -1, - -1, -1, -1, -1, 10, 11, 12, 34, -1, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, -1, -1, -1, -1, -1, -1, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, -1, 173, 174, - 175, -1, -1, 70, -1, -1, 162, 163, 164, 10, - 11, 167, 168, 169, 170, 171, -1, 173, 174, 175, - -1, -1, -1, 69, -1, -1, -1, -1, -1, -1, - 20, 21, 22, 23, 24, -1, 82, 83, -1, -1, - -1, -1, -1, -1, 34, -1, -1, -1, -1, 116, - -1, 52, -1, -1, 55, 56, -1, 58, 59, 60, - 61, 62, -1, -1, -1, -1, -1, 68, -1, -1, - 71, -1, -1, -1, 75, 121, 122, -1, 124, -1, - -1, -1, 83, -1, 130, -1, 132, -1, -1, 90, - 157, -1, -1, 160, -1, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 107, 174, 175, 10, - 11, 178, -1, -1, -1, -1, -1, -1, -1, 120, - -1, -1, -1, -1, -1, -1, -1, -1, 129, 130, - -1, -1, -1, -1, 135, -1, -1, -1, -1, -1, - -1, -1, 143, 144, 145, 146, -1, -1, 149, -1, - 151, 52, -1, -1, 55, 56, -1, 58, 59, 60, - 61, 62, -1, -1, -1, -1, -1, 68, -1, -1, - 71, 172, -1, -1, 75, 165, 166, 167, 168, 169, - 170, 171, 83, 173, 174, 175, -1, -1, -1, 90, - 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, - -1, -1, -1, -1, -1, -1, 107, -1, 34, 16, - 17, 18, 19, 20, 21, 22, 23, 24, -1, 120, - -1, -1, -1, -1, -1, -1, -1, 34, 129, 130, - -1, -1, -1, 55, 135, -1, 58, 59, 60, 61, - -1, -1, 143, 144, 145, 146, -1, -1, 149, 71, - 151, 16, 17, 18, 19, 20, 21, 22, 23, 24, - -1, -1, -1, -1, -1, -1, -1, -1, 90, 34, - -1, 172, 16, 17, 18, 19, 20, 21, 22, 23, - 24, -1, -1, -1, -1, 107, -1, -1, -1, -1, - 34, 16, 17, 18, 19, 20, 21, 22, 23, 24, - -1, -1, -1, -1, -1, -1, -1, 129, 130, 34, - 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, - -1, -1, -1, -1, 146, -1, -1, -1, 34, 151, - -1, -1, -1, -1, -1, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, -1, 173, 174, 175, - 176, -1, 174, -1, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, -1, 173, 174, 175, 176, - 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 34, -1, - -1, -1, -1, -1, -1, -1, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, -1, 173, 174, - 175, 176, -1, -1, -1, -1, -1, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, -1, 173, - 174, 175, 176, -1, -1, -1, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, -1, 173, 174, - 175, 176, -1, -1, -1, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, -1, 173, 174, 175, - 176, 16, 17, 18, 19, 20, 21, 22, 23, 24, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, - 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 34, -1, - -1, -1, -1, -1, -1, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, -1, 173, 174, 175, - 176, 16, 17, 18, 19, 20, 21, 22, 23, 24, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, - 16, 17, 18, 19, 20, 21, 22, 23, 24, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 34, 18, - 19, 20, 21, 22, 23, 24, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 34, 18, 19, 20, 21, - 22, 23, 24, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 34, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, -1, 173, 174, - 175, 176, -1, -1, -1, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, -1, 173, 174, 175, - 176, 18, 19, 20, 21, 22, 23, 24, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 34, -1, -1, - -1, -1, 157, -1, -1, -1, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, -1, 173, 174, - 175, -1, -1, -1, -1, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, -1, 173, 174, 175, - 6, -1, -1, 17, 163, 164, 165, 166, 167, 168, - 169, 170, 171, -1, 173, 174, 175, -1, -1, -1, - -1, 163, 164, -1, -1, 167, 168, 169, 170, 171, - -1, 173, 174, 175, 48, -1, 50, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 54, 63, - -1, 65, -1, -1, -1, -1, -1, 63, 64, 65, - 66, -1, -1, -1, -1, -1, -1, -1, 82, -1, - 76, 77, 78, 79, -1, 6, -1, -1, -1, -1, - -1, -1, -1, 89, -1, -1, -1, 164, -1, -1, - 167, 168, 169, 170, 171, -1, 173, 174, 175, -1, - 114, -1, -1, 117, 118, -1, -1, 121, 114, -1, - -1, 10, 11, 12, -1, -1, -1, -1, -1, 125, - -1, -1, -1, 54, 138, -1, 132, -1, -1, -1, - 136, 137, 63, 64, 65, 66, 150, -1, -1, -1, - -1, -1, 148, -1, 150, 76, 77, 78, 79, -1, - 164, -1, -1, -1, -1, -1, 55, -1, 89, 58, - 59, 60, 61, 62, 63, 10, 11, 12, -1, -1, - -1, -1, 71, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 114, 83, -1, -1, -1, -1, -1, - -1, 90, -1, -1, 125, -1, -1, -1, -1, -1, - -1, 132, -1, -1, -1, -1, 137, -1, 107, -1, - 55, -1, -1, 58, 59, 60, 61, 148, -1, 150, - -1, -1, -1, 11, 12, -1, 71, -1, -1, -1, - 129, 130, -1, -1, -1, -1, -1, -1, 83, -1, - -1, -1, -1, -1, 143, 90, -1, 146, -1, -1, - 149, 150, 151, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 107, -1, 52, -1, -1, 55, 56, -1, - 58, 59, 60, 61, 62, 63, -1, -1, -1, -1, - 68, -1, -1, 71, 129, 130, -1, 75, 11, 12, - -1, -1, -1, -1, -1, 83, -1, -1, -1, -1, - -1, 146, 90, -1, 149, -1, 151, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 107, - -1, 11, -1, -1, -1, -1, -1, -1, -1, 52, - -1, -1, 55, 56, -1, 58, 59, 60, 61, 62, - -1, 129, 130, -1, -1, 68, -1, 135, 71, -1, - -1, -1, 75, -1, -1, 143, 144, 145, 146, -1, - 83, 149, 52, 151, -1, 55, 56, 90, 58, 59, - 60, 61, 62, 63, -1, -1, -1, -1, 68, -1, - -1, 71, -1, -1, 107, 75, 11, -1, -1, -1, - -1, -1, -1, 83, -1, -1, -1, -1, -1, -1, - 90, -1, -1, -1, -1, -1, 129, 130, -1, -1, - -1, -1, 135, -1, -1, -1, -1, 107, -1, 11, - 143, 144, 145, 146, -1, -1, 149, 52, 151, -1, - 55, 56, -1, 58, 59, 60, 61, 62, 63, 129, - 130, -1, -1, 68, -1, 135, 71, -1, -1, -1, - 75, -1, -1, 143, 144, 145, 146, -1, 83, 149, - 52, 151, -1, 55, 56, 90, 58, 59, 60, 61, - 62, -1, -1, -1, -1, -1, 68, -1, -1, 71, - -1, -1, 107, 75, 11, -1, -1, -1, -1, -1, - -1, 83, -1, -1, -1, -1, -1, -1, 90, -1, - -1, 10, 11, 12, 129, 130, -1, -1, -1, -1, - 135, -1, -1, -1, -1, 107, -1, -1, 143, 144, - 145, 146, -1, -1, 149, 52, 151, -1, 55, 56, - -1, 58, 59, 60, 61, 62, -1, 129, 130, -1, - -1, 68, -1, 135, 71, -1, -1, -1, 75, -1, - -1, 143, 144, 145, 146, -1, 83, 149, -1, 151, - 69, -1, -1, 90, -1, -1, -1, -1, 10, 11, - 12, -1, -1, 82, 83, -1, -1, -1, -1, -1, - 107, -1, -1, 10, 11, 12, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, - 12, -1, 129, 130, -1, -1, -1, -1, 135, -1, - -1, -1, 121, 122, 123, 124, 143, 144, 145, 146, - -1, 130, 149, 132, 151, -1, -1, 69, -1, -1, - -1, -1, -1, -1, 143, -1, -1, -1, -1, 148, - 82, 83, 69, -1, -1, -1, -1, -1, 55, -1, - -1, 58, 59, 60, 61, 82, 83, 69, -1, -1, - 10, 11, 12, -1, -1, 15, -1, -1, -1, -1, - 82, 83, 55, -1, -1, 58, 59, 60, 61, 121, - 122, -1, 124, 90, -1, -1, -1, -1, 130, -1, - 132, -1, -1, -1, 121, 122, -1, 124, -1, -1, - 107, 143, -1, 130, -1, 132, 148, 90, -1, 121, - 122, -1, 124, -1, -1, -1, 143, -1, 130, 69, - 132, 148, 129, 130, 107, -1, -1, -1, -1, -1, - -1, 143, 82, 83, -1, -1, 148, -1, -1, 146, - -1, -1, -1, -1, 151, -1, 129, 130, 55, -1, - -1, 58, 59, 60, 61, -1, -1, -1, -1, -1, - -1, -1, -1, 146, -1, -1, -1, 174, 151, -1, - -1, 121, 122, -1, 124, -1, -1, -1, -1, -1, - 130, -1, 132, 90, -1, 54, -1, -1, -1, -1, - -1, 174, -1, -1, 63, 64, 65, 66, -1, -1, - 107, -1, -1, -1, -1, -1, -1, 76, 77, 78, - 79, -1, -1, -1, -1, 84, -1, -1, -1, -1, - 89, -1, 129, 130, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 146, - -1, -1, -1, -1, 151, 114, -1, -1, -1, 53, - 54, -1, -1, -1, -1, -1, 125, -1, -1, 63, - 64, 65, 66, 132, -1, -1, -1, 174, 137, -1, - 74, -1, 76, 77, 78, 79, 80, -1, 147, 148, - 84, 150, -1, -1, -1, 89, -1, -1, -1, -1, - 54, -1, -1, -1, -1, -1, 165, -1, -1, 63, - 64, 65, 66, -1, 108, 109, 110, 111, 112, 113, - 114, 115, 76, 77, 78, 79, -1, -1, 122, 123, - 124, 125, -1, -1, -1, 89, -1, -1, 132, 133, - 54, -1, 136, 137, -1, -1, -1, 141, -1, 63, - 64, 65, 66, 147, 148, -1, 150, 54, -1, -1, - 114, 115, 76, 77, 78, 79, 63, 64, 65, 66, - 84, 125, -1, -1, -1, 89, -1, -1, 132, 76, - 77, 78, 79, 137, -1, -1, -1, -1, -1, -1, - -1, -1, 89, -1, 148, -1, 150, -1, -1, -1, - 114, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 125, -1, -1, -1, -1, -1, 114, 132, -1, - -1, -1, 136, 137, -1, -1, -1, -1, 125, -1, - -1, -1, -1, 147, 148, 132, 150, -1, -1, -1, - 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 148, -1, 150 -}; - -/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of - state STATE-NUM. */ -static const yytype_int16 yystos[] = -{ - 0, 153, 154, 155, 181, 182, 292, 3, 4, 5, - 6, 8, 9, 10, 11, 51, 55, 58, 59, 60, - 61, 67, 71, 72, 81, 82, 83, 87, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 116, 118, 119, 121, - 126, 129, 130, 131, 134, 139, 142, 146, 151, 164, - 167, 168, 169, 172, 174, 175, 178, 282, 283, 291, - 11, 12, 52, 55, 56, 58, 59, 60, 61, 62, - 63, 68, 71, 75, 83, 90, 107, 129, 130, 135, - 143, 144, 145, 146, 149, 151, 244, 245, 249, 250, - 252, 258, 260, 264, 265, 270, 271, 272, 273, 0, - 48, 50, 192, 292, 156, 174, 174, 174, 174, 174, - 174, 174, 165, 174, 165, 174, 174, 174, 174, 174, - 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, - 174, 174, 174, 174, 174, 11, 52, 56, 68, 143, - 144, 247, 264, 265, 270, 282, 165, 174, 174, 15, - 174, 282, 165, 174, 174, 174, 282, 282, 282, 282, - 282, 11, 55, 58, 59, 60, 61, 71, 83, 90, - 107, 129, 130, 146, 151, 249, 280, 282, 10, 11, - 12, 69, 82, 83, 121, 122, 124, 130, 132, 160, - 164, 169, 286, 287, 289, 292, 282, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 34, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 173, 174, - 175, 6, 8, 244, 245, 174, 62, 135, 71, 107, - 271, 271, 271, 289, 174, 271, 13, 15, 17, 63, - 127, 150, 164, 169, 174, 242, 243, 292, 243, 259, - 192, 192, 147, 193, 194, 289, 174, 158, 183, 279, - 280, 292, 279, 249, 279, 279, 279, 279, 279, 249, - 279, 249, 279, 249, 279, 249, 249, 249, 249, 249, - 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, - 249, 279, 174, 289, 174, 174, 192, 192, 176, 249, - 279, 279, 174, 249, 249, 249, 282, 279, 279, 176, - 157, 176, 289, 289, 157, 179, 160, 232, 292, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 289, 176, 280, 282, 243, 243, 52, 282, 249, 169, - 289, 192, 242, 243, 242, 243, 242, 243, 192, 192, - 15, 17, 164, 169, 192, 227, 228, 237, 292, 175, - 156, 10, 11, 12, 121, 159, 290, 10, 11, 12, - 121, 156, 289, 290, 289, 49, 157, 174, 11, 52, - 56, 68, 143, 144, 246, 250, 252, 258, 264, 265, - 270, 282, 53, 54, 63, 64, 65, 66, 74, 76, - 77, 78, 79, 80, 84, 89, 108, 109, 110, 111, - 112, 113, 114, 115, 122, 123, 124, 125, 132, 133, - 136, 137, 141, 147, 148, 150, 186, 188, 189, 191, - 195, 215, 266, 269, 292, 177, 176, 176, 176, 176, - 176, 176, 176, 166, 176, 166, 176, 176, 176, 176, - 157, 176, 157, 176, 157, 176, 176, 176, 176, 176, - 176, 176, 176, 176, 176, 176, 176, 282, 249, 279, - 289, 289, 166, 176, 176, 289, 176, 166, 176, 176, - 176, 176, 282, 282, 15, 164, 287, 174, 212, 292, - 282, 159, 176, 179, 176, 176, 176, 192, 192, 13, - 15, 17, 63, 127, 150, 164, 169, 242, 292, 242, - 242, 192, 192, 192, 77, 89, 191, 176, 15, 157, - 278, 282, 292, 262, 263, 292, 11, 261, 271, 159, - 251, 253, 159, 192, 193, 3, 4, 5, 9, 10, - 15, 51, 67, 72, 81, 82, 116, 119, 121, 126, - 131, 134, 139, 142, 164, 167, 168, 172, 174, 178, - 229, 230, 237, 238, 284, 285, 291, 292, 174, 289, - 174, 176, 192, 192, 176, 191, 191, 191, 191, 191, - 191, 6, 191, 215, 191, 282, 159, 190, 115, 191, - 174, 174, 174, 174, 174, 174, 191, 156, 192, 159, - 159, 159, 191, 191, 174, 189, 191, 195, 216, 191, - 191, 199, 75, 115, 289, 191, 191, 10, 11, 120, - 156, 172, 202, 206, 246, 248, 174, 174, 249, 249, - 249, 176, 176, 176, 174, 176, 174, 232, 227, 17, - 63, 65, 82, 114, 117, 118, 121, 138, 150, 164, - 192, 282, 242, 169, 289, 192, 242, 242, 242, 192, - 192, 175, 242, 242, 242, 244, 245, 212, 15, 237, - 179, 289, 177, 261, 182, 82, 254, 292, 193, 174, - 165, 165, 247, 165, 15, 174, 284, 165, 174, 282, - 282, 282, 282, 249, 280, 282, 176, 15, 157, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 34, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 173, 174, 175, 52, 282, 249, 192, 289, 290, 289, - 192, 191, 176, 188, 156, 289, 289, 289, 289, 289, - 289, 289, 182, 289, 282, 165, 10, 11, 206, 246, - 248, 289, 289, 158, 192, 174, 174, 63, 244, 187, - 289, 197, 156, 158, 160, 234, 158, 196, 280, 280, - 176, 176, 176, 280, 280, 176, 282, 174, 34, 225, - 292, 192, 192, 242, 242, 242, 278, 176, 176, 176, - 13, 17, 63, 127, 150, 164, 169, 174, 240, 290, - 292, 13, 15, 17, 63, 127, 150, 164, 169, 174, - 241, 192, 192, 192, 177, 159, 255, 256, 292, 49, - 249, 249, 249, 174, 249, 174, 249, 249, 249, 282, - 176, 176, 15, 238, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 289, 176, 280, 282, 176, - 176, 176, 159, 191, 182, 156, 157, 157, 157, 157, - 157, 157, 177, 156, 157, 176, 10, 11, 12, 62, - 63, 143, 150, 217, 218, 219, 220, 221, 270, 292, - 174, 234, 200, 158, 158, 160, 203, 10, 13, 169, - 205, 244, 13, 17, 63, 127, 150, 164, 169, 239, - 290, 292, 182, 174, 156, 158, 159, 160, 233, 274, - 275, 69, 70, 156, 282, 13, 17, 63, 120, 150, - 164, 169, 174, 198, 222, 224, 290, 176, 176, 176, - 176, 212, 176, 176, 289, 63, 247, 156, 242, 179, - 174, 174, 174, 169, 192, 240, 240, 240, 192, 192, - 240, 175, 232, 192, 169, 289, 192, 241, 241, 241, - 192, 192, 241, 175, 232, 225, 157, 160, 122, 123, - 124, 143, 148, 257, 288, 289, 156, 157, 192, 176, - 166, 166, 279, 166, 289, 176, 166, 176, 176, 282, - 159, 176, 179, 261, 177, 268, 10, 10, 10, 10, - 10, 10, 267, 291, 158, 221, 221, 166, 157, 15, - 289, 13, 17, 63, 127, 150, 164, 169, 174, 240, - 241, 201, 224, 249, 227, 176, 169, 222, 227, 239, - 169, 192, 239, 239, 239, 192, 192, 174, 175, 192, - 177, 207, 274, 184, 185, 289, 69, 70, 177, 276, - 292, 158, 158, 156, 235, 236, 282, 292, 158, 169, - 192, 222, 6, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 34, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 70, 116, 157, 160, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 174, 175, 178, 213, 222, 192, 192, 222, 159, 174, - 175, 225, 160, 232, 234, 192, 192, 15, 176, 247, - 243, 274, 192, 227, 227, 227, 192, 240, 240, 240, - 176, 278, 192, 192, 241, 241, 241, 176, 278, 282, - 148, 288, 148, 288, 148, 288, 289, 122, 123, 124, - 15, 182, 257, 174, 174, 176, 174, 176, 174, 282, - 182, 157, 157, 176, 157, 226, 292, 157, 157, 157, - 182, 176, 240, 241, 240, 241, 189, 195, 214, 215, - 220, 289, 160, 169, 192, 192, 192, 160, 231, 292, - 232, 234, 158, 176, 174, 222, 176, 176, 174, 192, - 239, 239, 239, 210, 278, 227, 177, 156, 157, 156, - 174, 158, 158, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 75, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 88, 89, 90, 107, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 178, - 179, 277, 235, 177, 157, 192, 222, 10, 176, 179, - 192, 222, 222, 176, 282, 223, 278, 282, 157, 225, - 176, 243, 177, 176, 176, 176, 240, 174, 179, 241, - 174, 179, 157, 288, 288, 288, 288, 288, 288, 177, - 280, 280, 280, 280, 177, 10, 10, 158, 10, 176, - 10, 10, 10, 177, 158, 231, 231, 249, 192, 51, - 67, 72, 126, 131, 134, 164, 167, 168, 169, 172, - 174, 178, 281, 283, 157, 212, 204, 176, 174, 212, - 211, 239, 227, 179, 176, 274, 185, 279, 279, 276, - 177, 156, 282, 222, 192, 229, 179, 198, 156, 212, - 212, 212, 227, 192, 227, 192, 176, 176, 176, 176, - 176, 157, 176, 157, 158, 157, 176, 176, 157, 176, - 174, 165, 165, 165, 15, 174, 281, 165, 281, 281, - 281, 281, 281, 249, 280, 281, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 34, 161, 162, 163, 164, - 167, 168, 169, 170, 171, 173, 174, 175, 201, 192, - 227, 174, 208, 192, 227, 176, 192, 212, 177, 177, - 176, 177, 235, 176, 192, 274, 192, 192, 192, 176, - 176, 158, 10, 158, 10, 10, 158, 158, 10, 158, - 249, 249, 249, 249, 174, 249, 249, 176, 176, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 289, 176, - 280, 282, 176, 209, 227, 176, 212, 192, 15, 177, - 212, 177, 225, 225, 225, 212, 212, 157, 226, 176, - 157, 157, 176, 176, 166, 166, 166, 289, 176, 166, - 281, 159, 176, 179, 212, 227, 176, 212, 192, 192, - 192, 10, 176, 158, 10, 10, 158, 174, 174, 174, - 176, 174, 281, 192, 176, 212, 158, 176, 157, 176, - 280, 280, 280, 280, 212, 192, 158, 10, 158, 176, - 176, 176, 176, 192, 225, 176, 225, 158 -}; - -/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ -static const yytype_int16 yyr1[] = -{ - 0, 180, 181, 181, 181, 182, 182, 183, 182, 184, - 184, 185, 185, 185, 187, 186, 188, 188, 188, 188, - 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, - 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, - 188, 188, 188, 190, 189, 191, 191, 191, 191, 191, - 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, - 191, 191, 191, 192, 192, 192, 192, 192, 193, 193, - 194, 194, 196, 195, 195, 197, 195, 195, 195, 198, - 198, 200, 199, 199, 201, 201, 203, 202, 204, 202, - 205, 202, 207, 206, 208, 206, 209, 206, 210, 206, - 211, 206, 206, 212, 212, 212, 212, 212, 212, 212, - 212, 212, 212, 212, 212, 212, 212, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 213, 213, 214, 214, 214, - 215, 216, 215, 215, 215, 217, 217, 218, 218, 219, - 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, - 220, 220, 221, 221, 221, 221, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 222, 222, 223, 222, 224, - 224, 225, 225, 225, 226, 226, 227, 227, 227, 227, - 227, 228, 228, 229, 229, 229, 229, 229, 230, 230, - 231, 231, 232, 232, 233, 233, 233, 233, 233, 234, - 234, 234, 234, 234, 234, 235, 235, 235, 236, 236, - 236, 236, 237, 237, 238, 238, 239, 239, 239, 239, - 239, 239, 239, 239, 239, 239, 240, 240, 240, 240, - 240, 240, 240, 240, 240, 240, 240, 240, 241, 241, - 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, - 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, - 242, 243, 243, 243, 243, 243, 243, 243, 243, 243, - 243, 243, 243, 243, 243, 243, 244, 244, 244, 244, - 244, 244, 244, 244, 244, 244, 244, 244, 244, 245, - 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, - 246, 246, 246, 246, 247, 247, 247, 247, 247, 247, - 247, 247, 247, 248, 248, 249, 249, 249, 249, 251, - 250, 253, 252, 254, 254, 255, 255, 256, 256, 257, - 257, 257, 257, 257, 257, 257, 257, 257, 257, 259, - 258, 260, 260, 260, 260, 261, 261, 262, 262, 262, - 263, 263, 263, 264, 264, 264, 265, 265, 265, 267, - 266, 268, 266, 266, 266, 269, 269, 269, 269, 270, - 270, 270, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 272, 272, 272, - 273, 275, 274, 276, 276, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 278, 278, 279, 279, 280, 280, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 284, 284, 284, 284, 284, 284, 284, 284, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, - 284, 284, 284, 284, 284, 284, 284, 285, 285, 285, - 285, 285, 285, 285, 285, 285, 285, 285, 286, 286, - 286, 286, 286, 287, 287, 287, 287, 288, 288, 288, - 289, 289, 289, 289, 289, 289, 289, 289, 289, 289, - 289, 290, 290, 290, 290, 291, 291, 291, 291, 292 -}; - -/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ -static const yytype_int8 yyr2[] = -{ - 0, 2, 2, 2, 2, 1, 3, 0, 4, 1, - 3, 4, 5, 4, 0, 5, 1, 1, 1, 1, - 1, 2, 1, 1, 2, 2, 2, 2, 8, 11, - 9, 11, 13, 15, 7, 9, 12, 9, 9, 13, - 9, 7, 5, 0, 3, 1, 2, 2, 3, 2, - 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 1, 4, 7, 5, 5, 1, 3, - 1, 4, 0, 4, 3, 0, 4, 3, 1, 2, - 4, 0, 4, 3, 2, 4, 0, 7, 0, 10, - 0, 7, 0, 8, 0, 12, 0, 13, 0, 8, - 0, 9, 1, 1, 2, 2, 2, 4, 2, 2, - 2, 2, 2, 2, 4, 5, 6, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, - 2, 0, 6, 2, 2, 1, 1, 1, 3, 1, - 1, 1, 2, 4, 2, 3, 3, 4, 2, 3, - 4, 3, 1, 1, 1, 1, 2, 3, 4, 2, - 2, 3, 3, 3, 4, 5, 3, 0, 7, 2, - 3, 1, 3, 4, 1, 2, 1, 1, 1, 3, - 2, 1, 3, 1, 1, 1, 3, 2, 1, 3, - 1, 2, 1, 2, 1, 3, 5, 3, 3, 1, - 3, 3, 3, 3, 4, 1, 1, 2, 1, 3, - 3, 5, 5, 5, 1, 1, 1, 2, 2, 2, - 2, 3, 3, 3, 4, 5, 1, 2, 2, 2, - 2, 3, 3, 3, 4, 5, 8, 3, 1, 3, - 2, 2, 2, 3, 3, 3, 4, 5, 8, 3, - 1, 1, 3, 2, 2, 2, 3, 3, 3, 4, - 5, 1, 1, 3, 2, 2, 2, 3, 3, 3, - 4, 5, 6, 11, 11, 11, 1, 1, 2, 1, - 1, 1, 3, 5, 4, 4, 4, 1, 1, 1, - 1, 1, 2, 1, 1, 1, 3, 5, 3, 4, - 4, 4, 1, 1, 1, 1, 2, 3, 3, 4, - 4, 1, 1, 1, 1, 2, 3, 2, 3, 0, - 6, 0, 9, 1, 1, 1, 1, 2, 3, 1, - 2, 2, 2, 3, 3, 3, 3, 3, 3, 0, - 5, 4, 2, 5, 3, 1, 1, 1, 4, 6, - 1, 3, 5, 1, 2, 2, 1, 1, 1, 0, - 7, 0, 7, 4, 5, 3, 6, 4, 4, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 2, 2, 1, 1, 2, - 1, 0, 2, 1, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, - 4, 7, 7, 7, 7, 4, 2, 5, 4, 2, - 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 5, 4, 4, 3, 3, 3, 3, 1, - 4, 7, 7, 7, 7, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 5, 4, 2, 5, 4, 4, 2, 2, - 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 5, 4, 4, 3, 3, 3, 3, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 9, 12, 4, 4, 6, 4, 4, 6, - 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 1, 4, 7, 7, 7, 7, 4, 2, - 5, 4, 2, 5, 4, 4, 2, 2, 2, 2, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 5, 4, 4, 3, 3, 3, 3, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 4, 2, 3, 1, 2, 1, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 2, 2, 0 -}; - - -enum { YYENOMEM = -2 }; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab -#define YYNOMEM goto yyexhaustedlab - - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ - do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (&yylloc, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ - while (0) - -/* Backward compatibility with an undocumented macro. - Use YYerror or YYUNDEF. */ -#define YYERRCODE YYUNDEF - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (N) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (0) -#endif - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - - -/* YYLOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -# ifndef YYLOCATION_PRINT - -# if defined YY_LOCATION_PRINT - - /* Temporary convenience wrapper in case some people defined the - undocumented and private YY_LOCATION_PRINT macros. */ -# define YYLOCATION_PRINT(File, Loc) YY_LOCATION_PRINT(File, *(Loc)) - -# elif defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL - -/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ - -YY_ATTRIBUTE_UNUSED -static int -yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) -{ - int res = 0; - int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; - if (0 <= yylocp->first_line) - { - res += YYFPRINTF (yyo, "%d", yylocp->first_line); - if (0 <= yylocp->first_column) - res += YYFPRINTF (yyo, ".%d", yylocp->first_column); - } - if (0 <= yylocp->last_line) - { - if (yylocp->first_line < yylocp->last_line) - { - res += YYFPRINTF (yyo, "-%d", yylocp->last_line); - if (0 <= end_col) - res += YYFPRINTF (yyo, ".%d", end_col); - } - else if (0 <= end_col && yylocp->first_column < end_col) - res += YYFPRINTF (yyo, "-%d", end_col); - } - return res; -} - -# define YYLOCATION_PRINT yy_location_print_ - - /* Temporary convenience wrapper in case some people defined the - undocumented and private YY_LOCATION_PRINT macros. */ -# define YY_LOCATION_PRINT(File, Loc) YYLOCATION_PRINT(File, &(Loc)) - -# else - -# define YYLOCATION_PRINT(File, Loc) ((void) 0) - /* Temporary convenience wrapper in case some people defined the - undocumented and private YY_LOCATION_PRINT macros. */ -# define YY_LOCATION_PRINT YYLOCATION_PRINT - -# endif -# endif /* !defined YYLOCATION_PRINT */ - - -# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Kind, Value, Location); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - - -/*-----------------------------------. -| Print this symbol's value on YYO. | -`-----------------------------------*/ - -static void -yy_symbol_value_print (FILE *yyo, - yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) -{ - FILE *yyoutput = yyo; - YY_USE (yyoutput); - YY_USE (yylocationp); - if (!yyvaluep) - return; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YY_USE (yykind); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - -/*---------------------------. -| Print this symbol on YYO. | -`---------------------------*/ - -static void -yy_symbol_print (FILE *yyo, - yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) -{ - YYFPRINTF (yyo, "%s %s (", - yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); - - YYLOCATION_PRINT (yyo, yylocationp); - YYFPRINTF (yyo, ": "); - yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp); - YYFPRINTF (yyo, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -static void -yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -static void -yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, - int yyrule) -{ - int yylno = yyrline[yyrule]; - int yynrhs = yyr2[yyrule]; - int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, - YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), - &yyvsp[(yyi + 1) - (yynrhs)], - &(yylsp[(yyi + 1) - (yynrhs)])); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) ((void) 0) -# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - - - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -static void -yydestruct (const char *yymsg, - yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) -{ - YY_USE (yyvaluep); - YY_USE (yylocationp); - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YY_USE (yykind); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - - - - - -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (void) -{ -/* Lookahead token kind. */ -int yychar; - - -/* The semantic value of the lookahead symbol. */ -/* Default value used for initialization, for pacifying older GCCs - or non-GCC compilers. */ -YY_INITIAL_VALUE (static YYSTYPE yyval_default;) -YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); - -/* Location data for the lookahead symbol. */ -static YYLTYPE yyloc_default -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL - = { 1, 1, 1, 1 } -# endif -; -YYLTYPE yylloc = yyloc_default; - - /* Number of syntax errors so far. */ - int yynerrs = 0; - - yy_state_fast_t yystate = 0; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus = 0; - - /* Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* Their size. */ - YYPTRDIFF_T yystacksize = YYINITDEPTH; - - /* The state stack: array, bottom, top. */ - yy_state_t yyssa[YYINITDEPTH]; - yy_state_t *yyss = yyssa; - yy_state_t *yyssp = yyss; - - /* The semantic value stack: array, bottom, top. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp = yyvs; - - /* The location stack: array, bottom, top. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp = yyls; - - int yyn; - /* The return value of yyparse. */ - int yyresult; - /* Lookahead symbol kind. */ - yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - YYLTYPE yyloc; - - /* The locations where the error started and ended. */ - YYLTYPE yyerror_range[3]; - - - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yychar = YYEMPTY; /* Cause a token to be read. */ - - yylsp[0] = yylloc; - goto yysetstate; - - -/*------------------------------------------------------------. -| yynewstate -- push a new state, which is found in yystate. | -`------------------------------------------------------------*/ -yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - -/*--------------------------------------------------------------------. -| yysetstate -- set current state (the top of the stack) to yystate. | -`--------------------------------------------------------------------*/ -yysetstate: - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - YY_ASSERT (0 <= yystate && yystate < YYNSTATES); - YY_IGNORE_USELESS_CAST_BEGIN - *yyssp = YY_CAST (yy_state_t, yystate); - YY_IGNORE_USELESS_CAST_END - YY_STACK_PRINT (yyss, yyssp); - - if (yyss + yystacksize - 1 <= yyssp) -#if !defined yyoverflow && !defined YYSTACK_RELOCATE - YYNOMEM; -#else - { - /* Get the current used size of the three stacks, in elements. */ - YYPTRDIFF_T yysize = yyssp - yyss + 1; - -# if defined yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - yy_state_t *yyss1 = yyss; - YYSTYPE *yyvs1 = yyvs; - YYLTYPE *yyls1 = yyls; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * YYSIZEOF (*yyssp), - &yyvs1, yysize * YYSIZEOF (*yyvsp), - &yyls1, yysize * YYSIZEOF (*yylsp), - &yystacksize); - yyss = yyss1; - yyvs = yyvs1; - yyls = yyls1; - } -# else /* defined YYSTACK_RELOCATE */ - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - YYNOMEM; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yy_state_t *yyss1 = yyss; - union yyalloc *yyptr = - YY_CAST (union yyalloc *, - YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); - if (! yyptr) - YYNOMEM; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); - YYSTACK_RELOCATE (yyls_alloc, yyls); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - yylsp = yyls + yysize - 1; - - YY_IGNORE_USELESS_CAST_BEGIN - YYDPRINTF ((stderr, "Stack size increased to %ld\n", - YY_CAST (long, yystacksize))); - YY_IGNORE_USELESS_CAST_END - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } -#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ - - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token\n")); - yychar = yylex (&yylval, &yylloc); - } - - if (yychar <= YYEOF) - { - yychar = YYEOF; - yytoken = YYSYMBOL_YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else if (yychar == YYerror) - { - /* The scanner already issued an error message, process directly - to error recovery. But do not keep the error token as - lookahead, it is too special and may lead us to an endless - loop in error recovery. */ - yychar = YYUNDEF; - yytoken = YYSYMBOL_YYerror; - yyerror_range[1] = yylloc; - goto yyerrlab1; - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - *++yylsp = yylloc; - - /* Discard the shifted token. */ - yychar = YYEMPTY; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - '$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - /* Default location. */ - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); - yyerror_range[1] = yyloc; - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 3: /* grammar: START_CONST_EXPR const_expr */ -#line 468 "dtool/src/cppparser/cppBison.yxx" -{ - current_expr = (yyvsp[0].u.expr); -} -#line 3882 "built/tmp/cppBison.yxx.c" - break; - - case 4: /* grammar: START_TYPE full_type */ -#line 472 "dtool/src/cppparser/cppBison.yxx" -{ - current_type = (yyvsp[0].u.type); -} -#line 3890 "built/tmp/cppBison.yxx.c" - break; - - case 6: /* cpp: cpp optional_attributes ';' */ -#line 480 "dtool/src/cppparser/cppBison.yxx" -{ - if (!(yyvsp[-1].attr_list).is_empty()) { - current_scope->add_declaration(new CPPDeclaration((yylsp[-1]).file, (yyvsp[-1].attr_list)), global_scope, current_lexer, (yylsp[-1])); - } -} -#line 3900 "built/tmp/cppBison.yxx.c" - break; - - case 7: /* $@1: %empty */ -#line 486 "dtool/src/cppparser/cppBison.yxx" -{ - current_attributes = (yyvsp[0].attr_list); -} -#line 3908 "built/tmp/cppBison.yxx.c" - break; - - case 8: /* cpp: cpp optional_attributes $@1 declaration */ -#line 490 "dtool/src/cppparser/cppBison.yxx" -{ - current_attributes = CPPAttributeList(); -} -#line 3916 "built/tmp/cppBison.yxx.c" - break; - - case 11: /* constructor_init: name '(' optional_const_expr_comma ')' */ -#line 502 "dtool/src/cppparser/cppBison.yxx" -{ - delete (yyvsp[-1].u.expr); -} -#line 3924 "built/tmp/cppBison.yxx.c" - break; - - case 12: /* constructor_init: name '(' optional_const_expr_comma ')' ELLIPSIS */ -#line 506 "dtool/src/cppparser/cppBison.yxx" -{ - delete (yyvsp[-2].u.expr); -} -#line 3932 "built/tmp/cppBison.yxx.c" - break; - - case 13: /* constructor_init: name '{' optional_const_expr_comma '}' */ -#line 510 "dtool/src/cppparser/cppBison.yxx" -{ - delete (yyvsp[-1].u.expr); -} -#line 3940 "built/tmp/cppBison.yxx.c" - break; - - case 14: /* $@2: %empty */ -#line 522 "dtool/src/cppparser/cppBison.yxx" -{ - push_storage_class((current_storage_class & ~CPPInstance::SC_c_binding) | - ((yyvsp[-1].u.integer) & CPPInstance::SC_c_binding)); -} -#line 3949 "built/tmp/cppBison.yxx.c" - break; - - case 15: /* extern_c: storage_class '{' $@2 cpp '}' */ -#line 527 "dtool/src/cppparser/cppBison.yxx" -{ - pop_storage_class(); -} -#line 3957 "built/tmp/cppBison.yxx.c" - break; - - case 22: /* declaration: KW_BEGIN_PUBLISH */ -#line 540 "dtool/src/cppparser/cppBison.yxx" -{ - if (publish_nest_level != 0) { - yyerror("Unclosed __begin_publish", publish_loc); - publish_nest_level = 0; - current_scope->set_current_vis(V_public); - } - - publish_previous = current_scope->get_current_vis(); - publish_loc = (yylsp[0]); - publish_nest_level++; - current_scope->set_current_vis(V_published); -} -#line 3974 "built/tmp/cppBison.yxx.c" - break; - - case 23: /* declaration: KW_END_PUBLISH */ -#line 553 "dtool/src/cppparser/cppBison.yxx" -{ - if (publish_nest_level != 1) { - yyerror("Unmatched __end_publish", (yylsp[0])); - } else { - current_scope->set_current_vis(publish_previous); - } - publish_nest_level = 0; -} -#line 3987 "built/tmp/cppBison.yxx.c" - break; - - case 24: /* declaration: KW_PUBLISHED ':' */ -#line 562 "dtool/src/cppparser/cppBison.yxx" -{ - current_scope->set_current_vis(V_published); -} -#line 3995 "built/tmp/cppBison.yxx.c" - break; - - case 25: /* declaration: KW_PUBLIC ':' */ -#line 566 "dtool/src/cppparser/cppBison.yxx" -{ - if (publish_nest_level > 0) { - current_scope->set_current_vis(V_published); - } else { - current_scope->set_current_vis(V_public); - } -} -#line 4007 "built/tmp/cppBison.yxx.c" - break; - - case 26: /* declaration: KW_PROTECTED ':' */ -#line 574 "dtool/src/cppparser/cppBison.yxx" -{ - current_scope->set_current_vis(V_protected); -} -#line 4015 "built/tmp/cppBison.yxx.c" - break; - - case 27: /* declaration: KW_PRIVATE ':' */ -#line 578 "dtool/src/cppparser/cppBison.yxx" -{ - current_scope->set_current_vis(V_private); -} -#line 4023 "built/tmp/cppBison.yxx.c" - break; - - case 28: /* declaration: KW_MAKE_PROPERTY '(' name ',' IDENTIFIER maybe_comma_identifier ')' ';' */ -#line 582 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *getter = (yyvsp[-3].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-3].u.identifier)->get_fully_scoped_name(), (yylsp[-3])); - } else { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-5].u.identifier), CPPMakeProperty::T_normal, current_scope, (yylsp[-7]).file); - make_property->_get_function = getter->as_function_group(); - - if ((yyvsp[-2].u.identifier) != nullptr) { - CPPDeclaration *setter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - } else { - make_property->_set_function = setter->as_function_group(); - } - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-7])); - } -} -#line 4048 "built/tmp/cppBison.yxx.c" - break; - - case 29: /* declaration: KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 603 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-6].u.identifier)->get_fully_scoped_name(), (yylsp[-6])); - - } else { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-8].u.identifier), CPPMakeProperty::T_normal, current_scope, (yylsp[-10]).file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *setter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *deleter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - } else { - make_property->_del_function = deleter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-10])); - } -} -#line 4079 "built/tmp/cppBison.yxx.c" - break; - - case 30: /* declaration: KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 630 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *length_getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - length_getter = nullptr; - } - - CPPDeclaration *getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-6].u.identifier), CPPMakeProperty::T_sequence, current_scope, (yylsp[-8]).file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-8])); - } -} -#line 4104 "built/tmp/cppBison.yxx.c" - break; - - case 31: /* declaration: KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 651 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *length_getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + (yyvsp[-6].u.identifier)->get_fully_scoped_name(), (yylsp[-6])); - length_getter = nullptr; - } - - CPPDeclaration *getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-8].u.identifier), CPPMakeProperty::T_sequence, current_scope, (yylsp[-10]).file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - - CPPDeclaration *setter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - } else { - make_property->_set_function = setter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-10])); - } -} -#line 4137 "built/tmp/cppBison.yxx.c" - break; - - case 32: /* declaration: KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 680 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *length_getter = (yyvsp[-8].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + (yyvsp[-8].u.identifier)->get_fully_scoped_name(), (yylsp[-8])); - length_getter = nullptr; - } - - CPPDeclaration *getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-6].u.identifier)->get_fully_scoped_name(), (yylsp[-6])); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-10].u.identifier), CPPMakeProperty::T_sequence, current_scope, (yylsp[-12]).file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - - CPPDeclaration *setter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *deleter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - } else { - make_property->_del_function = deleter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-12])); - } -} -#line 4177 "built/tmp/cppBison.yxx.c" - break; - - case 33: /* declaration: KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 716 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *length_getter = (yyvsp[-10].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + (yyvsp[-10].u.identifier)->get_fully_scoped_name(), (yylsp[-10])); - length_getter = nullptr; - } - - CPPDeclaration *getter = (yyvsp[-8].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-8].u.identifier)->get_fully_scoped_name(), (yylsp[-8])); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-12].u.identifier), CPPMakeProperty::T_sequence, current_scope, (yylsp[-14]).file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - - CPPDeclaration *setter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + (yyvsp[-6].u.identifier)->get_fully_scoped_name(), (yylsp[-6])); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *deleter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - } else { - make_property->_del_function = deleter->as_function_group(); - } - - CPPDeclaration *inserter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (inserter == nullptr || inserter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid append method: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - } else { - make_property->_insert_function = inserter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-14])); - } -} -#line 4224 "built/tmp/cppBison.yxx.c" - break; - - case 34: /* declaration: KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ')' ';' */ -#line 759 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid item getter method: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - - } else { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-4].u.identifier), CPPMakeProperty::T_mapping, current_scope, (yylsp[-6]).file); - make_property->_get_function = getter->as_function_group(); - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-6])); - } -} -#line 4240 "built/tmp/cppBison.yxx.c" - break; - - case 35: /* declaration: KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 771 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - - } else { - CPPMakeProperty *make_property; - make_property = new CPPMakeProperty((yyvsp[-6].u.identifier), CPPMakeProperty::T_mapping, current_scope, (yylsp[-8]).file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-8])); - } -} -#line 4265 "built/tmp/cppBison.yxx.c" - break; - - case 36: /* declaration: KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER maybe_comma_identifier ')' ';' */ -#line 792 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *getter = (yyvsp[-5].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-5].u.identifier)->get_fully_scoped_name(), (yylsp[-5])); - - } else { - CPPMakeProperty *make_property = new CPPMakeProperty((yyvsp[-9].u.identifier), CPPMakeProperty::T_mapping, current_scope, (yylsp[-11]).file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = (yyvsp[-7].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + (yyvsp[-7].u.identifier)->get_fully_scoped_name(), (yylsp[-7])); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - CPPDeclaration *setter = (yyvsp[-3].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + (yyvsp[-3].u.identifier)->get_fully_scoped_name(), (yylsp[-3])); - } else { - make_property->_set_function = setter->as_function_group(); - } - - if ((yyvsp[-2].u.identifier) != nullptr) { - CPPDeclaration *deleter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - } else { - make_property->_del_function = deleter->as_function_group(); - } - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-11])); - } -} -#line 4305 "built/tmp/cppBison.yxx.c" - break; - - case 37: /* declaration: KW_MAKE_MAP_KEYS_SEQ '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 828 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *length_getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - length_getter = nullptr; - } - - CPPDeclaration *getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid getter: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = nullptr; - for (size_t i = 0; i < current_scope->_declarations.size(); ++i) { - make_property = current_scope->_declarations[i]->as_make_property(); - if (make_property != nullptr) { - if (make_property->get_fully_scoped_name() == (yyvsp[-6].u.identifier)->get_fully_scoped_name()) { - break; - } else { - make_property = nullptr; - } - } - } - if (make_property != nullptr) { - make_property->_get_key_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - } else { - yyerror("reference to non-existent MAKE_MAP_PROPERTY: " + (yyvsp[-6].u.identifier)->get_fully_scoped_name(), (yylsp[-6])); - } - } -} -#line 4343 "built/tmp/cppBison.yxx.c" - break; - - case 38: /* declaration: KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 862 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - - } else { - CPPMakeProperty *make_property; - make_property = new CPPMakeProperty((yyvsp[-6].u.identifier), CPPMakeProperty::T_normal, - current_scope, (yylsp[-8]).file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-8])); - } -} -#line 4369 "built/tmp/cppBison.yxx.c" - break; - - case 39: /* declaration: KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 884 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *getter = (yyvsp[-6].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + (yyvsp[-6].u.identifier)->get_fully_scoped_name(), (yylsp[-6])); - - } else { - CPPMakeProperty *make_property; - make_property = new CPPMakeProperty((yyvsp[-10].u.identifier), CPPMakeProperty::T_normal, - current_scope, (yylsp[-12]).file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = (yyvsp[-8].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + (yyvsp[-8].u.identifier)->get_fully_scoped_name(), (yylsp[-8])); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - CPPDeclaration *setter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid setter: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *clearer = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (clearer == nullptr || clearer->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid clear method: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - } else { - make_property->_clear_function = clearer->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, (yylsp[-12])); - } -} -#line 4409 "built/tmp/cppBison.yxx.c" - break; - - case 40: /* declaration: KW_MAKE_SEQ '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' */ -#line 920 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *length_getter = (yyvsp[-4].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + (yyvsp[-4].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - length_getter = nullptr; - } - - CPPDeclaration *element_getter = (yyvsp[-2].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (element_getter == nullptr || element_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid element method: " + (yyvsp[-2].u.identifier)->get_fully_scoped_name(), (yylsp[-4])); - element_getter = nullptr; - } - - if (length_getter != nullptr && element_getter != nullptr) { - CPPMakeSeq *make_seq = new CPPMakeSeq((yyvsp[-6].u.identifier), - length_getter->as_function_group(), - element_getter->as_function_group(), - current_scope, (yylsp[-8]).file); - current_scope->add_declaration(make_seq, global_scope, current_lexer, (yylsp[-8])); - } -} -#line 4435 "built/tmp/cppBison.yxx.c" - break; - - case 41: /* declaration: KW_STATIC_ASSERT '(' const_expr ',' string_literal ')' ';' */ -#line 942 "dtool/src/cppparser/cppBison.yxx" -{ - CPPExpression::Result result = (yyvsp[-4].u.expr)->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("static_assert requires a constant expression", (yylsp[-4])); - } else if (!result.as_boolean()) { - stringstream str; - str << *(yyvsp[-2].u.expr); - yywarning("static_assert failed: " + str.str(), (yylsp[-4])); - } -} -#line 4450 "built/tmp/cppBison.yxx.c" - break; - - case 42: /* declaration: KW_STATIC_ASSERT '(' const_expr ')' ';' */ -#line 953 "dtool/src/cppparser/cppBison.yxx" -{ - // This alternative version of static_assert was introduced in C++17. - CPPExpression::Result result = (yyvsp[-2].u.expr)->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("static_assert requires a constant expression", (yylsp[-2])); - } else if (!result.as_boolean()) { - yywarning("static_assert failed", (yylsp[-2])); - } -} -#line 4464 "built/tmp/cppBison.yxx.c" - break; - - case 43: /* $@3: %empty */ -#line 966 "dtool/src/cppparser/cppBison.yxx" -{ - CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("temp"), - V_public); - push_scope(new_scope); -} -#line 4474 "built/tmp/cppBison.yxx.c" - break; - - case 44: /* friend_declaration: KW_FRIEND $@3 declaration */ -#line 972 "dtool/src/cppparser/cppBison.yxx" -{ - delete current_scope; - pop_scope(); -} -#line 4483 "built/tmp/cppBison.yxx.c" - break; - - case 45: /* storage_class: empty */ -#line 981 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = 0; -} -#line 4491 "built/tmp/cppBison.yxx.c" - break; - - case 46: /* storage_class: KW_CONST storage_class */ -#line 985 "dtool/src/cppparser/cppBison.yxx" -{ - // This isn't really a storage class, but it helps with parsing. - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_const; -} -#line 4500 "built/tmp/cppBison.yxx.c" - break; - - case 47: /* storage_class: KW_EXTERN storage_class */ -#line 990 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extern; -} -#line 4508 "built/tmp/cppBison.yxx.c" - break; - - case 48: /* storage_class: KW_EXTERN SIMPLE_STRING storage_class */ -#line 994 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extern; - if ((yyvsp[-1].str) == "C") { - (yyval.u.integer) |= (int)CPPInstance::SC_c_binding; - } else if ((yyvsp[-1].str) == "C++") { - (yyval.u.integer) &= ~(int)CPPInstance::SC_c_binding; - } else { - yywarning("Ignoring unknown linkage type \"" + (yyvsp[-1].str) + "\"", (yylsp[-1])); - } -} -#line 4523 "built/tmp/cppBison.yxx.c" - break; - - case 49: /* storage_class: KW_STATIC storage_class */ -#line 1005 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_static; -} -#line 4531 "built/tmp/cppBison.yxx.c" - break; - - case 50: /* storage_class: KW_INLINE storage_class */ -#line 1009 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_inline; -} -#line 4539 "built/tmp/cppBison.yxx.c" - break; - - case 51: /* storage_class: KW_VIRTUAL storage_class */ -#line 1013 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_virtual; -} -#line 4547 "built/tmp/cppBison.yxx.c" - break; - - case 52: /* storage_class: KW_EXPLICIT storage_class */ -#line 1017 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_explicit; -} -#line 4555 "built/tmp/cppBison.yxx.c" - break; - - case 53: /* storage_class: KW_EXPLICIT_LPAREN const_expr ')' storage_class */ -#line 1021 "dtool/src/cppparser/cppBison.yxx" -{ - CPPExpression::Result result = (yyvsp[-2].u.expr)->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("explicit() requires a constant expression", (yylsp[-2])); - } else if (result.as_boolean()) { - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_explicit; - } -} -#line 4568 "built/tmp/cppBison.yxx.c" - break; - - case 54: /* storage_class: KW_REGISTER storage_class */ -#line 1030 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_register; -} -#line 4576 "built/tmp/cppBison.yxx.c" - break; - - case 55: /* storage_class: KW_VOLATILE storage_class */ -#line 1034 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_volatile; -} -#line 4584 "built/tmp/cppBison.yxx.c" - break; - - case 56: /* storage_class: KW_MUTABLE storage_class */ -#line 1038 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_mutable; -} -#line 4592 "built/tmp/cppBison.yxx.c" - break; - - case 57: /* storage_class: KW_CONSTEVAL storage_class */ -#line 1042 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_consteval; -} -#line 4600 "built/tmp/cppBison.yxx.c" - break; - - case 58: /* storage_class: KW_CONSTEXPR storage_class */ -#line 1046 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_constexpr; -} -#line 4608 "built/tmp/cppBison.yxx.c" - break; - - case 59: /* storage_class: KW_CONSTINIT storage_class */ -#line 1050 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_constinit; -} -#line 4616 "built/tmp/cppBison.yxx.c" - break; - - case 60: /* storage_class: KW_BLOCKING storage_class */ -#line 1054 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_blocking; -} -#line 4624 "built/tmp/cppBison.yxx.c" - break; - - case 61: /* storage_class: KW_EXTENSION storage_class */ -#line 1058 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_extension; -} -#line 4632 "built/tmp/cppBison.yxx.c" - break; - - case 62: /* storage_class: KW_THREAD_LOCAL storage_class */ -#line 1062 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[0].u.integer) | (int)CPPInstance::SC_thread_local; -} -#line 4640 "built/tmp/cppBison.yxx.c" - break; - - case 63: /* optional_attributes: empty */ -#line 1069 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = CPPAttributeList(); -} -#line 4648 "built/tmp/cppBison.yxx.c" - break; - - case 64: /* optional_attributes: ATTR_LEFT attribute_specifiers ATTR_RIGHT optional_attributes */ -#line 1073 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = (yyvsp[-2].attr_list); - (yyval.attr_list).add_attributes_from((yyvsp[0].attr_list)); -} -#line 4657 "built/tmp/cppBison.yxx.c" - break; - - case 65: /* optional_attributes: ATTR_LEFT KW_USING name ':' attribute_specifiers ATTR_RIGHT optional_attributes */ -#line 1078 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = (yyvsp[-2].attr_list); - for (CPPAttributeList::Attribute &attr : (yyval.attr_list)._attributes) { - attr._ident->prepend((yyvsp[-4].u.identifier)); - } - (yyval.attr_list).add_attributes_from((yyvsp[0].attr_list)); -} -#line 4669 "built/tmp/cppBison.yxx.c" - break; - - case 66: /* optional_attributes: KW_ALIGNAS '(' const_expr ')' optional_attributes */ -#line 1086 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = (yyvsp[0].attr_list); - (yyval.attr_list).add_alignas((yyvsp[-2].u.expr)->as_expression()); -} -#line 4678 "built/tmp/cppBison.yxx.c" - break; - - case 67: /* optional_attributes: KW_ALIGNAS '(' type_decl ')' optional_attributes */ -#line 1091 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = (yyvsp[0].attr_list); - (yyval.attr_list).add_alignas((yyvsp[-2].u.decl)->as_type()); -} -#line 4687 "built/tmp/cppBison.yxx.c" - break; - - case 68: /* attribute_specifiers: attribute_specifier */ -#line 1099 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = (yyvsp[0].attr_list); -} -#line 4695 "built/tmp/cppBison.yxx.c" - break; - - case 69: /* attribute_specifiers: attribute_specifier ',' attribute_specifiers */ -#line 1103 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = (yyvsp[-2].attr_list); - (yyval.attr_list).add_attributes_from((yyvsp[0].attr_list)); -} -#line 4704 "built/tmp/cppBison.yxx.c" - break; - - case 70: /* attribute_specifier: name */ -#line 1111 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = CPPAttributeList(); - (yyval.attr_list).add_attribute((yyvsp[0].u.identifier)); -} -#line 4713 "built/tmp/cppBison.yxx.c" - break; - - case 71: /* attribute_specifier: name '(' formal_parameter_list ')' */ -#line 1116 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.attr_list) = CPPAttributeList(); - (yyval.attr_list).add_attribute((yyvsp[-3].u.identifier)); -} -#line 4722 "built/tmp/cppBison.yxx.c" - break; - - case 72: /* $@4: %empty */ -#line 1124 "dtool/src/cppparser/cppBison.yxx" -{ - // We don't need to push/pop type, because we can't nest - // type_like_declaration. - if ((yyvsp[0].u.decl)->as_type_declaration()) { - current_type = (yyvsp[0].u.decl)->as_type_declaration()->_type; - } else { - current_type = (yyvsp[0].u.decl)->as_type(); - } - push_storage_class((yyvsp[-1].u.integer)); -} -#line 4737 "built/tmp/cppBison.yxx.c" - break; - - case 73: /* type_like_declaration: storage_class var_type_decl $@4 multiple_instance_identifiers */ -#line 1135 "dtool/src/cppparser/cppBison.yxx" -{ - pop_storage_class(); -} -#line 4745 "built/tmp/cppBison.yxx.c" - break; - - case 74: /* type_like_declaration: storage_class type_decl ';' */ -#line 1140 "dtool/src/cppparser/cppBison.yxx" -{ - // We don't really care about the storage class here. In fact, it's - // not actually legal to define a class or struct using a particular - // storage class, but we require it just to help yacc out in its - // parsing. - - current_scope->add_declaration((yyvsp[-1].u.decl), global_scope, current_lexer, (yylsp[-1])); -} -#line 4758 "built/tmp/cppBison.yxx.c" - break; - - case 75: /* $@5: %empty */ -#line 1149 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[0].u.instance) != nullptr) { - // Push the scope so that the initializers can make use of things defined - // in the class body. - push_scope((yyvsp[0].u.instance)->get_scope(current_scope, global_scope)); - (yyvsp[0].u.instance)->_storage_class |= (current_storage_class | (yyvsp[-1].u.integer)); - } -} -#line 4771 "built/tmp/cppBison.yxx.c" - break; - - case 76: /* type_like_declaration: storage_class constructor_prototype $@5 maybe_initialize_or_constructor_body */ -#line 1158 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-2].u.instance) != nullptr) { - pop_scope(); - current_scope->add_declaration((yyvsp[-2].u.instance), global_scope, current_lexer, (yylsp[-2])); - (yyvsp[-2].u.instance)->set_initializer((yyvsp[0].u.expr)); - } -} -#line 4783 "built/tmp/cppBison.yxx.c" - break; - - case 77: /* type_like_declaration: storage_class function_prototype maybe_initialize_or_function_body */ -#line 1166 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-1].u.instance) != nullptr) { - (yyvsp[-1].u.instance)->_storage_class |= (current_storage_class | (yyvsp[-2].u.integer)); - current_scope->add_declaration((yyvsp[-1].u.instance), global_scope, current_lexer, (yylsp[-1])); - (yyvsp[-1].u.instance)->set_initializer((yyvsp[0].u.expr)); - } -} -#line 4795 "built/tmp/cppBison.yxx.c" - break; - - case 79: /* multiple_instance_identifiers: instance_identifier_and_maybe_trailing_return_type maybe_initialize_or_function_body */ -#line 1182 "dtool/src/cppparser/cppBison.yxx" -{ - if (current_storage_class & CPPInstance::SC_const) { - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_const); - } - (yyvsp[-1].u.inst_ident)->add_attributes(current_attributes); - CPPInstance *inst = new CPPInstance(current_type, (yyvsp[-1].u.inst_ident), - current_storage_class, - (yylsp[-1]).file); - inst->set_initializer((yyvsp[0].u.expr)); - current_scope->add_declaration(inst, global_scope, current_lexer, (yylsp[-1])); -} -#line 4811 "built/tmp/cppBison.yxx.c" - break; - - case 80: /* multiple_instance_identifiers: instance_identifier_and_maybe_trailing_return_type maybe_initialize ',' multiple_instance_identifiers */ -#line 1194 "dtool/src/cppparser/cppBison.yxx" -{ - if (current_storage_class & CPPInstance::SC_const) { - (yyvsp[-3].u.inst_ident)->add_modifier(IIT_const); - } - (yyvsp[-3].u.inst_ident)->add_attributes(current_attributes); - CPPInstance *inst = new CPPInstance(current_type, (yyvsp[-3].u.inst_ident), - current_storage_class, - (yylsp[-3]).file); - inst->set_initializer((yyvsp[-2].u.expr)); - current_scope->add_declaration(inst, global_scope, current_lexer, (yylsp[-3])); -} -#line 4827 "built/tmp/cppBison.yxx.c" - break; - - case 81: /* $@6: %empty */ -#line 1210 "dtool/src/cppparser/cppBison.yxx" -{ - // We don't need to push/pop type, because we can't nest - // multiple_var_declarations. - if ((yyvsp[0].u.decl)->as_type_declaration()) { - current_type = (yyvsp[0].u.decl)->as_type_declaration()->_type; - } else { - current_type = (yyvsp[0].u.decl)->as_type(); - } - push_storage_class((yyvsp[-1].u.integer)); -} -#line 4842 "built/tmp/cppBison.yxx.c" - break; - - case 82: /* typedef_declaration: storage_class var_type_decl $@6 typedef_instance_identifiers */ -#line 1221 "dtool/src/cppparser/cppBison.yxx" -{ - pop_storage_class(); -} -#line 4850 "built/tmp/cppBison.yxx.c" - break; - - case 83: /* typedef_declaration: storage_class function_prototype maybe_initialize_or_function_body */ -#line 1225 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-1].u.instance) != nullptr) { - CPPInstance *inst = (yyvsp[-1].u.instance)->as_instance(); - if (inst != nullptr) { - inst->_storage_class |= (current_storage_class | (yyvsp[-2].u.integer)); - current_scope->add_declaration(inst, global_scope, current_lexer, (yylsp[-1])); - CPPTypedefType *typedef_type = new CPPTypedefType(inst->_type, inst->_ident, current_scope, inst->_attributes); - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, (yylsp[-1])); - } - } -} -#line 4866 "built/tmp/cppBison.yxx.c" - break; - - case 84: /* typedef_instance_identifiers: instance_identifier_and_maybe_trailing_return_type maybe_initialize_or_function_body */ -#line 1240 "dtool/src/cppparser/cppBison.yxx" -{ - if (current_storage_class & CPPInstance::SC_const) { - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_const); - } - (yyvsp[-1].u.inst_ident)->add_attributes(current_attributes); - CPPType *target_type = current_type; - CPPTypedefType *typedef_type = new CPPTypedefType(target_type, (yyvsp[-1].u.inst_ident), current_scope, (yylsp[-1]).file); - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, (yylsp[-1])); -} -#line 4880 "built/tmp/cppBison.yxx.c" - break; - - case 85: /* typedef_instance_identifiers: instance_identifier_and_maybe_trailing_return_type maybe_initialize ',' typedef_instance_identifiers */ -#line 1250 "dtool/src/cppparser/cppBison.yxx" -{ - if (current_storage_class & CPPInstance::SC_const) { - (yyvsp[-3].u.inst_ident)->add_modifier(IIT_const); - } - (yyvsp[-3].u.inst_ident)->add_attributes(current_attributes); - CPPType *target_type = current_type; - CPPTypedefType *typedef_type = new CPPTypedefType(target_type, (yyvsp[-3].u.inst_ident), current_scope, (yylsp[-3]).file); - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, (yylsp[-3])); -} -#line 4894 "built/tmp/cppBison.yxx.c" - break; - - case 86: /* $@7: %empty */ -#line 1265 "dtool/src/cppparser/cppBison.yxx" -{ - // Create a scope for this function. - CPPScope *scope = new CPPScope((yyvsp[-1].u.identifier)->get_scope(current_scope, global_scope), - (yyvsp[-1].u.identifier)->_names.back(), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} -#line 4911 "built/tmp/cppBison.yxx.c" - break; - - case 87: /* constructor_prototype: IDENTIFIER '(' $@7 function_parameter_list ')' function_post optional_attributes */ -#line 1278 "dtool/src/cppparser/cppBison.yxx" -{ - CPPScope *scope = (yyvsp[-6].u.identifier)->get_scope(current_scope, global_scope); - CPPType *type; - std::string simple_name = (yyvsp[-6].u.identifier)->get_simple_name(); - if (!simple_name.empty() && simple_name[0] == '~') { - // A destructor has no return type. - type = new CPPSimpleType(CPPSimpleType::T_void); - } - else if (scope != nullptr && simple_name == scope->get_simple_name()) { - // Neither does a constructor. - type = new CPPSimpleType(CPPSimpleType::T_void); - } - else { - // This isn't a constructor, so it has an implicit return type of - // int. - yywarning("function has no return type, assuming int", (yylsp[-6])); - type = new CPPSimpleType(CPPSimpleType::T_int); - } - pop_scope(); - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier((yyvsp[-6].u.identifier)); - ii->add_func_modifier((yyvsp[-3].u.param_list), (yyvsp[-1].u.integer), nullptr, (yyvsp[0].attr_list)); - ii->add_attributes(current_attributes); - - (yyval.u.instance) = new CPPInstance(type, ii, 0, (yylsp[-6]).file); -} -#line 4942 "built/tmp/cppBison.yxx.c" - break; - - case 88: /* $@8: %empty */ -#line 1307 "dtool/src/cppparser/cppBison.yxx" -{ - // Create a scope for this function. - CPPScope *scope = new CPPScope((yyvsp[-2].u.identifier)->get_scope(current_scope, global_scope), - (yyvsp[-2].u.identifier)->_names.back(), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} -#line 4959 "built/tmp/cppBison.yxx.c" - break; - - case 89: /* constructor_prototype: TYPENAME_IDENTIFIER '(' IDENTIFIER ')' '(' $@8 function_parameter_list ')' function_post optional_attributes */ -#line 1320 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); - CPPType *type = (yyvsp[-9].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[-9].u.identifier)->get_fully_scoped_name(), (yylsp[-9])); - } - assert(type != nullptr); - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier((yyvsp[-7].u.identifier)); - ii->add_func_modifier((yyvsp[-3].u.param_list), (yyvsp[-1].u.integer), nullptr, (yyvsp[0].attr_list)); - ii->add_attributes(current_attributes); - - (yyval.u.instance) = new CPPInstance(type, ii, 0, (yylsp[-9]).file); -} -#line 4978 "built/tmp/cppBison.yxx.c" - break; - - case 90: /* $@9: %empty */ -#line 1335 "dtool/src/cppparser/cppBison.yxx" -{ - // Create a scope for this function. - CPPScope *scope = new CPPScope((yyvsp[-1].u.identifier)->get_scope(current_scope, global_scope), - (yyvsp[-1].u.identifier)->_names.back(), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} -#line 4995 "built/tmp/cppBison.yxx.c" - break; - - case 91: /* constructor_prototype: TYPENAME_IDENTIFIER '(' $@9 function_parameter_list ')' function_post optional_attributes */ -#line 1348 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); - CPPType *type; - if ((yyvsp[-6].u.identifier)->get_simple_name() == current_scope->get_simple_name()) { - // This is a constructor, and has no return. - type = new CPPSimpleType(CPPSimpleType::T_void); - } else { - // This isn't a constructor, so it has an implicit return type of - // int. - type = new CPPSimpleType(CPPSimpleType::T_int); - } - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier((yyvsp[-6].u.identifier)); - ii->add_func_modifier((yyvsp[-3].u.param_list), (yyvsp[-1].u.integer), nullptr, (yyvsp[0].attr_list)); - ii->add_attributes(current_attributes); - - (yyval.u.instance) = new CPPInstance(type, ii, 0, (yylsp[-6]).file); -} -#line 5018 "built/tmp/cppBison.yxx.c" - break; - - case 92: /* $@10: %empty */ -#line 1372 "dtool/src/cppparser/cppBison.yxx" -{ - push_scope((yyvsp[-1].u.identifier)->get_scope(current_scope, global_scope)); -} -#line 5026 "built/tmp/cppBison.yxx.c" - break; - - case 93: /* function_prototype: '~' name '(' $@10 function_parameter_list ')' function_post optional_attributes */ -#line 1376 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); - if ((yyvsp[-6].u.identifier)->is_scoped()) { - yyerror("Invalid destructor name: ~" + (yyvsp[-6].u.identifier)->get_fully_scoped_name(), (yylsp[-6])); - } else { - CPPIdentifier *ident = - new CPPIdentifier("~" + (yyvsp[-6].u.identifier)->get_simple_name(), (yylsp[-6])); - delete (yyvsp[-6].u.identifier); - - CPPType *type; - type = new CPPSimpleType(CPPSimpleType::T_void); - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier(ident); - ii->add_func_modifier((yyvsp[-3].u.param_list), (yyvsp[-1].u.integer), nullptr, (yyvsp[0].attr_list)); - ii->add_attributes(current_attributes); - - (yyval.u.instance) = new CPPInstance(type, ii, 0, (yylsp[-6]).file); - } -} -#line 5050 "built/tmp/cppBison.yxx.c" - break; - - case 94: /* $@11: %empty */ -#line 1403 "dtool/src/cppparser/cppBison.yxx" -{ - push_scope((yyvsp[-2].u.inst_ident)->get_scope(current_scope, global_scope)); -} -#line 5058 "built/tmp/cppBison.yxx.c" - break; - - case 95: /* function_prototype: TYPENAME_IDENTIFIER '(' '*' instance_identifier ')' '(' $@11 function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type */ -#line 1407 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); - CPPType *type = (yyvsp[-11].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[-11].u.identifier)->get_fully_scoped_name(), (yylsp[-11])); - } - assert(type != nullptr); - - CPPInstanceIdentifier *ii = (yyvsp[-8].u.inst_ident); - ii->add_modifier(IIT_pointer); - ii->add_func_modifier((yyvsp[-4].u.param_list), (yyvsp[-2].u.integer), nullptr, (yyvsp[-1].attr_list)); - ii->add_attributes(current_attributes); - (yyval.u.instance) = new CPPInstance(type, ii, 0, (yylsp[-11]).file); -} -#line 5077 "built/tmp/cppBison.yxx.c" - break; - - case 96: /* $@12: %empty */ -#line 1422 "dtool/src/cppparser/cppBison.yxx" -{ - push_scope((yyvsp[-2].u.inst_ident)->get_scope(current_scope, global_scope)); -} -#line 5085 "built/tmp/cppBison.yxx.c" - break; - - case 97: /* function_prototype: TYPENAME_IDENTIFIER '(' SCOPING '*' instance_identifier ')' '(' $@12 function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type */ -#line 1426 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); - CPPType *type = (yyvsp[-12].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[-12].u.identifier)->get_fully_scoped_name(), (yylsp[-12])); - } - assert(type != nullptr); - - CPPInstanceIdentifier *ii = (yyvsp[-8].u.inst_ident); - ii->add_scoped_pointer_modifier((yyvsp[-10].u.identifier)); - ii->add_func_modifier((yyvsp[-4].u.param_list), (yyvsp[-2].u.integer), nullptr, (yyvsp[-1].attr_list)); - ii->add_attributes(current_attributes); - (yyval.u.instance) = new CPPInstance(type, ii, 0, (yylsp[-12]).file); -} -#line 5104 "built/tmp/cppBison.yxx.c" - break; - - case 98: /* $@13: %empty */ -#line 1443 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-3].u.identifier) != nullptr) { - push_scope((yyvsp[-3].u.identifier)->get_scope(current_scope, global_scope)); - } -} -#line 5114 "built/tmp/cppBison.yxx.c" - break; - - case 99: /* function_prototype: KW_OPERATOR type not_paren_formal_parameter_identifier '(' $@13 function_parameter_list ')' function_post */ -#line 1449 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-7].u.identifier) != nullptr) { - pop_scope(); - } - - // We use formal_parameter_identifier, because that can match a type - // name with or without an identifier, but especially without, which - // is what follows the keyword "operator" in a typecast function. - // As an added bonus, the type of the formal_parameter will be the - // typecast type, i.e. the return type of the typecast function. - - // We give typecast operators the name "operator typecast ", - // where is a simple name of the type to be typecast. Use - // the method's return type to determine the full type description. - string name = "operator typecast " + (yyvsp[-6].u.type)->get_simple_name(); - CPPIdentifier *ident = (yyvsp[-7].u.identifier); - if (ident == nullptr) { - ident = new CPPIdentifier(name, (yylsp[-6])); - } else { - ident->add_name(name); - } - (yyval.u.instance) = CPPInstance::make_typecast_function - (new CPPInstance((yyvsp[-6].u.type), (yyvsp[-5].u.inst_ident), 0, (yylsp[-5]).file), ident, (yyvsp[-2].u.param_list), (yyvsp[0].u.integer)); - (yyval.u.instance)->_attributes.add_attributes_from(current_attributes); -} -#line 5144 "built/tmp/cppBison.yxx.c" - break; - - case 100: /* $@14: %empty */ -#line 1475 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-4].u.identifier) != nullptr) { - push_scope((yyvsp[-4].u.identifier)->get_scope(current_scope, global_scope)); - } -} -#line 5154 "built/tmp/cppBison.yxx.c" - break; - - case 101: /* function_prototype: KW_OPERATOR KW_CONST type not_paren_formal_parameter_identifier '(' $@14 function_parameter_list ')' function_post */ -#line 1481 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-8].u.identifier) != nullptr) { - pop_scope(); - } - - CPPIdentifier *ident = (yyvsp[-8].u.identifier); - if (ident == nullptr) { - ident = new CPPIdentifier("operator typecast", (yylsp[-5])); - } else { - ident->add_name("operator typecast"); - } - (yyvsp[-5].u.inst_ident)->add_modifier(IIT_const); - (yyvsp[-5].u.inst_ident)->add_attributes(current_attributes); - (yyval.u.instance) = CPPInstance::make_typecast_function - (new CPPInstance((yyvsp[-6].u.type), (yyvsp[-5].u.inst_ident), 0, (yylsp[-5]).file), ident, (yyvsp[-2].u.param_list), (yyvsp[0].u.integer)); -} -#line 5175 "built/tmp/cppBison.yxx.c" - break; - - case 102: /* function_prototype: IDENTIFIER */ -#line 1502 "dtool/src/cppparser/cppBison.yxx" -{ - CPPDeclaration *decl = - (yyvsp[0].u.identifier)->find_symbol(current_scope, global_scope, current_lexer); - if (decl != nullptr) { - (yyval.u.instance) = decl->as_instance(); - } else { - (yyval.u.instance) = nullptr; - } -} -#line 5189 "built/tmp/cppBison.yxx.c" - break; - - case 103: /* function_post: empty */ -#line 1515 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = 0; -} -#line 5197 "built/tmp/cppBison.yxx.c" - break; - - case 104: /* function_post: function_post KW_CONST */ -#line 1519 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-1].u.integer) | (int)CPPFunctionType::F_const_method; -} -#line 5205 "built/tmp/cppBison.yxx.c" - break; - - case 105: /* function_post: function_post KW_VOLATILE */ -#line 1523 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-1].u.integer) | (int)CPPFunctionType::F_volatile_method; -} -#line 5213 "built/tmp/cppBison.yxx.c" - break; - - case 106: /* function_post: function_post KW_NOEXCEPT */ -#line 1527 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-1].u.integer) | (int)CPPFunctionType::F_noexcept; -} -#line 5221 "built/tmp/cppBison.yxx.c" - break; - - case 107: /* function_post: function_post KW_NOEXCEPT_LPAREN const_expr ')' */ -#line 1531 "dtool/src/cppparser/cppBison.yxx" -{ - CPPExpression::Result result = (yyvsp[-1].u.expr)->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("noexcept() requires a constant expression", (yylsp[-1])); - } else if (result.as_boolean()) { - (yyval.u.integer) = (yyvsp[-3].u.integer) | (int)CPPFunctionType::F_noexcept; - } -} -#line 5234 "built/tmp/cppBison.yxx.c" - break; - - case 108: /* function_post: function_post KW_FINAL */ -#line 1540 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-1].u.integer) | (int)CPPFunctionType::F_final; -} -#line 5242 "built/tmp/cppBison.yxx.c" - break; - - case 109: /* function_post: function_post KW_OVERRIDE */ -#line 1544 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-1].u.integer) | (int)CPPFunctionType::F_override; -} -#line 5250 "built/tmp/cppBison.yxx.c" - break; - - case 110: /* function_post: function_post '&' */ -#line 1548 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-1].u.integer) | (int)CPPFunctionType::F_lvalue_method; -} -#line 5258 "built/tmp/cppBison.yxx.c" - break; - - case 111: /* function_post: function_post ANDAND */ -#line 1552 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-1].u.integer) | (int)CPPFunctionType::F_rvalue_method; -} -#line 5266 "built/tmp/cppBison.yxx.c" - break; - - case 112: /* function_post: function_post KW_MUTABLE */ -#line 1556 "dtool/src/cppparser/cppBison.yxx" -{ - // Used for lambdas, currently ignored. - (yyval.u.integer) = (yyvsp[-1].u.integer); -} -#line 5275 "built/tmp/cppBison.yxx.c" - break; - - case 113: /* function_post: function_post KW_CONSTEXPR */ -#line 1561 "dtool/src/cppparser/cppBison.yxx" -{ - // Used for lambdas in C++17, currently ignored. - (yyval.u.integer) = (yyvsp[-1].u.integer); -} -#line 5284 "built/tmp/cppBison.yxx.c" - break; - - case 114: /* function_post: function_post KW_THROW '(' ')' */ -#line 1566 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-3].u.integer); -} -#line 5292 "built/tmp/cppBison.yxx.c" - break; - - case 115: /* function_post: function_post KW_THROW '(' name ')' */ -#line 1570 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-4].u.integer); -} -#line 5300 "built/tmp/cppBison.yxx.c" - break; - - case 116: /* function_post: function_post KW_THROW '(' name ELLIPSIS ')' */ -#line 1574 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.integer) = (yyvsp[-5].u.integer); -} -#line 5308 "built/tmp/cppBison.yxx.c" - break; - - case 117: /* function_operator: '!' */ -#line 1581 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "!"; -} -#line 5316 "built/tmp/cppBison.yxx.c" - break; - - case 118: /* function_operator: '~' */ -#line 1585 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "~"; -} -#line 5324 "built/tmp/cppBison.yxx.c" - break; - - case 119: /* function_operator: '*' */ -#line 1589 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "*"; -} -#line 5332 "built/tmp/cppBison.yxx.c" - break; - - case 120: /* function_operator: '/' */ -#line 1593 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "/"; -} -#line 5340 "built/tmp/cppBison.yxx.c" - break; - - case 121: /* function_operator: '%' */ -#line 1597 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "%"; -} -#line 5348 "built/tmp/cppBison.yxx.c" - break; - - case 122: /* function_operator: '+' */ -#line 1601 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "+"; -} -#line 5356 "built/tmp/cppBison.yxx.c" - break; - - case 123: /* function_operator: '-' */ -#line 1605 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "-"; -} -#line 5364 "built/tmp/cppBison.yxx.c" - break; - - case 124: /* function_operator: '|' */ -#line 1609 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "|"; -} -#line 5372 "built/tmp/cppBison.yxx.c" - break; - - case 125: /* function_operator: '&' */ -#line 1613 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "&"; -} -#line 5380 "built/tmp/cppBison.yxx.c" - break; - - case 126: /* function_operator: '^' */ -#line 1617 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "^"; -} -#line 5388 "built/tmp/cppBison.yxx.c" - break; - - case 127: /* function_operator: OROR */ -#line 1621 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "||"; -} -#line 5396 "built/tmp/cppBison.yxx.c" - break; - - case 128: /* function_operator: ANDAND */ -#line 1625 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "&&"; -} -#line 5404 "built/tmp/cppBison.yxx.c" - break; - - case 129: /* function_operator: EQCOMPARE */ -#line 1629 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "=="; -} -#line 5412 "built/tmp/cppBison.yxx.c" - break; - - case 130: /* function_operator: NECOMPARE */ -#line 1633 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "!="; -} -#line 5420 "built/tmp/cppBison.yxx.c" - break; - - case 131: /* function_operator: LECOMPARE */ -#line 1637 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "<="; -} -#line 5428 "built/tmp/cppBison.yxx.c" - break; - - case 132: /* function_operator: GECOMPARE */ -#line 1641 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = ">="; -} -#line 5436 "built/tmp/cppBison.yxx.c" - break; - - case 133: /* function_operator: '<' */ -#line 1645 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "<"; -} -#line 5444 "built/tmp/cppBison.yxx.c" - break; - - case 134: /* function_operator: '>' */ -#line 1649 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = ">"; -} -#line 5452 "built/tmp/cppBison.yxx.c" - break; - - case 135: /* function_operator: SPACESHIP */ -#line 1653 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "<=>"; -} -#line 5460 "built/tmp/cppBison.yxx.c" - break; - - case 136: /* function_operator: LSHIFT */ -#line 1657 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "<<"; -} -#line 5468 "built/tmp/cppBison.yxx.c" - break; - - case 137: /* function_operator: RSHIFT */ -#line 1661 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = ">>"; -} -#line 5476 "built/tmp/cppBison.yxx.c" - break; - - case 138: /* function_operator: '=' */ -#line 1665 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "="; -} -#line 5484 "built/tmp/cppBison.yxx.c" - break; - - case 139: /* function_operator: ',' */ -#line 1669 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = ","; -} -#line 5492 "built/tmp/cppBison.yxx.c" - break; - - case 140: /* function_operator: PLUSPLUS */ -#line 1673 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "++"; -} -#line 5500 "built/tmp/cppBison.yxx.c" - break; - - case 141: /* function_operator: MINUSMINUS */ -#line 1677 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "--"; -} -#line 5508 "built/tmp/cppBison.yxx.c" - break; - - case 142: /* function_operator: TIMESEQUAL */ -#line 1681 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "*="; -} -#line 5516 "built/tmp/cppBison.yxx.c" - break; - - case 143: /* function_operator: DIVIDEEQUAL */ -#line 1685 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "/="; -} -#line 5524 "built/tmp/cppBison.yxx.c" - break; - - case 144: /* function_operator: MODEQUAL */ -#line 1689 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "%="; -} -#line 5532 "built/tmp/cppBison.yxx.c" - break; - - case 145: /* function_operator: PLUSEQUAL */ -#line 1693 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "+="; -} -#line 5540 "built/tmp/cppBison.yxx.c" - break; - - case 146: /* function_operator: MINUSEQUAL */ -#line 1697 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "-="; -} -#line 5548 "built/tmp/cppBison.yxx.c" - break; - - case 147: /* function_operator: OREQUAL */ -#line 1701 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "|="; -} -#line 5556 "built/tmp/cppBison.yxx.c" - break; - - case 148: /* function_operator: ANDEQUAL */ -#line 1705 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "&="; -} -#line 5564 "built/tmp/cppBison.yxx.c" - break; - - case 149: /* function_operator: XOREQUAL */ -#line 1709 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "^="; -} -#line 5572 "built/tmp/cppBison.yxx.c" - break; - - case 150: /* function_operator: LSHIFTEQUAL */ -#line 1713 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "<<="; -} -#line 5580 "built/tmp/cppBison.yxx.c" - break; - - case 151: /* function_operator: RSHIFTEQUAL */ -#line 1717 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = ">>="; -} -#line 5588 "built/tmp/cppBison.yxx.c" - break; - - case 152: /* function_operator: POINTSAT */ -#line 1721 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "->"; -} -#line 5596 "built/tmp/cppBison.yxx.c" - break; - - case 153: /* function_operator: '[' ']' */ -#line 1725 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "[]"; -} -#line 5604 "built/tmp/cppBison.yxx.c" - break; - - case 154: /* function_operator: '(' ')' */ -#line 1729 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "()"; -} -#line 5612 "built/tmp/cppBison.yxx.c" - break; - - case 155: /* function_operator: KW_NEW */ -#line 1733 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "new"; -} -#line 5620 "built/tmp/cppBison.yxx.c" - break; - - case 156: /* function_operator: KW_DELETE */ -#line 1737 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.str) = "delete"; -} -#line 5628 "built/tmp/cppBison.yxx.c" - break; - - case 161: /* $@15: %empty */ -#line 1751 "dtool/src/cppparser/cppBison.yxx" -{ - push_scope(new CPPTemplateScope(current_scope)); -} -#line 5636 "built/tmp/cppBison.yxx.c" - break; - - case 162: /* template_declaration: KW_TEMPLATE $@15 '<' template_formal_parameters '>' more_template_declaration */ -#line 1755 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); -} -#line 5644 "built/tmp/cppBison.yxx.c" - break; - - case 167: /* template_nonempty_formal_parameters: template_formal_parameter */ -#line 1769 "dtool/src/cppparser/cppBison.yxx" -{ - CPPTemplateScope *ts = current_scope->as_template_scope(); - assert(ts != nullptr); - ts->add_template_parameter((yyvsp[0].u.decl)); -} -#line 5654 "built/tmp/cppBison.yxx.c" - break; - - case 168: /* template_nonempty_formal_parameters: template_nonempty_formal_parameters ',' template_formal_parameter */ -#line 1775 "dtool/src/cppparser/cppBison.yxx" -{ - CPPTemplateScope *ts = current_scope->as_template_scope(); - assert(ts != nullptr); - ts->add_template_parameter((yyvsp[0].u.decl)); -} -#line 5664 "built/tmp/cppBison.yxx.c" - break; - - case 171: /* template_formal_parameter: typename_keyword */ -#line 1789 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type(new CPPClassTemplateParameter(nullptr)); -} -#line 5672 "built/tmp/cppBison.yxx.c" - break; - - case 172: /* template_formal_parameter: typename_keyword name */ -#line 1793 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type(new CPPClassTemplateParameter((yyvsp[0].u.identifier))); -} -#line 5680 "built/tmp/cppBison.yxx.c" - break; - - case 173: /* template_formal_parameter: typename_keyword name '=' full_type */ -#line 1797 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type(new CPPClassTemplateParameter((yyvsp[-2].u.identifier), (yyvsp[0].u.type))); -} -#line 5688 "built/tmp/cppBison.yxx.c" - break; - - case 174: /* template_formal_parameter: typename_keyword ELLIPSIS */ -#line 1801 "dtool/src/cppparser/cppBison.yxx" -{ - CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter(nullptr); - ctp->_packed = true; - (yyval.u.decl) = CPPType::new_type(ctp); -} -#line 5698 "built/tmp/cppBison.yxx.c" - break; - - case 175: /* template_formal_parameter: typename_keyword ELLIPSIS name */ -#line 1807 "dtool/src/cppparser/cppBison.yxx" -{ - CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter((yyvsp[0].u.identifier)); - ctp->_packed = true; - (yyval.u.decl) = CPPType::new_type(ctp); -} -#line 5708 "built/tmp/cppBison.yxx.c" - break; - - case 176: /* template_formal_parameter: template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize */ -#line 1813 "dtool/src/cppparser/cppBison.yxx" -{ - CPPInstance *inst = new CPPInstance((yyvsp[-2].u.type), (yyvsp[-1].u.inst_ident), 0, (yylsp[-1]).file); - inst->set_initializer((yyvsp[0].u.expr)); - (yyval.u.decl) = inst; -} -#line 5718 "built/tmp/cppBison.yxx.c" - break; - - case 177: /* template_formal_parameter: KW_CONST template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize */ -#line 1819 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_const); - CPPInstance *inst = new CPPInstance((yyvsp[-2].u.type), (yyvsp[-1].u.inst_ident), 0, (yylsp[-1]).file); - inst->set_initializer((yyvsp[0].u.expr)); - (yyval.u.decl) = inst; -} -#line 5729 "built/tmp/cppBison.yxx.c" - break; - - case 178: /* template_formal_parameter: template_formal_parameter_type parameter_pack_identifier */ -#line 1826 "dtool/src/cppparser/cppBison.yxx" -{ - CPPInstance *inst = new CPPInstance((yyvsp[-1].u.type), (yyvsp[0].u.inst_ident), 0, (yylsp[0]).file); - (yyval.u.decl) = inst; -} -#line 5738 "built/tmp/cppBison.yxx.c" - break; - - case 179: /* template_formal_parameter: KW_CONST template_formal_parameter_type parameter_pack_identifier */ -#line 1831 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[0].u.inst_ident)->add_modifier(IIT_const); - CPPInstance *inst = new CPPInstance((yyvsp[-1].u.type), (yyvsp[0].u.inst_ident), 0, (yylsp[0]).file); - (yyval.u.decl) = inst; -} -#line 5748 "built/tmp/cppBison.yxx.c" - break; - - case 180: /* template_formal_parameter: KW_VOLATILE template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize */ -#line 1837 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_volatile); - CPPInstance *inst = new CPPInstance((yyvsp[-2].u.type), (yyvsp[-1].u.inst_ident), 0, (yylsp[-1]).file); - inst->set_initializer((yyvsp[0].u.expr)); - (yyval.u.decl) = inst; -} -#line 5759 "built/tmp/cppBison.yxx.c" - break; - - case 181: /* template_formal_parameter: KW_VOLATILE template_formal_parameter_type parameter_pack_identifier */ -#line 1844 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[0].u.inst_ident)->add_modifier(IIT_volatile); - CPPInstance *inst = new CPPInstance((yyvsp[-1].u.type), (yyvsp[0].u.inst_ident), 0, (yylsp[0]).file); - (yyval.u.decl) = inst; -} -#line 5769 "built/tmp/cppBison.yxx.c" - break; - - case 182: /* template_formal_parameter_type: simple_type */ -#line 1853 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type((yyvsp[0].u.simple_type)); -} -#line 5777 "built/tmp/cppBison.yxx.c" - break; - - case 183: /* template_formal_parameter_type: IDENTIFIER */ -#line 1857 "dtool/src/cppparser/cppBison.yxx" -{ - yywarning("Not a type: " + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[0])); - (yyval.u.type) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); -} -#line 5786 "built/tmp/cppBison.yxx.c" - break; - - case 184: /* template_formal_parameter_type: TYPENAME_IDENTIFIER */ -#line 1862 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if ((yyval.u.type) == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[0])); - } - assert((yyval.u.type) != nullptr); -} -#line 5798 "built/tmp/cppBison.yxx.c" - break; - - case 185: /* template_formal_parameter_type: TYPEPACK_IDENTIFIER */ -#line 1870 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if ((yyval.u.type) == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[0])); - } - assert((yyval.u.type) != nullptr); -} -#line 5810 "built/tmp/cppBison.yxx.c" - break; - - case 186: /* instance_identifier: name_no_final optional_attributes */ -#line 1882 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier((yyvsp[-1].u.identifier), (yyvsp[0].attr_list)); -} -#line 5818 "built/tmp/cppBison.yxx.c" - break; - - case 187: /* instance_identifier: KW_OPERATOR function_operator optional_attributes */ -#line 1886 "dtool/src/cppparser/cppBison.yxx" -{ - // For an operator function. We implement this simply by building a - // ficticious name for the function; in other respects it's just - // like a regular function. - CPPIdentifier *ident = (yyvsp[-2].u.identifier); - if (ident == nullptr) { - ident = new CPPIdentifier("operator "+(yyvsp[-1].str), (yylsp[-1])); - } else { - ident->_names.push_back("operator "+(yyvsp[-1].str)); - } - - (yyval.u.inst_ident) = new CPPInstanceIdentifier(ident, (yyvsp[0].attr_list)); -} -#line 5836 "built/tmp/cppBison.yxx.c" - break; - - case 188: /* instance_identifier: KW_OPERATOR SIMPLE_STRING IDENTIFIER optional_attributes */ -#line 1900 "dtool/src/cppparser/cppBison.yxx" -{ - // A C++11 literal operator. - if (!(yyvsp[-2].str).empty()) { - yyerror("expected empty string", (yylsp[-2])); - } - CPPIdentifier *ident = (yyvsp[-3].u.identifier); - if (ident == nullptr) { - ident = new CPPIdentifier("operator \"\" "+(yyvsp[-1].u.identifier)->get_simple_name(), (yylsp[-1])); - } else { - ident->_names.push_back("operator \"\" "+(yyvsp[-1].u.identifier)->get_simple_name()); - } - - (yyval.u.inst_ident) = new CPPInstanceIdentifier(ident, (yyvsp[0].attr_list)); -} -#line 5855 "built/tmp/cppBison.yxx.c" - break; - - case 189: /* instance_identifier: KW_CONST instance_identifier */ -#line 1915 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_const); -} -#line 5864 "built/tmp/cppBison.yxx.c" - break; - - case 190: /* instance_identifier: KW_VOLATILE instance_identifier */ -#line 1920 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_volatile); -} -#line 5873 "built/tmp/cppBison.yxx.c" - break; - - case 191: /* instance_identifier: '*' optional_attributes instance_identifier */ -#line 1925 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_pointer, (yyvsp[-1].attr_list)); -} -#line 5882 "built/tmp/cppBison.yxx.c" - break; - - case 192: /* instance_identifier: '&' optional_attributes instance_identifier */ -#line 1930 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_reference, (yyvsp[-1].attr_list)); -} -#line 5891 "built/tmp/cppBison.yxx.c" - break; - - case 193: /* instance_identifier: ANDAND optional_attributes instance_identifier */ -#line 1935 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_rvalue_reference, (yyvsp[-1].attr_list)); -} -#line 5900 "built/tmp/cppBison.yxx.c" - break; - - case 194: /* instance_identifier: SCOPING '*' optional_attributes instance_identifier */ -#line 1940 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_scoped_pointer_modifier((yyvsp[-3].u.identifier), (yyvsp[-1].attr_list)); -} -#line 5909 "built/tmp/cppBison.yxx.c" - break; - - case 195: /* instance_identifier: instance_identifier '[' optional_const_expr ']' optional_attributes */ -#line 1945 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-4].u.inst_ident); - (yyval.u.inst_ident)->add_array_modifier((yyvsp[-2].u.expr), (yyvsp[0].attr_list)); -} -#line 5918 "built/tmp/cppBison.yxx.c" - break; - - case 196: /* instance_identifier: '(' instance_identifier ')' */ -#line 1950 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-1].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_paren); -} -#line 5927 "built/tmp/cppBison.yxx.c" - break; - - case 197: /* $@16: %empty */ -#line 1955 "dtool/src/cppparser/cppBison.yxx" -{ - // Create a scope for this function (in case it is a function) - CPPScope *scope = new CPPScope((yyvsp[-1].u.inst_ident)->get_scope(current_scope, global_scope), - CPPNameComponent(""), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} -#line 5944 "built/tmp/cppBison.yxx.c" - break; - - case 198: /* instance_identifier: instance_identifier '(' $@16 formal_parameter_list ')' function_post optional_attributes */ -#line 1968 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); - (yyval.u.inst_ident) = (yyvsp[-6].u.inst_ident); - if ((yyvsp[-3].u.param_list)->is_parameter_expr() && (yyvsp[-1].u.integer) == 0) { - // Oops, this must have been an instance declaration with a - // parameter list, not a function prototype. - (yyval.u.inst_ident)->add_initializer_modifier((yyvsp[-3].u.param_list)); - } - else { - // This was (probably) a function prototype. - (yyval.u.inst_ident)->add_func_modifier((yyvsp[-3].u.param_list), (yyvsp[-1].u.integer), nullptr, (yyvsp[0].attr_list)); - } -} -#line 5962 "built/tmp/cppBison.yxx.c" - break; - - case 199: /* instance_identifier_and_maybe_trailing_return_type: instance_identifier maybe_trailing_return_type */ -#line 1986 "dtool/src/cppparser/cppBison.yxx" -{ - // This is handled a bit awkwardly right now. Ideally it'd be wrapped - // up in the instance_identifier rule, but then more needs to happen in - // order to avoid shift/reduce conflicts. - if ((yyvsp[0].u.type) != nullptr) { - (yyvsp[-1].u.inst_ident)->add_trailing_return_type((yyvsp[0].u.type)); - } - (yyval.u.inst_ident) = (yyvsp[-1].u.inst_ident); -} -#line 5976 "built/tmp/cppBison.yxx.c" - break; - - case 200: /* instance_identifier_and_maybe_trailing_return_type: instance_identifier ':' const_expr */ -#line 1996 "dtool/src/cppparser/cppBison.yxx" -{ - // Bitfield definition. - (yyvsp[-2].u.inst_ident)->_bit_width = (yyvsp[0].u.expr); - (yyval.u.inst_ident) = (yyvsp[-2].u.inst_ident); -} -#line 5986 "built/tmp/cppBison.yxx.c" - break; - - case 201: /* maybe_trailing_return_type: empty */ -#line 2006 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = nullptr; -} -#line 5994 "built/tmp/cppBison.yxx.c" - break; - - case 202: /* maybe_trailing_return_type: POINTSAT predefined_type empty_instance_identifier */ -#line 2010 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.inst_ident)->unroll_type((yyvsp[-1].u.type)); -} -#line 6002 "built/tmp/cppBison.yxx.c" - break; - - case 203: /* maybe_trailing_return_type: POINTSAT KW_CONST predefined_type empty_instance_identifier */ -#line 2014 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[0].u.inst_ident)->add_modifier(IIT_const); - (yyval.u.type) = (yyvsp[0].u.inst_ident)->unroll_type((yyvsp[-1].u.type)); -} -#line 6011 "built/tmp/cppBison.yxx.c" - break; - - case 204: /* maybe_comma_identifier: empty */ -#line 2023 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = nullptr; -} -#line 6019 "built/tmp/cppBison.yxx.c" - break; - - case 205: /* maybe_comma_identifier: ',' IDENTIFIER */ -#line 2027 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = (yyvsp[0].u.identifier); -} -#line 6027 "built/tmp/cppBison.yxx.c" - break; - - case 206: /* function_parameter_list: empty */ -#line 2035 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = new CPPParameterList; -} -#line 6035 "built/tmp/cppBison.yxx.c" - break; - - case 207: /* function_parameter_list: ELLIPSIS */ -#line 2039 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = new CPPParameterList; - (yyval.u.param_list)->_includes_ellipsis = true; -} -#line 6044 "built/tmp/cppBison.yxx.c" - break; - - case 208: /* function_parameter_list: function_parameters */ -#line 2044 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[0].u.param_list); -} -#line 6052 "built/tmp/cppBison.yxx.c" - break; - - case 209: /* function_parameter_list: function_parameters ',' ELLIPSIS */ -#line 2048 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[-2].u.param_list); - (yyval.u.param_list)->_includes_ellipsis = true; -} -#line 6061 "built/tmp/cppBison.yxx.c" - break; - - case 210: /* function_parameter_list: function_parameters ELLIPSIS */ -#line 2053 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[-1].u.param_list); - (yyval.u.param_list)->_includes_ellipsis = true; -} -#line 6070 "built/tmp/cppBison.yxx.c" - break; - - case 211: /* function_parameters: function_parameter */ -#line 2061 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = new CPPParameterList; - (yyval.u.param_list)->_parameters.push_back((yyvsp[0].u.instance)); -} -#line 6079 "built/tmp/cppBison.yxx.c" - break; - - case 212: /* function_parameters: function_parameters ',' function_parameter */ -#line 2066 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[-2].u.param_list); - (yyval.u.param_list)->_parameters.push_back((yyvsp[0].u.instance)); -} -#line 6088 "built/tmp/cppBison.yxx.c" - break; - - case 213: /* formal_parameter_list: empty */ -#line 2074 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = new CPPParameterList; -} -#line 6096 "built/tmp/cppBison.yxx.c" - break; - - case 214: /* formal_parameter_list: ELLIPSIS */ -#line 2078 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = new CPPParameterList; - (yyval.u.param_list)->_includes_ellipsis = true; -} -#line 6105 "built/tmp/cppBison.yxx.c" - break; - - case 215: /* formal_parameter_list: formal_parameters */ -#line 2083 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[0].u.param_list); -} -#line 6113 "built/tmp/cppBison.yxx.c" - break; - - case 216: /* formal_parameter_list: formal_parameters ',' ELLIPSIS */ -#line 2087 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[-2].u.param_list); - (yyval.u.param_list)->_includes_ellipsis = true; -} -#line 6122 "built/tmp/cppBison.yxx.c" - break; - - case 217: /* formal_parameter_list: formal_parameters ELLIPSIS */ -#line 2092 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[-1].u.param_list); - (yyval.u.param_list)->_includes_ellipsis = true; -} -#line 6131 "built/tmp/cppBison.yxx.c" - break; - - case 218: /* formal_parameters: formal_parameter */ -#line 2100 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = new CPPParameterList; - (yyval.u.param_list)->_parameters.push_back((yyvsp[0].u.instance)); -} -#line 6140 "built/tmp/cppBison.yxx.c" - break; - - case 219: /* formal_parameters: formal_parameters ',' formal_parameter */ -#line 2105 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.param_list) = (yyvsp[-2].u.param_list); - (yyval.u.param_list)->_parameters.push_back((yyvsp[0].u.instance)); -} -#line 6149 "built/tmp/cppBison.yxx.c" - break; - - case 220: /* template_parameter_maybe_initialize: empty */ -#line 2113 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6157 "built/tmp/cppBison.yxx.c" - break; - - case 221: /* template_parameter_maybe_initialize: '=' no_angle_bracket_const_expr */ -#line 2117 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 6165 "built/tmp/cppBison.yxx.c" - break; - - case 222: /* maybe_initialize: empty */ -#line 2124 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6173 "built/tmp/cppBison.yxx.c" - break; - - case 223: /* maybe_initialize: '=' const_expr */ -#line 2128 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 6181 "built/tmp/cppBison.yxx.c" - break; - - case 224: /* maybe_initialize_or_constructor_body: ';' */ -#line 2135 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6189 "built/tmp/cppBison.yxx.c" - break; - - case 225: /* maybe_initialize_or_constructor_body: '{' code '}' */ -#line 2139 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6197 "built/tmp/cppBison.yxx.c" - break; - - case 226: /* maybe_initialize_or_constructor_body: ':' constructor_inits '{' code '}' */ -#line 2143 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6205 "built/tmp/cppBison.yxx.c" - break; - - case 227: /* maybe_initialize_or_constructor_body: '=' KW_DEFAULT ';' */ -#line 2147 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::get_default()); -} -#line 6213 "built/tmp/cppBison.yxx.c" - break; - - case 228: /* maybe_initialize_or_constructor_body: '=' KW_DELETE ';' */ -#line 2151 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::get_delete()); -} -#line 6221 "built/tmp/cppBison.yxx.c" - break; - - case 229: /* maybe_initialize_or_function_body: ';' */ -#line 2158 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6229 "built/tmp/cppBison.yxx.c" - break; - - case 230: /* maybe_initialize_or_function_body: '{' code '}' */ -#line 2162 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6237 "built/tmp/cppBison.yxx.c" - break; - - case 231: /* maybe_initialize_or_function_body: '=' const_expr ';' */ -#line 2166 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[-1].u.expr); -} -#line 6245 "built/tmp/cppBison.yxx.c" - break; - - case 232: /* maybe_initialize_or_function_body: '=' KW_DEFAULT ';' */ -#line 2170 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::get_default()); -} -#line 6253 "built/tmp/cppBison.yxx.c" - break; - - case 233: /* maybe_initialize_or_function_body: '=' KW_DELETE ';' */ -#line 2174 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::get_delete()); -} -#line 6261 "built/tmp/cppBison.yxx.c" - break; - - case 234: /* maybe_initialize_or_function_body: '=' '{' structure_init '}' */ -#line 2178 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 6269 "built/tmp/cppBison.yxx.c" - break; - - case 238: /* structure_init_body: const_expr */ -#line 2191 "dtool/src/cppparser/cppBison.yxx" -{ -} -#line 6276 "built/tmp/cppBison.yxx.c" - break; - - case 242: /* function_parameter: optional_attributes storage_class type formal_parameter_identifier maybe_initialize */ -#line 2200 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-3].u.integer) & CPPInstance::SC_const) { - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_const); - } - if ((yyvsp[-3].u.integer) & CPPInstance::SC_volatile) { - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_volatile); - } - (yyvsp[-1].u.inst_ident)->add_attributes((yyvsp[-4].attr_list)); - (yyval.u.instance) = new CPPInstance((yyvsp[-2].u.type), (yyvsp[-1].u.inst_ident), 0, (yylsp[-1]).file); - (yyval.u.instance)->set_initializer((yyvsp[0].u.expr)); -} -#line 6292 "built/tmp/cppBison.yxx.c" - break; - - case 243: /* function_parameter: optional_attributes storage_class type_pack parameter_pack_identifier maybe_initialize */ -#line 2212 "dtool/src/cppparser/cppBison.yxx" -{ - if ((yyvsp[-3].u.integer) & CPPInstance::SC_const) { - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_const); - } - if ((yyvsp[-3].u.integer) & CPPInstance::SC_volatile) { - (yyvsp[-1].u.inst_ident)->add_modifier(IIT_volatile); - } - (yyvsp[-1].u.inst_ident)->add_attributes((yyvsp[-4].attr_list)); - (yyval.u.instance) = new CPPInstance((yyvsp[-2].u.type), (yyvsp[-1].u.inst_ident), 0, (yylsp[-1]).file); - (yyval.u.instance)->set_initializer((yyvsp[0].u.expr)); -} -#line 6308 "built/tmp/cppBison.yxx.c" - break; - - case 244: /* formal_parameter: function_parameter */ -#line 2231 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.instance) = (yyvsp[0].u.instance); -} -#line 6316 "built/tmp/cppBison.yxx.c" - break; - - case 245: /* formal_parameter: formal_const_expr */ -#line 2235 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_parameter)); - (yyval.u.instance) = new CPPInstance(type, "expr"); - (yyval.u.instance)->set_initializer((yyvsp[0].u.expr)); -} -#line 6327 "built/tmp/cppBison.yxx.c" - break; - - case 246: /* not_paren_formal_parameter_identifier: empty */ -#line 2245 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); -} -#line 6335 "built/tmp/cppBison.yxx.c" - break; - - case 247: /* not_paren_formal_parameter_identifier: name_no_final optional_attributes */ -#line 2249 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier((yyvsp[-1].u.identifier), (yyvsp[0].attr_list)); -} -#line 6343 "built/tmp/cppBison.yxx.c" - break; - - case 248: /* not_paren_formal_parameter_identifier: KW_CONST not_paren_formal_parameter_identifier */ -#line 2253 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_const); -} -#line 6352 "built/tmp/cppBison.yxx.c" - break; - - case 249: /* not_paren_formal_parameter_identifier: KW_VOLATILE not_paren_formal_parameter_identifier */ -#line 2258 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_volatile); -} -#line 6361 "built/tmp/cppBison.yxx.c" - break; - - case 250: /* not_paren_formal_parameter_identifier: KW_RESTRICT not_paren_formal_parameter_identifier */ -#line 2263 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_restrict); -} -#line 6370 "built/tmp/cppBison.yxx.c" - break; - - case 251: /* not_paren_formal_parameter_identifier: '*' optional_attributes not_paren_formal_parameter_identifier */ -#line 2268 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_pointer, (yyvsp[-1].attr_list)); -} -#line 6379 "built/tmp/cppBison.yxx.c" - break; - - case 252: /* not_paren_formal_parameter_identifier: '&' optional_attributes not_paren_formal_parameter_identifier */ -#line 2273 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_reference, (yyvsp[-1].attr_list)); -} -#line 6388 "built/tmp/cppBison.yxx.c" - break; - - case 253: /* not_paren_formal_parameter_identifier: ANDAND optional_attributes not_paren_formal_parameter_identifier */ -#line 2278 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_rvalue_reference, (yyvsp[-1].attr_list)); -} -#line 6397 "built/tmp/cppBison.yxx.c" - break; - - case 254: /* not_paren_formal_parameter_identifier: SCOPING '*' optional_attributes not_paren_formal_parameter_identifier */ -#line 2283 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_scoped_pointer_modifier((yyvsp[-3].u.identifier), (yyvsp[-1].attr_list)); -} -#line 6406 "built/tmp/cppBison.yxx.c" - break; - - case 255: /* not_paren_formal_parameter_identifier: not_paren_formal_parameter_identifier '[' optional_const_expr ']' optional_attributes */ -#line 2288 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-4].u.inst_ident); - (yyval.u.inst_ident)->add_array_modifier((yyvsp[-2].u.expr), (yyvsp[0].attr_list)); -} -#line 6415 "built/tmp/cppBison.yxx.c" - break; - - case 256: /* formal_parameter_identifier: empty */ -#line 2296 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); -} -#line 6423 "built/tmp/cppBison.yxx.c" - break; - - case 257: /* formal_parameter_identifier: name_no_final optional_attributes */ -#line 2300 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier((yyvsp[-1].u.identifier), (yyvsp[0].attr_list)); -} -#line 6431 "built/tmp/cppBison.yxx.c" - break; - - case 258: /* formal_parameter_identifier: KW_CONST formal_parameter_identifier */ -#line 2304 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_const); -} -#line 6440 "built/tmp/cppBison.yxx.c" - break; - - case 259: /* formal_parameter_identifier: KW_VOLATILE formal_parameter_identifier */ -#line 2309 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_volatile); -} -#line 6449 "built/tmp/cppBison.yxx.c" - break; - - case 260: /* formal_parameter_identifier: KW_RESTRICT formal_parameter_identifier */ -#line 2314 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_restrict); -} -#line 6458 "built/tmp/cppBison.yxx.c" - break; - - case 261: /* formal_parameter_identifier: '*' optional_attributes formal_parameter_identifier */ -#line 2319 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_pointer, (yyvsp[-1].attr_list)); -} -#line 6467 "built/tmp/cppBison.yxx.c" - break; - - case 262: /* formal_parameter_identifier: '&' optional_attributes formal_parameter_identifier */ -#line 2324 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_reference, (yyvsp[-1].attr_list)); -} -#line 6476 "built/tmp/cppBison.yxx.c" - break; - - case 263: /* formal_parameter_identifier: ANDAND optional_attributes formal_parameter_identifier */ -#line 2329 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_rvalue_reference, (yyvsp[-1].attr_list)); -} -#line 6485 "built/tmp/cppBison.yxx.c" - break; - - case 264: /* formal_parameter_identifier: SCOPING '*' optional_attributes formal_parameter_identifier */ -#line 2334 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_scoped_pointer_modifier((yyvsp[-3].u.identifier), (yyvsp[-1].attr_list)); -} -#line 6494 "built/tmp/cppBison.yxx.c" - break; - - case 265: /* formal_parameter_identifier: formal_parameter_identifier '[' optional_const_expr ']' optional_attributes */ -#line 2339 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-4].u.inst_ident); - (yyval.u.inst_ident)->add_array_modifier((yyvsp[-2].u.expr), (yyvsp[0].attr_list)); -} -#line 6503 "built/tmp/cppBison.yxx.c" - break; - - case 266: /* formal_parameter_identifier: '(' formal_parameter_identifier ')' '(' function_parameter_list ')' function_post optional_attributes */ -#line 2344 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-6].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_paren); - (yyval.u.inst_ident)->add_func_modifier((yyvsp[-3].u.param_list), (yyvsp[-1].u.integer), nullptr, (yyvsp[0].attr_list)); -} -#line 6513 "built/tmp/cppBison.yxx.c" - break; - - case 267: /* formal_parameter_identifier: '(' formal_parameter_identifier ')' */ -#line 2350 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-1].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_paren); -} -#line 6522 "built/tmp/cppBison.yxx.c" - break; - - case 268: /* parameter_pack_identifier: ELLIPSIS */ -#line 2358 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); - (yyval.u.inst_ident)->_packed = true; -} -#line 6531 "built/tmp/cppBison.yxx.c" - break; - - case 269: /* parameter_pack_identifier: ELLIPSIS name optional_attributes */ -#line 2363 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier((yyvsp[-1].u.identifier), (yyvsp[0].attr_list)); - (yyval.u.inst_ident)->_packed = true; -} -#line 6540 "built/tmp/cppBison.yxx.c" - break; - - case 270: /* parameter_pack_identifier: KW_CONST parameter_pack_identifier */ -#line 2368 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_const); -} -#line 6549 "built/tmp/cppBison.yxx.c" - break; - - case 271: /* parameter_pack_identifier: KW_VOLATILE parameter_pack_identifier */ -#line 2373 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_volatile); -} -#line 6558 "built/tmp/cppBison.yxx.c" - break; - - case 272: /* parameter_pack_identifier: KW_RESTRICT parameter_pack_identifier */ -#line 2378 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_restrict); -} -#line 6567 "built/tmp/cppBison.yxx.c" - break; - - case 273: /* parameter_pack_identifier: '*' optional_attributes parameter_pack_identifier */ -#line 2383 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_pointer, (yyvsp[-1].attr_list)); -} -#line 6576 "built/tmp/cppBison.yxx.c" - break; - - case 274: /* parameter_pack_identifier: '&' optional_attributes parameter_pack_identifier */ -#line 2388 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_reference, (yyvsp[-1].attr_list)); -} -#line 6585 "built/tmp/cppBison.yxx.c" - break; - - case 275: /* parameter_pack_identifier: ANDAND optional_attributes parameter_pack_identifier */ -#line 2393 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_rvalue_reference, (yyvsp[-1].attr_list)); -} -#line 6594 "built/tmp/cppBison.yxx.c" - break; - - case 276: /* parameter_pack_identifier: SCOPING '*' optional_attributes parameter_pack_identifier */ -#line 2398 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_scoped_pointer_modifier((yyvsp[-3].u.identifier), (yyvsp[-1].attr_list)); -} -#line 6603 "built/tmp/cppBison.yxx.c" - break; - - case 277: /* parameter_pack_identifier: parameter_pack_identifier '[' optional_const_expr ']' optional_attributes */ -#line 2403 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-4].u.inst_ident); - (yyval.u.inst_ident)->add_array_modifier((yyvsp[-2].u.expr), (yyvsp[0].attr_list)); -} -#line 6612 "built/tmp/cppBison.yxx.c" - break; - - case 278: /* parameter_pack_identifier: '(' parameter_pack_identifier ')' '(' function_parameter_list ')' function_post optional_attributes */ -#line 2408 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-6].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_paren); - (yyval.u.inst_ident)->add_func_modifier((yyvsp[-3].u.param_list), (yyvsp[-1].u.integer), nullptr, (yyvsp[0].attr_list)); -} -#line 6622 "built/tmp/cppBison.yxx.c" - break; - - case 279: /* parameter_pack_identifier: '(' parameter_pack_identifier ')' */ -#line 2414 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-1].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_paren); -} -#line 6631 "built/tmp/cppBison.yxx.c" - break; - - case 280: /* not_paren_empty_instance_identifier: empty */ -#line 2422 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); -} -#line 6639 "built/tmp/cppBison.yxx.c" - break; - - case 281: /* not_paren_empty_instance_identifier: ELLIPSIS */ -#line 2426 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); - (yyval.u.inst_ident)->_packed = true; -} -#line 6648 "built/tmp/cppBison.yxx.c" - break; - - case 282: /* not_paren_empty_instance_identifier: ELLIPSIS name optional_attributes */ -#line 2431 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier((yyvsp[-1].u.identifier), (yyvsp[0].attr_list)); - (yyval.u.inst_ident)->_packed = true; -} -#line 6657 "built/tmp/cppBison.yxx.c" - break; - - case 283: /* not_paren_empty_instance_identifier: KW_CONST not_paren_empty_instance_identifier */ -#line 2436 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_const); -} -#line 6666 "built/tmp/cppBison.yxx.c" - break; - - case 284: /* not_paren_empty_instance_identifier: KW_VOLATILE not_paren_empty_instance_identifier */ -#line 2441 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_volatile); -} -#line 6675 "built/tmp/cppBison.yxx.c" - break; - - case 285: /* not_paren_empty_instance_identifier: KW_RESTRICT not_paren_empty_instance_identifier */ -#line 2446 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_restrict); -} -#line 6684 "built/tmp/cppBison.yxx.c" - break; - - case 286: /* not_paren_empty_instance_identifier: '*' optional_attributes not_paren_empty_instance_identifier */ -#line 2451 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_pointer, (yyvsp[-1].attr_list)); -} -#line 6693 "built/tmp/cppBison.yxx.c" - break; - - case 287: /* not_paren_empty_instance_identifier: '&' optional_attributes not_paren_empty_instance_identifier */ -#line 2456 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_reference, (yyvsp[-1].attr_list)); -} -#line 6702 "built/tmp/cppBison.yxx.c" - break; - - case 288: /* not_paren_empty_instance_identifier: ANDAND optional_attributes not_paren_empty_instance_identifier */ -#line 2461 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_rvalue_reference, (yyvsp[-1].attr_list)); -} -#line 6711 "built/tmp/cppBison.yxx.c" - break; - - case 289: /* not_paren_empty_instance_identifier: SCOPING '*' optional_attributes not_paren_empty_instance_identifier */ -#line 2466 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_scoped_pointer_modifier((yyvsp[-3].u.identifier), (yyvsp[-1].attr_list)); -} -#line 6720 "built/tmp/cppBison.yxx.c" - break; - - case 290: /* not_paren_empty_instance_identifier: not_paren_empty_instance_identifier '[' optional_const_expr ']' optional_attributes */ -#line 2471 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-4].u.inst_ident); - (yyval.u.inst_ident)->add_array_modifier((yyvsp[-2].u.expr), (yyvsp[0].attr_list)); -} -#line 6729 "built/tmp/cppBison.yxx.c" - break; - - case 291: /* empty_instance_identifier: empty */ -#line 2479 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); -} -#line 6737 "built/tmp/cppBison.yxx.c" - break; - - case 292: /* empty_instance_identifier: ELLIPSIS */ -#line 2483 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); - (yyval.u.inst_ident)->_packed = true; -} -#line 6746 "built/tmp/cppBison.yxx.c" - break; - - case 293: /* empty_instance_identifier: ELLIPSIS name optional_attributes */ -#line 2488 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier((yyvsp[-1].u.identifier), (yyvsp[0].attr_list)); - (yyval.u.inst_ident)->_packed = true; -} -#line 6755 "built/tmp/cppBison.yxx.c" - break; - - case 294: /* empty_instance_identifier: KW_CONST empty_instance_identifier */ -#line 2493 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_const); -} -#line 6764 "built/tmp/cppBison.yxx.c" - break; - - case 295: /* empty_instance_identifier: KW_VOLATILE empty_instance_identifier */ -#line 2498 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_volatile); -} -#line 6773 "built/tmp/cppBison.yxx.c" - break; - - case 296: /* empty_instance_identifier: KW_RESTRICT empty_instance_identifier */ -#line 2503 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_restrict); -} -#line 6782 "built/tmp/cppBison.yxx.c" - break; - - case 297: /* empty_instance_identifier: '*' optional_attributes not_paren_empty_instance_identifier */ -#line 2508 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_pointer, (yyvsp[-1].attr_list)); -} -#line 6791 "built/tmp/cppBison.yxx.c" - break; - - case 298: /* empty_instance_identifier: '&' optional_attributes not_paren_empty_instance_identifier */ -#line 2513 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_reference, (yyvsp[-1].attr_list)); -} -#line 6800 "built/tmp/cppBison.yxx.c" - break; - - case 299: /* empty_instance_identifier: ANDAND optional_attributes not_paren_empty_instance_identifier */ -#line 2518 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_rvalue_reference, (yyvsp[-1].attr_list)); -} -#line 6809 "built/tmp/cppBison.yxx.c" - break; - - case 300: /* empty_instance_identifier: SCOPING '*' optional_attributes not_paren_empty_instance_identifier */ -#line 2523 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[0].u.inst_ident); - (yyval.u.inst_ident)->add_scoped_pointer_modifier((yyvsp[-3].u.identifier), (yyvsp[-1].attr_list)); -} -#line 6818 "built/tmp/cppBison.yxx.c" - break; - - case 301: /* empty_instance_identifier: not_paren_empty_instance_identifier '[' optional_const_expr ']' optional_attributes */ -#line 2528 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-4].u.inst_ident); - (yyval.u.inst_ident)->add_array_modifier((yyvsp[-2].u.expr), (yyvsp[0].attr_list)); -} -#line 6827 "built/tmp/cppBison.yxx.c" - break; - - case 302: /* empty_instance_identifier: '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type */ -#line 2533 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = new CPPInstanceIdentifier(nullptr); - (yyval.u.inst_ident)->add_modifier(IIT_paren); - (yyval.u.inst_ident)->add_func_modifier((yyvsp[-4].u.param_list), (yyvsp[-2].u.integer), (yyvsp[0].u.type), (yyvsp[-1].attr_list)); -} -#line 6837 "built/tmp/cppBison.yxx.c" - break; - - case 303: /* empty_instance_identifier: '(' '*' optional_attributes not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type */ -#line 2539 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-7].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_pointer, (yyvsp[-8].attr_list)); - (yyval.u.inst_ident)->add_modifier(IIT_paren); - (yyval.u.inst_ident)->add_func_modifier((yyvsp[-4].u.param_list), (yyvsp[-2].u.integer), (yyvsp[0].u.type), (yyvsp[-1].attr_list)); -} -#line 6848 "built/tmp/cppBison.yxx.c" - break; - - case 304: /* empty_instance_identifier: '(' '&' optional_attributes not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type */ -#line 2546 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-7].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_reference, (yyvsp[-8].attr_list)); - (yyval.u.inst_ident)->add_modifier(IIT_paren); - (yyval.u.inst_ident)->add_func_modifier((yyvsp[-4].u.param_list), (yyvsp[-2].u.integer), (yyvsp[0].u.type), (yyvsp[-1].attr_list)); -} -#line 6859 "built/tmp/cppBison.yxx.c" - break; - - case 305: /* empty_instance_identifier: '(' ANDAND optional_attributes not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type */ -#line 2553 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.inst_ident) = (yyvsp[-7].u.inst_ident); - (yyval.u.inst_ident)->add_modifier(IIT_rvalue_reference, (yyvsp[-8].attr_list)); - (yyval.u.inst_ident)->add_modifier(IIT_paren); - (yyval.u.inst_ident)->add_func_modifier((yyvsp[-4].u.param_list), (yyvsp[-2].u.integer), (yyvsp[0].u.type), (yyvsp[-1].attr_list)); -} -#line 6870 "built/tmp/cppBison.yxx.c" - break; - - case 306: /* type: simple_type */ -#line 2563 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type((yyvsp[0].u.simple_type)); -} -#line 6878 "built/tmp/cppBison.yxx.c" - break; - - case 307: /* type: TYPENAME_IDENTIFIER */ -#line 2567 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if ((yyval.u.type) == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[0])); - } - assert((yyval.u.type) != nullptr); -} -#line 6890 "built/tmp/cppBison.yxx.c" - break; - - case 308: /* type: KW_TYPENAME name */ -#line 2575 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPTBDType((yyvsp[0].u.identifier))); -} -#line 6898 "built/tmp/cppBison.yxx.c" - break; - - case 309: /* type: anonymous_struct */ -#line 2579 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type((yyvsp[0].u.struct_type)); -} -#line 6906 "built/tmp/cppBison.yxx.c" - break; - - case 310: /* type: named_struct */ -#line 2583 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type((yyvsp[0].u.struct_type)); -} -#line 6914 "built/tmp/cppBison.yxx.c" - break; - - case 311: /* type: enum */ -#line 2587 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type((yyvsp[0].u.enum_type)); -} -#line 6922 "built/tmp/cppBison.yxx.c" - break; - - case 312: /* type: struct_keyword optional_attributes name */ -#line 2591 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - (yyval.u.type) = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType((yyvsp[-2].u.extension_enum), (yyvsp[0].u.identifier), current_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list))) - ->as_extension_type(); - CPPScope *scope = (yyvsp[0].u.identifier)->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - (yyval.u.type) = et; - } -} -#line 6942 "built/tmp/cppBison.yxx.c" - break; - - case 313: /* type: enum_keyword optional_attributes name_no_final ':' enum_element_type */ -#line 2607 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = (yyvsp[-2].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - (yyval.u.type) = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType((yyvsp[-4].u.extension_enum), (yyvsp[-2].u.identifier), current_scope, (yylsp[-4]).file, (yyvsp[-3].attr_list))) - ->as_extension_type(); - CPPScope *scope = (yyvsp[-2].u.identifier)->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - (yyval.u.type) = et; - } -} -#line 6962 "built/tmp/cppBison.yxx.c" - break; - - case 314: /* type: KW_DECLTYPE '(' const_expr ')' */ -#line 2623 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[-1].u.expr)->determine_type(); - if ((yyval.u.type) == nullptr) { - stringstream str; - str << *(yyvsp[-1].u.expr); - yyerror("could not determine type of " + str.str(), (yylsp[-1])); - } -} -#line 6975 "built/tmp/cppBison.yxx.c" - break; - - case 315: /* type: KW_DECLTYPE '(' KW_AUTO ')' */ -#line 2632 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} -#line 6983 "built/tmp/cppBison.yxx.c" - break; - - case 316: /* type: KW_UNDERLYING_TYPE '(' full_type ')' */ -#line 2636 "dtool/src/cppparser/cppBison.yxx" -{ - CPPEnumType *enum_type = (yyvsp[-1].u.type)->as_enum_type(); - if (enum_type == nullptr) { - yyerror("an enumeration type is required", (yylsp[-1])); - (yyval.u.type) = (yyvsp[-1].u.type); - } else { - (yyval.u.type) = enum_type->get_underlying_type(); - } -} -#line 6997 "built/tmp/cppBison.yxx.c" - break; - - case 317: /* type: KW_AUTO */ -#line 2646 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} -#line 7005 "built/tmp/cppBison.yxx.c" - break; - - case 318: /* type: KW_BUILTIN_VA_LIST */ -#line 2650 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_va_list)); -} -#line 7013 "built/tmp/cppBison.yxx.c" - break; - - case 319: /* type_pack: TYPEPACK_IDENTIFIER */ -#line 2657 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if ((yyval.u.type) == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[0])); - } - assert((yyval.u.type) != nullptr); -} -#line 7025 "built/tmp/cppBison.yxx.c" - break; - - case 320: /* type_decl: simple_type */ -#line 2668 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type((yyvsp[0].u.simple_type)); -} -#line 7033 "built/tmp/cppBison.yxx.c" - break; - - case 321: /* type_decl: TYPENAME_IDENTIFIER */ -#line 2672 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if ((yyval.u.decl) == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[0])); - } - assert((yyval.u.decl) != nullptr); -} -#line 7045 "built/tmp/cppBison.yxx.c" - break; - - case 322: /* type_decl: KW_TYPENAME name */ -#line 2680 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type(new CPPTBDType((yyvsp[0].u.identifier))); -} -#line 7053 "built/tmp/cppBison.yxx.c" - break; - - case 323: /* type_decl: anonymous_struct */ -#line 2684 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type((yyvsp[0].u.struct_type)); -} -#line 7061 "built/tmp/cppBison.yxx.c" - break; - - case 324: /* type_decl: named_struct */ -#line 2688 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = new CPPTypeDeclaration(CPPType::new_type((yyvsp[0].u.struct_type))); -} -#line 7069 "built/tmp/cppBison.yxx.c" - break; - - case 325: /* type_decl: enum */ -#line 2692 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = new CPPTypeDeclaration(CPPType::new_type((yyvsp[0].u.enum_type))); -} -#line 7077 "built/tmp/cppBison.yxx.c" - break; - - case 326: /* type_decl: struct_keyword optional_attributes name */ -#line 2696 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - (yyval.u.decl) = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType((yyvsp[-2].u.extension_enum), (yyvsp[0].u.identifier), current_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list))) - ->as_extension_type(); - CPPScope *scope = (yyvsp[0].u.identifier)->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - (yyval.u.decl) = et; - } -} -#line 7097 "built/tmp/cppBison.yxx.c" - break; - - case 327: /* type_decl: enum_keyword optional_attributes name_no_final ':' enum_element_type */ -#line 2712 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = (yyvsp[-2].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - (yyval.u.decl) = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType((yyvsp[-4].u.extension_enum), (yyvsp[-2].u.identifier), current_scope, (yylsp[-4]).file, (yyvsp[-3].attr_list))) - ->as_extension_type(); - CPPScope *scope = (yyvsp[-2].u.identifier)->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - (yyval.u.decl) = et; - } -} -#line 7117 "built/tmp/cppBison.yxx.c" - break; - - case 328: /* type_decl: enum_keyword optional_attributes name */ -#line 2728 "dtool/src/cppparser/cppBison.yxx" -{ - yywarning(string("C++ does not permit forward declaration of untyped enum ") + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[-2])); - - CPPType *type = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - (yyval.u.decl) = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType((yyvsp[-2].u.extension_enum), (yyvsp[0].u.identifier), current_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list))) - ->as_extension_type(); - CPPScope *scope = (yyvsp[0].u.identifier)->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - (yyval.u.decl) = et; - } -} -#line 7139 "built/tmp/cppBison.yxx.c" - break; - - case 329: /* type_decl: KW_DECLTYPE '(' const_expr ')' */ -#line 2746 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = (yyvsp[-1].u.expr)->determine_type(); - if ((yyval.u.decl) == nullptr) { - stringstream str; - str << *(yyvsp[-1].u.expr); - yyerror("could not determine type of " + str.str(), (yylsp[-1])); - } -} -#line 7152 "built/tmp/cppBison.yxx.c" - break; - - case 330: /* type_decl: KW_DECLTYPE '(' KW_AUTO ')' */ -#line 2755 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} -#line 7160 "built/tmp/cppBison.yxx.c" - break; - - case 331: /* type_decl: KW_UNDERLYING_TYPE '(' full_type ')' */ -#line 2759 "dtool/src/cppparser/cppBison.yxx" -{ - CPPEnumType *enum_type = (yyvsp[-1].u.type)->as_enum_type(); - if (enum_type == nullptr) { - yyerror("an enumeration type is required", (yylsp[-1])); - (yyval.u.decl) = (yyvsp[-1].u.type); - } else { - (yyval.u.decl) = enum_type->get_underlying_type(); - } -} -#line 7174 "built/tmp/cppBison.yxx.c" - break; - - case 332: /* type_decl: KW_AUTO */ -#line 2769 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} -#line 7182 "built/tmp/cppBison.yxx.c" - break; - - case 333: /* type_decl: KW_BUILTIN_VA_LIST */ -#line 2773 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_va_list)); -} -#line 7190 "built/tmp/cppBison.yxx.c" - break; - - case 334: /* predefined_type: simple_type */ -#line 2780 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type((yyvsp[0].u.simple_type)); -} -#line 7198 "built/tmp/cppBison.yxx.c" - break; - - case 335: /* predefined_type: TYPENAME_IDENTIFIER */ -#line 2784 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if ((yyval.u.type) == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[0].u.identifier)->get_fully_scoped_name(), (yylsp[0])); - } - assert((yyval.u.type) != nullptr); -} -#line 7210 "built/tmp/cppBison.yxx.c" - break; - - case 336: /* predefined_type: KW_TYPENAME name */ -#line 2792 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPTBDType((yyvsp[0].u.identifier))); -} -#line 7218 "built/tmp/cppBison.yxx.c" - break; - - case 337: /* predefined_type: struct_keyword optional_attributes name */ -#line 2796 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - (yyval.u.type) = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType((yyvsp[-2].u.extension_enum), (yyvsp[0].u.identifier), current_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list))) - ->as_extension_type(); - CPPScope *scope = (yyvsp[0].u.identifier)->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - (yyval.u.type) = et; - } -} -#line 7238 "built/tmp/cppBison.yxx.c" - break; - - case 338: /* predefined_type: enum_keyword optional_attributes name */ -#line 2812 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - (yyval.u.type) = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType((yyvsp[-2].u.extension_enum), (yyvsp[0].u.identifier), current_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list))) - ->as_extension_type(); - CPPScope *scope = (yyvsp[0].u.identifier)->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - (yyval.u.type) = et; - } -} -#line 7258 "built/tmp/cppBison.yxx.c" - break; - - case 339: /* predefined_type: KW_DECLTYPE '(' const_expr ')' */ -#line 2828 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[-1].u.expr)->determine_type(); - if ((yyval.u.type) == nullptr) { - stringstream str; - str << *(yyvsp[-1].u.expr); - yyerror("could not determine type of " + str.str(), (yylsp[-1])); - } -} -#line 7271 "built/tmp/cppBison.yxx.c" - break; - - case 340: /* predefined_type: KW_UNDERLYING_TYPE '(' full_type ')' */ -#line 2837 "dtool/src/cppparser/cppBison.yxx" -{ - CPPEnumType *enum_type = (yyvsp[-1].u.type)->as_enum_type(); - if (enum_type == nullptr) { - yyerror("an enumeration type is required", (yylsp[-1])); - (yyval.u.type) = (yyvsp[-1].u.type); - } else { - (yyval.u.type) = enum_type->get_underlying_type(); - } -} -#line 7285 "built/tmp/cppBison.yxx.c" - break; - - case 341: /* predefined_type: KW_AUTO */ -#line 2847 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} -#line 7293 "built/tmp/cppBison.yxx.c" - break; - - case 342: /* predefined_type: KW_BUILTIN_VA_LIST */ -#line 2851 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_va_list)); -} -#line 7301 "built/tmp/cppBison.yxx.c" - break; - - case 343: /* var_type_decl: type_decl */ -#line 2858 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.decl) = (yyvsp[0].u.decl); -} -#line 7309 "built/tmp/cppBison.yxx.c" - break; - - case 344: /* var_type_decl: IDENTIFIER */ -#line 2862 "dtool/src/cppparser/cppBison.yxx" -{ - yyerror(string("unknown type '") + (yyvsp[0].u.identifier)->get_fully_scoped_name() + "'", (yylsp[0])); - - (yyval.u.decl) = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); -} -#line 7319 "built/tmp/cppBison.yxx.c" - break; - - case 345: /* full_type: type empty_instance_identifier */ -#line 2870 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.inst_ident)->unroll_type((yyvsp[-1].u.type)); -} -#line 7327 "built/tmp/cppBison.yxx.c" - break; - - case 346: /* full_type: KW_CONST type empty_instance_identifier */ -#line 2874 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[0].u.inst_ident)->add_modifier(IIT_const); - (yyval.u.type) = (yyvsp[0].u.inst_ident)->unroll_type((yyvsp[-1].u.type)); -} -#line 7336 "built/tmp/cppBison.yxx.c" - break; - - case 347: /* full_type: type_pack empty_instance_identifier */ -#line 2879 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.inst_ident)->unroll_type((yyvsp[-1].u.type)); -} -#line 7344 "built/tmp/cppBison.yxx.c" - break; - - case 348: /* full_type: KW_CONST type_pack empty_instance_identifier */ -#line 2883 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[0].u.inst_ident)->add_modifier(IIT_const); - (yyval.u.type) = (yyvsp[0].u.inst_ident)->unroll_type((yyvsp[-1].u.type)); -} -#line 7353 "built/tmp/cppBison.yxx.c" - break; - - case 349: /* $@17: %empty */ -#line 2891 "dtool/src/cppparser/cppBison.yxx" -{ - CPPVisibility starting_vis = - ((yyvsp[-2].u.extension_enum) == CPPExtensionType::T_class) ? V_private : V_public; - - CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("anon"), - starting_vis); - CPPStructType *st = new CPPStructType((yyvsp[-2].u.extension_enum), nullptr, current_scope, - new_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list)); - new_scope->set_struct_type(st); - - push_scope(new_scope); - push_struct(st); -} -#line 7371 "built/tmp/cppBison.yxx.c" - break; - - case 350: /* anonymous_struct: struct_keyword optional_attributes '{' $@17 cpp '}' */ -#line 2905 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.struct_type) = current_struct; - current_struct->_incomplete = false; - pop_struct(); - pop_scope(); -} -#line 7382 "built/tmp/cppBison.yxx.c" - break; - - case 351: /* $@18: %empty */ -#line 2915 "dtool/src/cppparser/cppBison.yxx" -{ - CPPVisibility starting_vis = - ((yyvsp[-2].u.extension_enum) == CPPExtensionType::T_class) ? V_private : V_public; - - CPPScope *scope = (yyvsp[0].u.identifier)->get_scope(current_scope, global_scope, current_lexer); - if (scope == nullptr) { - scope = current_scope; - } - CPPScope *new_scope = new CPPScope(scope, (yyvsp[0].u.identifier)->_names.back(), - starting_vis); - - CPPStructType *st = new CPPStructType((yyvsp[-2].u.extension_enum), (yyvsp[0].u.identifier), current_scope, - new_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list)); - new_scope->set_struct_type(st); - current_scope->define_extension_type(st); - - push_scope(new_scope); - push_struct(st); -} -#line 7406 "built/tmp/cppBison.yxx.c" - break; - - case 352: /* named_struct: struct_keyword optional_attributes name_no_final $@18 maybe_final maybe_class_derivation '{' cpp '}' */ -#line 2935 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.struct_type) = current_struct; - current_struct->_incomplete = false; - pop_struct(); - pop_scope(); -} -#line 7417 "built/tmp/cppBison.yxx.c" - break; - - case 354: /* maybe_final: KW_FINAL */ -#line 2946 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->_final = true; -} -#line 7425 "built/tmp/cppBison.yxx.c" - break; - - case 359: /* base_specification: class_derivation_name */ -#line 2963 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_unknown, false); -} -#line 7433 "built/tmp/cppBison.yxx.c" - break; - - case 360: /* base_specification: KW_PUBLIC class_derivation_name */ -#line 2967 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_public, false); -} -#line 7441 "built/tmp/cppBison.yxx.c" - break; - - case 361: /* base_specification: KW_PROTECTED class_derivation_name */ -#line 2971 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_protected, false); -} -#line 7449 "built/tmp/cppBison.yxx.c" - break; - - case 362: /* base_specification: KW_PRIVATE class_derivation_name */ -#line 2975 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_private, false); -} -#line 7457 "built/tmp/cppBison.yxx.c" - break; - - case 363: /* base_specification: KW_VIRTUAL KW_PUBLIC class_derivation_name */ -#line 2979 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_public, true); -} -#line 7465 "built/tmp/cppBison.yxx.c" - break; - - case 364: /* base_specification: KW_VIRTUAL KW_PROTECTED class_derivation_name */ -#line 2983 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_protected, true); -} -#line 7473 "built/tmp/cppBison.yxx.c" - break; - - case 365: /* base_specification: KW_VIRTUAL KW_PRIVATE class_derivation_name */ -#line 2987 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_private, true); -} -#line 7481 "built/tmp/cppBison.yxx.c" - break; - - case 366: /* base_specification: KW_PUBLIC KW_VIRTUAL class_derivation_name */ -#line 2991 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_public, true); -} -#line 7489 "built/tmp/cppBison.yxx.c" - break; - - case 367: /* base_specification: KW_PROTECTED KW_VIRTUAL class_derivation_name */ -#line 2995 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_protected, true); -} -#line 7497 "built/tmp/cppBison.yxx.c" - break; - - case 368: /* base_specification: KW_PRIVATE KW_VIRTUAL class_derivation_name */ -#line 2999 "dtool/src/cppparser/cppBison.yxx" -{ - current_struct->append_derivation((yyvsp[0].u.type), V_private, true); -} -#line 7505 "built/tmp/cppBison.yxx.c" - break; - - case 369: /* $@19: %empty */ -#line 3006 "dtool/src/cppparser/cppBison.yxx" -{ - if (current_enum->_scope != nullptr) { - push_scope(current_enum->_scope); - } -} -#line 7515 "built/tmp/cppBison.yxx.c" - break; - - case 370: /* enum: enum_decl $@19 '{' enum_body '}' */ -#line 3012 "dtool/src/cppparser/cppBison.yxx" -{ - if (current_enum->_scope != nullptr) { - pop_scope(); - } - (yyval.u.enum_type) = current_enum; - current_enum = nullptr; -} -#line 7527 "built/tmp/cppBison.yxx.c" - break; - - case 371: /* enum_decl: enum_keyword optional_attributes ':' enum_element_type */ -#line 3023 "dtool/src/cppparser/cppBison.yxx" -{ - current_enum = new CPPEnumType((yyvsp[-3].u.extension_enum), nullptr, (yyvsp[0].u.type), current_scope, nullptr, (yylsp[-3]).file, (yyvsp[-2].attr_list)); -} -#line 7535 "built/tmp/cppBison.yxx.c" - break; - - case 372: /* enum_decl: enum_keyword optional_attributes */ -#line 3027 "dtool/src/cppparser/cppBison.yxx" -{ - current_enum = new CPPEnumType((yyvsp[-1].u.extension_enum), nullptr, current_scope, nullptr, (yylsp[-1]).file, (yyvsp[0].attr_list)); -} -#line 7543 "built/tmp/cppBison.yxx.c" - break; - - case 373: /* enum_decl: enum_keyword optional_attributes name_no_final ':' enum_element_type */ -#line 3031 "dtool/src/cppparser/cppBison.yxx" -{ - CPPScope *new_scope = new CPPScope(current_scope, (yyvsp[-2].u.identifier)->_names.back(), V_public); - current_enum = new CPPEnumType((yyvsp[-4].u.extension_enum), (yyvsp[-2].u.identifier), (yyvsp[0].u.type), current_scope, new_scope, (yylsp[-4]).file, (yyvsp[-3].attr_list)); -} -#line 7552 "built/tmp/cppBison.yxx.c" - break; - - case 374: /* enum_decl: enum_keyword optional_attributes name_no_final */ -#line 3036 "dtool/src/cppparser/cppBison.yxx" -{ - CPPScope *new_scope = new CPPScope(current_scope, (yyvsp[0].u.identifier)->_names.back(), V_public); - current_enum = new CPPEnumType((yyvsp[-2].u.extension_enum), (yyvsp[0].u.identifier), current_scope, new_scope, (yylsp[-2]).file, (yyvsp[-1].attr_list)); -} -#line 7561 "built/tmp/cppBison.yxx.c" - break; - - case 375: /* enum_element_type: simple_int_type */ -#line 3044 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type((yyvsp[0].u.simple_type)); -} -#line 7569 "built/tmp/cppBison.yxx.c" - break; - - case 376: /* enum_element_type: TYPENAME_IDENTIFIER */ -#line 3048 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); -} -#line 7577 "built/tmp/cppBison.yxx.c" - break; - - case 378: /* enum_body_trailing_comma: enum_body_trailing_comma name optional_attributes ',' */ -#line 3056 "dtool/src/cppparser/cppBison.yxx" -{ - assert(current_enum != nullptr); - current_enum->add_element((yyvsp[-2].u.identifier)->get_simple_name(), nullptr, current_lexer, (yylsp[-2]), (yyvsp[-1].attr_list)); -} -#line 7586 "built/tmp/cppBison.yxx.c" - break; - - case 379: /* enum_body_trailing_comma: enum_body_trailing_comma name optional_attributes '=' const_expr ',' */ -#line 3061 "dtool/src/cppparser/cppBison.yxx" -{ - assert(current_enum != nullptr); - current_enum->add_element((yyvsp[-4].u.identifier)->get_simple_name(), (yyvsp[-1].u.expr), current_lexer, (yylsp[-4]), (yyvsp[-3].attr_list)); -} -#line 7595 "built/tmp/cppBison.yxx.c" - break; - - case 381: /* enum_body: enum_body_trailing_comma name optional_attributes */ -#line 3069 "dtool/src/cppparser/cppBison.yxx" -{ - assert(current_enum != nullptr); - current_enum->add_element((yyvsp[-1].u.identifier)->get_simple_name(), nullptr, current_lexer, (yylsp[-1]), (yyvsp[0].attr_list)); -} -#line 7604 "built/tmp/cppBison.yxx.c" - break; - - case 382: /* enum_body: enum_body_trailing_comma name optional_attributes '=' const_expr */ -#line 3074 "dtool/src/cppparser/cppBison.yxx" -{ - assert(current_enum != nullptr); - current_enum->add_element((yyvsp[-3].u.identifier)->get_simple_name(), (yyvsp[0].u.expr), current_lexer, (yylsp[-3]), (yyvsp[-2].attr_list)); -} -#line 7613 "built/tmp/cppBison.yxx.c" - break; - - case 383: /* enum_keyword: KW_ENUM */ -#line 3082 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.extension_enum) = CPPExtensionType::T_enum; -} -#line 7621 "built/tmp/cppBison.yxx.c" - break; - - case 384: /* enum_keyword: KW_ENUM KW_CLASS */ -#line 3086 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.extension_enum) = CPPExtensionType::T_enum_class; -} -#line 7629 "built/tmp/cppBison.yxx.c" - break; - - case 385: /* enum_keyword: KW_ENUM KW_STRUCT */ -#line 3090 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.extension_enum) = CPPExtensionType::T_enum_struct; -} -#line 7637 "built/tmp/cppBison.yxx.c" - break; - - case 386: /* struct_keyword: KW_CLASS */ -#line 3097 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.extension_enum) = CPPExtensionType::T_class; -} -#line 7645 "built/tmp/cppBison.yxx.c" - break; - - case 387: /* struct_keyword: KW_STRUCT */ -#line 3101 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.extension_enum) = CPPExtensionType::T_struct; -} -#line 7653 "built/tmp/cppBison.yxx.c" - break; - - case 388: /* struct_keyword: KW_UNION */ -#line 3105 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.extension_enum) = CPPExtensionType::T_union; -} -#line 7661 "built/tmp/cppBison.yxx.c" - break; - - case 389: /* $@20: %empty */ -#line 3112 "dtool/src/cppparser/cppBison.yxx" -{ - CPPScope *scope = (yyvsp[-1].u.identifier)->find_scope(current_scope, global_scope, current_lexer); - if (scope == nullptr) { - // This must be a new namespace declaration. - CPPScope *parent_scope = - (yyvsp[-1].u.identifier)->get_scope(current_scope, global_scope, current_lexer); - if (parent_scope == nullptr) { - parent_scope = current_scope; - } - scope = new CPPScope(parent_scope, (yyvsp[-1].u.identifier)->_names.back(), V_public); - } - - CPPNamespace *nspace = new CPPNamespace((yyvsp[-1].u.identifier), scope, (yylsp[-3]).file, (yyvsp[-2].attr_list)); - current_scope->add_declaration(nspace, global_scope, current_lexer, (yylsp[-3])); - current_scope->define_namespace(nspace); - push_scope(scope); -} -#line 7683 "built/tmp/cppBison.yxx.c" - break; - - case 390: /* namespace_declaration: KW_NAMESPACE optional_attributes name '{' $@20 cpp '}' */ -#line 3130 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); -} -#line 7691 "built/tmp/cppBison.yxx.c" - break; - - case 391: /* $@21: %empty */ -#line 3134 "dtool/src/cppparser/cppBison.yxx" -{ - CPPScope *scope = (yyvsp[-1].u.identifier)->find_scope(current_scope, global_scope, current_lexer); - if (scope == nullptr) { - // This must be a new namespace declaration. - CPPScope *parent_scope = - (yyvsp[-1].u.identifier)->get_scope(current_scope, global_scope, current_lexer); - if (parent_scope == nullptr) { - parent_scope = current_scope; - } - scope = new CPPScope(parent_scope, (yyvsp[-1].u.identifier)->_names.back(), V_public); - } - - CPPNamespace *nspace = new CPPNamespace((yyvsp[-1].u.identifier), scope, (yylsp[-2]).file); - nspace->_is_inline = true; - current_scope->add_declaration(nspace, global_scope, current_lexer, (yylsp[-2])); - current_scope->define_namespace(nspace); - push_scope(scope); -} -#line 7714 "built/tmp/cppBison.yxx.c" - break; - - case 392: /* namespace_declaration: KW_INLINE KW_NAMESPACE name '{' $@21 cpp '}' */ -#line 3153 "dtool/src/cppparser/cppBison.yxx" -{ - pop_scope(); -} -#line 7722 "built/tmp/cppBison.yxx.c" - break; - - case 395: /* using_declaration: KW_USING name ';' */ -#line 3162 "dtool/src/cppparser/cppBison.yxx" -{ - CPPUsing *using_decl = new CPPUsing((yyvsp[-1].u.identifier), false, (yylsp[-2]).file); - current_scope->add_declaration(using_decl, global_scope, current_lexer, (yylsp[-2])); - current_scope->add_using(using_decl, global_scope, current_lexer); -} -#line 7732 "built/tmp/cppBison.yxx.c" - break; - - case 396: /* using_declaration: KW_USING name optional_attributes '=' full_type ';' */ -#line 3168 "dtool/src/cppparser/cppBison.yxx" -{ - // This is really just an alternative way to declare a typedef. - CPPTypedefType *typedef_type = new CPPTypedefType((yyvsp[-1].u.type), (yyvsp[-4].u.identifier), current_scope, (yyvsp[-3].attr_list)); - typedef_type->_using = true; - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, (yylsp[-5])); -} -#line 7743 "built/tmp/cppBison.yxx.c" - break; - - case 397: /* using_declaration: KW_USING KW_NAMESPACE name ';' */ -#line 3175 "dtool/src/cppparser/cppBison.yxx" -{ - CPPUsing *using_decl = new CPPUsing((yyvsp[-1].u.identifier), true, (yylsp[-3]).file); - current_scope->add_declaration(using_decl, global_scope, current_lexer, (yylsp[-3])); - current_scope->add_using(using_decl, global_scope, current_lexer); -} -#line 7753 "built/tmp/cppBison.yxx.c" - break; - - case 398: /* using_declaration: KW_USING KW_ENUM name ';' */ -#line 3181 "dtool/src/cppparser/cppBison.yxx" -{ - CPPUsing *using_decl = new CPPUsing((yyvsp[-1].u.identifier), false, (yylsp[-3]).file); - current_scope->add_declaration(using_decl, global_scope, current_lexer, (yylsp[-3])); - current_scope->add_using(using_decl, global_scope, current_lexer); -} -#line 7763 "built/tmp/cppBison.yxx.c" - break; - - case 402: /* simple_int_type: KW_BOOL */ -#line 3196 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_bool); -} -#line 7771 "built/tmp/cppBison.yxx.c" - break; - - case 403: /* simple_int_type: KW_CHAR */ -#line 3200 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_char); -} -#line 7779 "built/tmp/cppBison.yxx.c" - break; - - case 404: /* simple_int_type: KW_WCHAR_T */ -#line 3204 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_wchar_t); -} -#line 7787 "built/tmp/cppBison.yxx.c" - break; - - case 405: /* simple_int_type: KW_CHAR8_T */ -#line 3208 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_char8_t); -} -#line 7795 "built/tmp/cppBison.yxx.c" - break; - - case 406: /* simple_int_type: KW_CHAR16_T */ -#line 3212 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_char16_t); -} -#line 7803 "built/tmp/cppBison.yxx.c" - break; - - case 407: /* simple_int_type: KW_CHAR32_T */ -#line 3216 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_char32_t); -} -#line 7811 "built/tmp/cppBison.yxx.c" - break; - - case 408: /* simple_int_type: KW_SHORT */ -#line 3220 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_short); -} -#line 7820 "built/tmp/cppBison.yxx.c" - break; - - case 409: /* simple_int_type: KW_LONG */ -#line 3225 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_long); -} -#line 7829 "built/tmp/cppBison.yxx.c" - break; - - case 410: /* simple_int_type: KW_UNSIGNED */ -#line 3230 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_unsigned); -} -#line 7838 "built/tmp/cppBison.yxx.c" - break; - - case 411: /* simple_int_type: KW_SIGNED */ -#line 3235 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_signed); -} -#line 7847 "built/tmp/cppBison.yxx.c" - break; - - case 412: /* simple_int_type: KW_INT */ -#line 3240 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_int); -} -#line 7855 "built/tmp/cppBison.yxx.c" - break; - - case 413: /* simple_int_type: KW_SHORT simple_int_type */ -#line 3244 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = (yyvsp[0].u.simple_type); - (yyval.u.simple_type)->_flags |= CPPSimpleType::F_short; -} -#line 7864 "built/tmp/cppBison.yxx.c" - break; - - case 414: /* simple_int_type: KW_LONG simple_int_type */ -#line 3249 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = (yyvsp[0].u.simple_type); - if ((yyval.u.simple_type)->_flags & CPPSimpleType::F_long) { - (yyval.u.simple_type)->_flags |= CPPSimpleType::F_longlong; - } else { - (yyval.u.simple_type)->_flags |= CPPSimpleType::F_long; - } -} -#line 7877 "built/tmp/cppBison.yxx.c" - break; - - case 415: /* simple_int_type: KW_UNSIGNED simple_int_type */ -#line 3258 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = (yyvsp[0].u.simple_type); - (yyval.u.simple_type)->_flags |= CPPSimpleType::F_unsigned; -} -#line 7886 "built/tmp/cppBison.yxx.c" - break; - - case 416: /* simple_int_type: KW_SIGNED simple_int_type */ -#line 3263 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = (yyvsp[0].u.simple_type); - (yyval.u.simple_type)->_flags |= CPPSimpleType::F_signed; -} -#line 7895 "built/tmp/cppBison.yxx.c" - break; - - case 417: /* simple_float_type: KW_FLOAT */ -#line 3271 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_float); -} -#line 7903 "built/tmp/cppBison.yxx.c" - break; - - case 418: /* simple_float_type: KW_DOUBLE */ -#line 3275 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_double); -} -#line 7911 "built/tmp/cppBison.yxx.c" - break; - - case 419: /* simple_float_type: KW_LONG KW_DOUBLE */ -#line 3279 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_double, - CPPSimpleType::F_long); -} -#line 7920 "built/tmp/cppBison.yxx.c" - break; - - case 420: /* simple_void_type: KW_VOID */ -#line 3287 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.simple_type) = new CPPSimpleType(CPPSimpleType::T_void); -} -#line 7928 "built/tmp/cppBison.yxx.c" - break; - - case 421: /* $@22: %empty */ -#line 3296 "dtool/src/cppparser/cppBison.yxx" -{ - current_lexer->_resolve_identifiers = false; -} -#line 7936 "built/tmp/cppBison.yxx.c" - break; - - case 422: /* code: $@22 code_block */ -#line 3300 "dtool/src/cppparser/cppBison.yxx" -{ - current_lexer->_resolve_identifiers = true; -} -#line 7944 "built/tmp/cppBison.yxx.c" - break; - - case 539: /* element: KW_WHILE */ -#line 3345 "dtool/src/cppparser/cppBison.yxx" -{ -} -#line 7951 "built/tmp/cppBison.yxx.c" - break; - - case 563: /* optional_const_expr: empty */ -#line 3354 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 7959 "built/tmp/cppBison.yxx.c" - break; - - case 564: /* optional_const_expr: const_expr */ -#line 3358 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 7967 "built/tmp/cppBison.yxx.c" - break; - - case 565: /* optional_const_expr_comma: empty */ -#line 3365 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = nullptr; -} -#line 7975 "built/tmp/cppBison.yxx.c" - break; - - case 566: /* optional_const_expr_comma: const_expr_comma */ -#line 3369 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 7983 "built/tmp/cppBison.yxx.c" - break; - - case 567: /* const_expr_comma: const_expr */ -#line 3376 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 7991 "built/tmp/cppBison.yxx.c" - break; - - case 568: /* const_expr_comma: const_expr_comma ',' const_expr */ -#line 3380 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(',', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 7999 "built/tmp/cppBison.yxx.c" - break; - - case 569: /* no_angle_bracket_const_expr: const_operand */ -#line 3387 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 8007 "built/tmp/cppBison.yxx.c" - break; - - case 570: /* no_angle_bracket_const_expr: '(' full_type ')' no_angle_bracket_const_expr */ -#line 3391 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-2].u.type), (yyvsp[0].u.expr))); -} -#line 8015 "built/tmp/cppBison.yxx.c" - break; - - case 571: /* no_angle_bracket_const_expr: KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3395 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_static_cast)); -} -#line 8023 "built/tmp/cppBison.yxx.c" - break; - - case 572: /* no_angle_bracket_const_expr: KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3399 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_dynamic_cast)); -} -#line 8031 "built/tmp/cppBison.yxx.c" - break; - - case 573: /* no_angle_bracket_const_expr: KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3403 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_const_cast)); -} -#line 8039 "built/tmp/cppBison.yxx.c" - break; - - case 574: /* no_angle_bracket_const_expr: KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3407 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_reinterpret_cast)); -} -#line 8047 "built/tmp/cppBison.yxx.c" - break; - - case 575: /* no_angle_bracket_const_expr: KW_SIZEOF '(' full_type ')' */ -#line 3411 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_func((yyvsp[-1].u.type))); -} -#line 8055 "built/tmp/cppBison.yxx.c" - break; - - case 576: /* no_angle_bracket_const_expr: KW_SIZEOF no_angle_bracket_const_expr */ -#line 3415 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_func((yyvsp[0].u.expr))); -} -#line 8063 "built/tmp/cppBison.yxx.c" - break; - - case 577: /* no_angle_bracket_const_expr: KW_SIZEOF ELLIPSIS '(' name ')' */ -#line 3419 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_ellipsis_func((yyvsp[-1].u.identifier))); -} -#line 8071 "built/tmp/cppBison.yxx.c" - break; - - case 578: /* no_angle_bracket_const_expr: KW_ALIGNOF '(' full_type ')' */ -#line 3423 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::alignof_func((yyvsp[-1].u.type))); -} -#line 8079 "built/tmp/cppBison.yxx.c" - break; - - case 579: /* no_angle_bracket_const_expr: '!' no_angle_bracket_const_expr */ -#line 3427 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_NOT, (yyvsp[0].u.expr)); -} -#line 8087 "built/tmp/cppBison.yxx.c" - break; - - case 580: /* no_angle_bracket_const_expr: '~' no_angle_bracket_const_expr */ -#line 3431 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_NEGATE, (yyvsp[0].u.expr)); -} -#line 8095 "built/tmp/cppBison.yxx.c" - break; - - case 581: /* no_angle_bracket_const_expr: '-' no_angle_bracket_const_expr */ -#line 3435 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_MINUS, (yyvsp[0].u.expr)); -} -#line 8103 "built/tmp/cppBison.yxx.c" - break; - - case 582: /* no_angle_bracket_const_expr: '+' no_angle_bracket_const_expr */ -#line 3439 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_PLUS, (yyvsp[0].u.expr)); -} -#line 8111 "built/tmp/cppBison.yxx.c" - break; - - case 583: /* no_angle_bracket_const_expr: '*' no_angle_bracket_const_expr */ -#line 3443 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_STAR, (yyvsp[0].u.expr)); -} -#line 8119 "built/tmp/cppBison.yxx.c" - break; - - case 584: /* no_angle_bracket_const_expr: '&' no_angle_bracket_const_expr */ -#line 3447 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_REF, (yyvsp[0].u.expr)); -} -#line 8127 "built/tmp/cppBison.yxx.c" - break; - - case 585: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '*' no_angle_bracket_const_expr */ -#line 3451 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('*', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8135 "built/tmp/cppBison.yxx.c" - break; - - case 586: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '/' no_angle_bracket_const_expr */ -#line 3455 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('/', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8143 "built/tmp/cppBison.yxx.c" - break; - - case 587: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '%' no_angle_bracket_const_expr */ -#line 3459 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('%', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8151 "built/tmp/cppBison.yxx.c" - break; - - case 588: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '+' no_angle_bracket_const_expr */ -#line 3463 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('+', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8159 "built/tmp/cppBison.yxx.c" - break; - - case 589: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '-' no_angle_bracket_const_expr */ -#line 3467 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('-', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8167 "built/tmp/cppBison.yxx.c" - break; - - case 590: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '|' no_angle_bracket_const_expr */ -#line 3471 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('|', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8175 "built/tmp/cppBison.yxx.c" - break; - - case 591: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '^' no_angle_bracket_const_expr */ -#line 3475 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('^', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8183 "built/tmp/cppBison.yxx.c" - break; - - case 592: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '&' no_angle_bracket_const_expr */ -#line 3479 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('&', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8191 "built/tmp/cppBison.yxx.c" - break; - - case 593: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr OROR no_angle_bracket_const_expr */ -#line 3483 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(OROR, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8199 "built/tmp/cppBison.yxx.c" - break; - - case 594: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr ANDAND no_angle_bracket_const_expr */ -#line 3487 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(ANDAND, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8207 "built/tmp/cppBison.yxx.c" - break; - - case 595: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr EQCOMPARE no_angle_bracket_const_expr */ -#line 3491 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(EQCOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8215 "built/tmp/cppBison.yxx.c" - break; - - case 596: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr NECOMPARE no_angle_bracket_const_expr */ -#line 3495 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(NECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8223 "built/tmp/cppBison.yxx.c" - break; - - case 597: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr LECOMPARE no_angle_bracket_const_expr */ -#line 3499 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(LECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8231 "built/tmp/cppBison.yxx.c" - break; - - case 598: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr GECOMPARE no_angle_bracket_const_expr */ -#line 3503 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(GECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8239 "built/tmp/cppBison.yxx.c" - break; - - case 599: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr SPACESHIP no_angle_bracket_const_expr */ -#line 3507 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(SPACESHIP, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8247 "built/tmp/cppBison.yxx.c" - break; - - case 600: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr LSHIFT no_angle_bracket_const_expr */ -#line 3511 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(LSHIFT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8255 "built/tmp/cppBison.yxx.c" - break; - - case 601: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr RSHIFT no_angle_bracket_const_expr */ -#line 3515 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(RSHIFT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8263 "built/tmp/cppBison.yxx.c" - break; - - case 602: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '?' no_angle_bracket_const_expr ':' no_angle_bracket_const_expr */ -#line 3519 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('?', (yyvsp[-4].u.expr), (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8271 "built/tmp/cppBison.yxx.c" - break; - - case 603: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '[' const_expr ']' */ -#line 3523 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('[', (yyvsp[-3].u.expr), (yyvsp[-1].u.expr)); -} -#line 8279 "built/tmp/cppBison.yxx.c" - break; - - case 604: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '(' const_expr_comma ')' */ -#line 3527 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('f', (yyvsp[-3].u.expr), (yyvsp[-1].u.expr)); -} -#line 8287 "built/tmp/cppBison.yxx.c" - break; - - case 605: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '(' ')' */ -#line 3531 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('f', (yyvsp[-2].u.expr)); -} -#line 8295 "built/tmp/cppBison.yxx.c" - break; - - case 606: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr '.' name */ -#line 3535 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('.', (yyvsp[-2].u.expr), new CPPExpression((yyvsp[0].u.identifier), current_scope, global_scope, current_lexer)); -} -#line 8303 "built/tmp/cppBison.yxx.c" - break; - - case 607: /* no_angle_bracket_const_expr: no_angle_bracket_const_expr POINTSAT no_angle_bracket_const_expr */ -#line 3539 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(POINTSAT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8311 "built/tmp/cppBison.yxx.c" - break; - - case 608: /* no_angle_bracket_const_expr: '(' const_expr_comma ')' */ -#line 3543 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[-1].u.expr); -} -#line 8319 "built/tmp/cppBison.yxx.c" - break; - - case 609: /* const_expr: const_operand */ -#line 3551 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 8327 "built/tmp/cppBison.yxx.c" - break; - - case 610: /* const_expr: '(' full_type ')' const_expr */ -#line 3555 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-2].u.type), (yyvsp[0].u.expr))); -} -#line 8335 "built/tmp/cppBison.yxx.c" - break; - - case 611: /* const_expr: KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3559 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_static_cast)); -} -#line 8343 "built/tmp/cppBison.yxx.c" - break; - - case 612: /* const_expr: KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3563 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_dynamic_cast)); -} -#line 8351 "built/tmp/cppBison.yxx.c" - break; - - case 613: /* const_expr: KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3567 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_const_cast)); -} -#line 8359 "built/tmp/cppBison.yxx.c" - break; - - case 614: /* const_expr: KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 3571 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_reinterpret_cast)); -} -#line 8367 "built/tmp/cppBison.yxx.c" - break; - - case 615: /* const_expr: TYPENAME_IDENTIFIER '(' optional_const_expr_comma ')' */ -#line 3575 "dtool/src/cppparser/cppBison.yxx" -{ - // A constructor call. - CPPType *type = (yyvsp[-3].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[-3].u.identifier)->get_fully_scoped_name(), (yylsp[-3])); - } - assert(type != nullptr); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8381 "built/tmp/cppBison.yxx.c" - break; - - case 616: /* const_expr: TYPENAME_IDENTIFIER '{' optional_const_expr_comma '}' */ -#line 3585 "dtool/src/cppparser/cppBison.yxx" -{ - // Aggregate initialization. - CPPType *type = (yyvsp[-3].u.identifier)->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + (yyvsp[-3].u.identifier)->get_fully_scoped_name(), (yylsp[-3])); - } - assert(type != nullptr); - (yyval.u.expr) = new CPPExpression(CPPExpression::aggregate_init_op(type, (yyvsp[-1].u.expr))); -} -#line 8395 "built/tmp/cppBison.yxx.c" - break; - - case 617: /* const_expr: KW_INT '(' optional_const_expr_comma ')' */ -#line 3595 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8405 "built/tmp/cppBison.yxx.c" - break; - - case 618: /* const_expr: KW_CHAR '(' optional_const_expr_comma ')' */ -#line 3601 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8415 "built/tmp/cppBison.yxx.c" - break; - - case 619: /* const_expr: KW_WCHAR_T '(' optional_const_expr_comma ')' */ -#line 3607 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8425 "built/tmp/cppBison.yxx.c" - break; - - case 620: /* const_expr: KW_CHAR8_T '(' optional_const_expr_comma ')' */ -#line 3613 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char8_t)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8435 "built/tmp/cppBison.yxx.c" - break; - - case 621: /* const_expr: KW_CHAR16_T '(' optional_const_expr_comma ')' */ -#line 3619 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8445 "built/tmp/cppBison.yxx.c" - break; - - case 622: /* const_expr: KW_CHAR32_T '(' optional_const_expr_comma ')' */ -#line 3625 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8455 "built/tmp/cppBison.yxx.c" - break; - - case 623: /* const_expr: KW_BOOL '(' optional_const_expr_comma ')' */ -#line 3631 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8465 "built/tmp/cppBison.yxx.c" - break; - - case 624: /* const_expr: KW_SHORT '(' optional_const_expr_comma ')' */ -#line 3637 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_short)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8476 "built/tmp/cppBison.yxx.c" - break; - - case 625: /* const_expr: KW_LONG '(' optional_const_expr_comma ')' */ -#line 3644 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_long)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8487 "built/tmp/cppBison.yxx.c" - break; - - case 626: /* const_expr: KW_UNSIGNED '(' optional_const_expr_comma ')' */ -#line 3651 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_unsigned)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8498 "built/tmp/cppBison.yxx.c" - break; - - case 627: /* const_expr: KW_SIGNED '(' optional_const_expr_comma ')' */ -#line 3658 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_signed)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8509 "built/tmp/cppBison.yxx.c" - break; - - case 628: /* const_expr: KW_FLOAT '(' optional_const_expr_comma ')' */ -#line 3665 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_float)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8519 "built/tmp/cppBison.yxx.c" - break; - - case 629: /* const_expr: KW_DOUBLE '(' optional_const_expr_comma ')' */ -#line 3671 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double)); - (yyval.u.expr) = new CPPExpression(CPPExpression::construct_op(type, (yyvsp[-1].u.expr))); -} -#line 8529 "built/tmp/cppBison.yxx.c" - break; - - case 630: /* const_expr: KW_SIZEOF '(' full_type ')' */ -#line 3677 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_func((yyvsp[-1].u.type))); -} -#line 8537 "built/tmp/cppBison.yxx.c" - break; - - case 631: /* const_expr: KW_SIZEOF const_expr */ -#line 3681 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_func((yyvsp[0].u.expr))); -} -#line 8545 "built/tmp/cppBison.yxx.c" - break; - - case 632: /* const_expr: KW_SIZEOF ELLIPSIS '(' name ')' */ -#line 3685 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_ellipsis_func((yyvsp[-1].u.identifier))); -} -#line 8553 "built/tmp/cppBison.yxx.c" - break; - - case 633: /* const_expr: KW_ALIGNOF '(' full_type ')' */ -#line 3689 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::alignof_func((yyvsp[-1].u.type))); -} -#line 8561 "built/tmp/cppBison.yxx.c" - break; - - case 634: /* const_expr: KW_NEW predefined_type */ -#line 3693 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::new_op((yyvsp[0].u.type))); -} -#line 8569 "built/tmp/cppBison.yxx.c" - break; - - case 635: /* const_expr: KW_NEW predefined_type '(' optional_const_expr_comma ')' */ -#line 3697 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::new_op((yyvsp[-3].u.type), (yyvsp[-1].u.expr))); -} -#line 8577 "built/tmp/cppBison.yxx.c" - break; - - case 636: /* const_expr: KW_TYPEID '(' full_type ')' */ -#line 3701 "dtool/src/cppparser/cppBison.yxx" -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", (yylsp[-3])); - } - (yyval.u.expr) = new CPPExpression(CPPExpression::typeid_op((yyvsp[-1].u.type), std_type_info)); -} -#line 8592 "built/tmp/cppBison.yxx.c" - break; - - case 637: /* const_expr: KW_TYPEID '(' const_expr ')' */ -#line 3712 "dtool/src/cppparser/cppBison.yxx" -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", (yylsp[-3])); - } - (yyval.u.expr) = new CPPExpression(CPPExpression::typeid_op((yyvsp[-1].u.expr), std_type_info)); -} -#line 8607 "built/tmp/cppBison.yxx.c" - break; - - case 638: /* const_expr: '!' const_expr */ -#line 3723 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_NOT, (yyvsp[0].u.expr)); -} -#line 8615 "built/tmp/cppBison.yxx.c" - break; - - case 639: /* const_expr: '~' const_expr */ -#line 3727 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_NEGATE, (yyvsp[0].u.expr)); -} -#line 8623 "built/tmp/cppBison.yxx.c" - break; - - case 640: /* const_expr: '-' const_expr */ -#line 3731 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_MINUS, (yyvsp[0].u.expr)); -} -#line 8631 "built/tmp/cppBison.yxx.c" - break; - - case 641: /* const_expr: '+' const_expr */ -#line 3735 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_PLUS, (yyvsp[0].u.expr)); -} -#line 8639 "built/tmp/cppBison.yxx.c" - break; - - case 642: /* const_expr: '*' const_expr */ -#line 3739 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_STAR, (yyvsp[0].u.expr)); -} -#line 8647 "built/tmp/cppBison.yxx.c" - break; - - case 643: /* const_expr: '&' const_expr */ -#line 3743 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_REF, (yyvsp[0].u.expr)); -} -#line 8655 "built/tmp/cppBison.yxx.c" - break; - - case 644: /* const_expr: const_expr '*' const_expr */ -#line 3747 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('*', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8663 "built/tmp/cppBison.yxx.c" - break; - - case 645: /* const_expr: const_expr '/' const_expr */ -#line 3751 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('/', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8671 "built/tmp/cppBison.yxx.c" - break; - - case 646: /* const_expr: const_expr '%' const_expr */ -#line 3755 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('%', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8679 "built/tmp/cppBison.yxx.c" - break; - - case 647: /* const_expr: const_expr '+' const_expr */ -#line 3759 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('+', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8687 "built/tmp/cppBison.yxx.c" - break; - - case 648: /* const_expr: const_expr '-' const_expr */ -#line 3763 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('-', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8695 "built/tmp/cppBison.yxx.c" - break; - - case 649: /* const_expr: const_expr '|' const_expr */ -#line 3767 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('|', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8703 "built/tmp/cppBison.yxx.c" - break; - - case 650: /* const_expr: const_expr '^' const_expr */ -#line 3771 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('^', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8711 "built/tmp/cppBison.yxx.c" - break; - - case 651: /* const_expr: const_expr '&' const_expr */ -#line 3775 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('&', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8719 "built/tmp/cppBison.yxx.c" - break; - - case 652: /* const_expr: const_expr OROR const_expr */ -#line 3779 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(OROR, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8727 "built/tmp/cppBison.yxx.c" - break; - - case 653: /* const_expr: const_expr ANDAND const_expr */ -#line 3783 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(ANDAND, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8735 "built/tmp/cppBison.yxx.c" - break; - - case 654: /* const_expr: const_expr EQCOMPARE const_expr */ -#line 3787 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(EQCOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8743 "built/tmp/cppBison.yxx.c" - break; - - case 655: /* const_expr: const_expr NECOMPARE const_expr */ -#line 3791 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(NECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8751 "built/tmp/cppBison.yxx.c" - break; - - case 656: /* const_expr: const_expr LECOMPARE const_expr */ -#line 3795 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(LECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8759 "built/tmp/cppBison.yxx.c" - break; - - case 657: /* const_expr: const_expr GECOMPARE const_expr */ -#line 3799 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(GECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8767 "built/tmp/cppBison.yxx.c" - break; - - case 658: /* const_expr: const_expr SPACESHIP const_expr */ -#line 3803 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(SPACESHIP, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8775 "built/tmp/cppBison.yxx.c" - break; - - case 659: /* const_expr: const_expr '<' const_expr */ -#line 3807 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('<', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8783 "built/tmp/cppBison.yxx.c" - break; - - case 660: /* const_expr: const_expr '>' const_expr */ -#line 3811 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('>', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8791 "built/tmp/cppBison.yxx.c" - break; - - case 661: /* const_expr: const_expr LSHIFT const_expr */ -#line 3815 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(LSHIFT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8799 "built/tmp/cppBison.yxx.c" - break; - - case 662: /* const_expr: const_expr RSHIFT const_expr */ -#line 3819 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(RSHIFT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8807 "built/tmp/cppBison.yxx.c" - break; - - case 663: /* const_expr: const_expr '?' const_expr ':' const_expr */ -#line 3823 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('?', (yyvsp[-4].u.expr), (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8815 "built/tmp/cppBison.yxx.c" - break; - - case 664: /* const_expr: const_expr '[' const_expr ']' */ -#line 3827 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('[', (yyvsp[-3].u.expr), (yyvsp[-1].u.expr)); -} -#line 8823 "built/tmp/cppBison.yxx.c" - break; - - case 665: /* const_expr: const_expr '(' const_expr_comma ')' */ -#line 3831 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('f', (yyvsp[-3].u.expr), (yyvsp[-1].u.expr)); -} -#line 8831 "built/tmp/cppBison.yxx.c" - break; - - case 666: /* const_expr: const_expr '(' ')' */ -#line 3835 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('f', (yyvsp[-2].u.expr)); -} -#line 8839 "built/tmp/cppBison.yxx.c" - break; - - case 667: /* const_expr: KW_NOEXCEPT_LPAREN const_expr ')' */ -#line 3839 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(KW_NOEXCEPT, (yyvsp[-1].u.expr)); -} -#line 8847 "built/tmp/cppBison.yxx.c" - break; - - case 668: /* const_expr: const_expr '.' name */ -#line 3843 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('.', (yyvsp[-2].u.expr), new CPPExpression((yyvsp[0].u.identifier), current_scope, global_scope, current_lexer)); -} -#line 8855 "built/tmp/cppBison.yxx.c" - break; - - case 669: /* const_expr: const_expr POINTSAT const_expr */ -#line 3847 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(POINTSAT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 8863 "built/tmp/cppBison.yxx.c" - break; - - case 670: /* const_expr: '(' const_expr_comma ')' */ -#line 3851 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[-1].u.expr); -} -#line 8871 "built/tmp/cppBison.yxx.c" - break; - - case 671: /* const_operand: INTEGER */ -#line 3858 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.integer)); -} -#line 8879 "built/tmp/cppBison.yxx.c" - break; - - case 672: /* const_operand: KW_TRUE */ -#line 3862 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(true); -} -#line 8887 "built/tmp/cppBison.yxx.c" - break; - - case 673: /* const_operand: KW_FALSE */ -#line 3866 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(false); -} -#line 8895 "built/tmp/cppBison.yxx.c" - break; - - case 674: /* const_operand: CHAR_TOK */ -#line 3870 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.integer)); -} -#line 8903 "built/tmp/cppBison.yxx.c" - break; - - case 675: /* const_operand: REAL */ -#line 3874 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.real)); -} -#line 8911 "built/tmp/cppBison.yxx.c" - break; - - case 676: /* const_operand: string_literal */ -#line 3878 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 8919 "built/tmp/cppBison.yxx.c" - break; - - case 677: /* const_operand: CUSTOM_LITERAL */ -#line 3882 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 8927 "built/tmp/cppBison.yxx.c" - break; - - case 678: /* const_operand: IDENTIFIER */ -#line 3886 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.identifier), current_scope, global_scope, current_lexer); -} -#line 8935 "built/tmp/cppBison.yxx.c" - break; - - case 679: /* const_operand: KW_FINAL */ -#line 3890 "dtool/src/cppparser/cppBison.yxx" -{ - // A variable named "final". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("final", (yylsp[0])); - (yyval.u.expr) = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} -#line 8945 "built/tmp/cppBison.yxx.c" - break; - - case 680: /* const_operand: KW_OVERRIDE */ -#line 3896 "dtool/src/cppparser/cppBison.yxx" -{ - // A variable named "override". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("override", (yylsp[0])); - (yyval.u.expr) = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} -#line 8955 "built/tmp/cppBison.yxx.c" - break; - - case 681: /* const_operand: KW_NULLPTR */ -#line 3902 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::get_nullptr()); -} -#line 8963 "built/tmp/cppBison.yxx.c" - break; - - case 682: /* const_operand: '[' capture_list ']' function_post optional_attributes maybe_trailing_return_type '{' code '}' */ -#line 3906 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[-7].u.closure_type)->_flags = (yyvsp[-5].u.integer); - (yyvsp[-7].u.closure_type)->_attributes = (yyvsp[-4].attr_list); - (yyvsp[-7].u.closure_type)->_return_type = (yyvsp[-3].u.type); - (yyval.u.expr) = new CPPExpression(CPPExpression::lambda((yyvsp[-7].u.closure_type))); -} -#line 8974 "built/tmp/cppBison.yxx.c" - break; - - case 683: /* const_operand: '[' capture_list ']' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type '{' code '}' */ -#line 3913 "dtool/src/cppparser/cppBison.yxx" -{ - (yyvsp[-10].u.closure_type)->_parameters = (yyvsp[-7].u.param_list); - (yyvsp[-10].u.closure_type)->_flags = (yyvsp[-5].u.integer); - (yyvsp[-10].u.closure_type)->_attributes = (yyvsp[-4].attr_list); - (yyvsp[-10].u.closure_type)->_return_type = (yyvsp[-3].u.type); - (yyval.u.expr) = new CPPExpression(CPPExpression::lambda((yyvsp[-10].u.closure_type))); -} -#line 8986 "built/tmp/cppBison.yxx.c" - break; - - case 684: /* const_operand: KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')' */ -#line 3921 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_HAS_VIRTUAL_DESTRUCTOR, (yyvsp[-1].u.type))); -} -#line 8994 "built/tmp/cppBison.yxx.c" - break; - - case 685: /* const_operand: KW_IS_ABSTRACT '(' full_type ')' */ -#line 3925 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_ABSTRACT, (yyvsp[-1].u.type))); -} -#line 9002 "built/tmp/cppBison.yxx.c" - break; - - case 686: /* const_operand: KW_IS_BASE_OF '(' full_type ',' full_type ')' */ -#line 3929 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, (yyvsp[-3].u.type), (yyvsp[-1].u.type))); -} -#line 9010 "built/tmp/cppBison.yxx.c" - break; - - case 687: /* const_operand: KW_IS_CLASS '(' full_type ')' */ -#line 3933 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, (yyvsp[-1].u.type))); -} -#line 9018 "built/tmp/cppBison.yxx.c" - break; - - case 688: /* const_operand: KW_IS_CONSTRUCTIBLE '(' full_type ')' */ -#line 3937 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, (yyvsp[-1].u.type))); -} -#line 9026 "built/tmp/cppBison.yxx.c" - break; - - case 689: /* const_operand: KW_IS_CONSTRUCTIBLE '(' full_type ',' full_type ')' */ -#line 3941 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, (yyvsp[-3].u.type), (yyvsp[-1].u.type))); -} -#line 9034 "built/tmp/cppBison.yxx.c" - break; - - case 690: /* const_operand: KW_IS_CONVERTIBLE_TO '(' full_type ',' full_type ')' */ -#line 3945 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_CONVERTIBLE_TO, (yyvsp[-3].u.type), (yyvsp[-1].u.type))); -} -#line 9042 "built/tmp/cppBison.yxx.c" - break; - - case 691: /* const_operand: KW_IS_DESTRUCTIBLE '(' full_type ')' */ -#line 3949 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_DESTRUCTIBLE, (yyvsp[-1].u.type))); -} -#line 9050 "built/tmp/cppBison.yxx.c" - break; - - case 692: /* const_operand: KW_IS_EMPTY '(' full_type ')' */ -#line 3953 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_EMPTY, (yyvsp[-1].u.type))); -} -#line 9058 "built/tmp/cppBison.yxx.c" - break; - - case 693: /* const_operand: KW_IS_ENUM '(' full_type ')' */ -#line 3957 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_ENUM, (yyvsp[-1].u.type))); -} -#line 9066 "built/tmp/cppBison.yxx.c" - break; - - case 694: /* const_operand: KW_IS_FINAL '(' full_type ')' */ -#line 3961 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_FINAL, (yyvsp[-1].u.type))); -} -#line 9074 "built/tmp/cppBison.yxx.c" - break; - - case 695: /* const_operand: KW_IS_FUNDAMENTAL '(' full_type ')' */ -#line 3965 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_FUNDAMENTAL, (yyvsp[-1].u.type))); -} -#line 9082 "built/tmp/cppBison.yxx.c" - break; - - case 696: /* const_operand: KW_IS_POD '(' full_type ')' */ -#line 3969 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_POD, (yyvsp[-1].u.type))); -} -#line 9090 "built/tmp/cppBison.yxx.c" - break; - - case 697: /* const_operand: KW_IS_POLYMORPHIC '(' full_type ')' */ -#line 3973 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_POLYMORPHIC, (yyvsp[-1].u.type))); -} -#line 9098 "built/tmp/cppBison.yxx.c" - break; - - case 698: /* const_operand: KW_IS_STANDARD_LAYOUT '(' full_type ')' */ -#line 3977 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_STANDARD_LAYOUT, (yyvsp[-1].u.type))); -} -#line 9106 "built/tmp/cppBison.yxx.c" - break; - - case 699: /* const_operand: KW_IS_TRIVIAL '(' full_type ')' */ -#line 3981 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_TRIVIAL, (yyvsp[-1].u.type))); -} -#line 9114 "built/tmp/cppBison.yxx.c" - break; - - case 700: /* const_operand: KW_IS_TRIVIALLY_COPYABLE '(' full_type ')' */ -#line 3985 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_TRIVIALLY_COPYABLE, (yyvsp[-1].u.type))); -} -#line 9122 "built/tmp/cppBison.yxx.c" - break; - - case 701: /* const_operand: KW_IS_UNION '(' full_type ')' */ -#line 3989 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::type_trait(KW_IS_UNION, (yyvsp[-1].u.type))); -} -#line 9130 "built/tmp/cppBison.yxx.c" - break; - - case 702: /* formal_const_expr: formal_const_operand */ -#line 4003 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 9138 "built/tmp/cppBison.yxx.c" - break; - - case 703: /* formal_const_expr: '(' full_type ')' const_expr */ -#line 4007 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-2].u.type), (yyvsp[0].u.expr))); -} -#line 9146 "built/tmp/cppBison.yxx.c" - break; - - case 704: /* formal_const_expr: KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 4011 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_static_cast)); -} -#line 9154 "built/tmp/cppBison.yxx.c" - break; - - case 705: /* formal_const_expr: KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 4015 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_dynamic_cast)); -} -#line 9162 "built/tmp/cppBison.yxx.c" - break; - - case 706: /* formal_const_expr: KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 4019 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_const_cast)); -} -#line 9170 "built/tmp/cppBison.yxx.c" - break; - - case 707: /* formal_const_expr: KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' */ -#line 4023 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::typecast_op((yyvsp[-4].u.type), (yyvsp[-1].u.expr), CPPExpression::T_reinterpret_cast)); -} -#line 9178 "built/tmp/cppBison.yxx.c" - break; - - case 708: /* formal_const_expr: KW_SIZEOF '(' full_type ')' */ -#line 4027 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_func((yyvsp[-1].u.type))); -} -#line 9186 "built/tmp/cppBison.yxx.c" - break; - - case 709: /* formal_const_expr: KW_SIZEOF formal_const_expr */ -#line 4031 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_func((yyvsp[0].u.expr))); -} -#line 9194 "built/tmp/cppBison.yxx.c" - break; - - case 710: /* formal_const_expr: KW_SIZEOF ELLIPSIS '(' name ')' */ -#line 4035 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::sizeof_ellipsis_func((yyvsp[-1].u.identifier))); -} -#line 9202 "built/tmp/cppBison.yxx.c" - break; - - case 711: /* formal_const_expr: KW_ALIGNOF '(' full_type ')' */ -#line 4039 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::alignof_func((yyvsp[-1].u.type))); -} -#line 9210 "built/tmp/cppBison.yxx.c" - break; - - case 712: /* formal_const_expr: KW_NEW predefined_type */ -#line 4043 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::new_op((yyvsp[0].u.type))); -} -#line 9218 "built/tmp/cppBison.yxx.c" - break; - - case 713: /* formal_const_expr: KW_NEW predefined_type '(' optional_const_expr_comma ')' */ -#line 4047 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::new_op((yyvsp[-3].u.type), (yyvsp[-1].u.expr))); -} -#line 9226 "built/tmp/cppBison.yxx.c" - break; - - case 714: /* formal_const_expr: KW_TYPEID '(' full_type ')' */ -#line 4051 "dtool/src/cppparser/cppBison.yxx" -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", (yylsp[-3])); - } - (yyval.u.expr) = new CPPExpression(CPPExpression::typeid_op((yyvsp[-1].u.type), std_type_info)); -} -#line 9241 "built/tmp/cppBison.yxx.c" - break; - - case 715: /* formal_const_expr: KW_TYPEID '(' const_expr ')' */ -#line 4062 "dtool/src/cppparser/cppBison.yxx" -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", (yylsp[-3])); - } - (yyval.u.expr) = new CPPExpression(CPPExpression::typeid_op((yyvsp[-1].u.expr), std_type_info)); -} -#line 9256 "built/tmp/cppBison.yxx.c" - break; - - case 716: /* formal_const_expr: '!' const_expr */ -#line 4073 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_NOT, (yyvsp[0].u.expr)); -} -#line 9264 "built/tmp/cppBison.yxx.c" - break; - - case 717: /* formal_const_expr: '~' const_expr */ -#line 4077 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_NEGATE, (yyvsp[0].u.expr)); -} -#line 9272 "built/tmp/cppBison.yxx.c" - break; - - case 718: /* formal_const_expr: '-' const_expr */ -#line 4081 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_MINUS, (yyvsp[0].u.expr)); -} -#line 9280 "built/tmp/cppBison.yxx.c" - break; - - case 719: /* formal_const_expr: '+' const_expr */ -#line 4085 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_PLUS, (yyvsp[0].u.expr)); -} -#line 9288 "built/tmp/cppBison.yxx.c" - break; - - case 720: /* formal_const_expr: '&' const_expr */ -#line 4089 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(UNARY_REF, (yyvsp[0].u.expr)); -} -#line 9296 "built/tmp/cppBison.yxx.c" - break; - - case 721: /* formal_const_expr: formal_const_expr '*' const_expr */ -#line 4093 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('*', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9304 "built/tmp/cppBison.yxx.c" - break; - - case 722: /* formal_const_expr: formal_const_expr '/' const_expr */ -#line 4097 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('/', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9312 "built/tmp/cppBison.yxx.c" - break; - - case 723: /* formal_const_expr: formal_const_expr '%' const_expr */ -#line 4101 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('%', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9320 "built/tmp/cppBison.yxx.c" - break; - - case 724: /* formal_const_expr: formal_const_expr '+' const_expr */ -#line 4105 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('+', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9328 "built/tmp/cppBison.yxx.c" - break; - - case 725: /* formal_const_expr: formal_const_expr '-' const_expr */ -#line 4109 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('-', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9336 "built/tmp/cppBison.yxx.c" - break; - - case 726: /* formal_const_expr: formal_const_expr '|' const_expr */ -#line 4113 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('|', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9344 "built/tmp/cppBison.yxx.c" - break; - - case 727: /* formal_const_expr: formal_const_expr '^' const_expr */ -#line 4117 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('^', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9352 "built/tmp/cppBison.yxx.c" - break; - - case 728: /* formal_const_expr: formal_const_expr '&' const_expr */ -#line 4121 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('&', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9360 "built/tmp/cppBison.yxx.c" - break; - - case 729: /* formal_const_expr: formal_const_expr OROR const_expr */ -#line 4125 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(OROR, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9368 "built/tmp/cppBison.yxx.c" - break; - - case 730: /* formal_const_expr: formal_const_expr ANDAND const_expr */ -#line 4129 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(ANDAND, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9376 "built/tmp/cppBison.yxx.c" - break; - - case 731: /* formal_const_expr: formal_const_expr EQCOMPARE const_expr */ -#line 4133 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(EQCOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9384 "built/tmp/cppBison.yxx.c" - break; - - case 732: /* formal_const_expr: formal_const_expr NECOMPARE const_expr */ -#line 4137 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(NECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9392 "built/tmp/cppBison.yxx.c" - break; - - case 733: /* formal_const_expr: formal_const_expr LECOMPARE const_expr */ -#line 4141 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(LECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9400 "built/tmp/cppBison.yxx.c" - break; - - case 734: /* formal_const_expr: formal_const_expr GECOMPARE const_expr */ -#line 4145 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(GECOMPARE, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9408 "built/tmp/cppBison.yxx.c" - break; - - case 735: /* formal_const_expr: formal_const_expr SPACESHIP const_expr */ -#line 4149 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(SPACESHIP, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9416 "built/tmp/cppBison.yxx.c" - break; - - case 736: /* formal_const_expr: formal_const_expr '<' const_expr */ -#line 4153 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('<', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9424 "built/tmp/cppBison.yxx.c" - break; - - case 737: /* formal_const_expr: formal_const_expr '>' const_expr */ -#line 4157 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('>', (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9432 "built/tmp/cppBison.yxx.c" - break; - - case 738: /* formal_const_expr: formal_const_expr LSHIFT const_expr */ -#line 4161 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(LSHIFT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9440 "built/tmp/cppBison.yxx.c" - break; - - case 739: /* formal_const_expr: formal_const_expr RSHIFT const_expr */ -#line 4165 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(RSHIFT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9448 "built/tmp/cppBison.yxx.c" - break; - - case 740: /* formal_const_expr: formal_const_expr '?' const_expr ':' const_expr */ -#line 4169 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('?', (yyvsp[-4].u.expr), (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9456 "built/tmp/cppBison.yxx.c" - break; - - case 741: /* formal_const_expr: formal_const_expr '[' const_expr ']' */ -#line 4173 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('[', (yyvsp[-3].u.expr), (yyvsp[-1].u.expr)); -} -#line 9464 "built/tmp/cppBison.yxx.c" - break; - - case 742: /* formal_const_expr: formal_const_expr '(' const_expr_comma ')' */ -#line 4177 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('f', (yyvsp[-3].u.expr), (yyvsp[-1].u.expr)); -} -#line 9472 "built/tmp/cppBison.yxx.c" - break; - - case 743: /* formal_const_expr: formal_const_expr '(' ')' */ -#line 4181 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('f', (yyvsp[-2].u.expr)); -} -#line 9480 "built/tmp/cppBison.yxx.c" - break; - - case 744: /* formal_const_expr: formal_const_expr '.' name */ -#line 4185 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression('.', (yyvsp[-2].u.expr), new CPPExpression((yyvsp[0].u.identifier), current_scope, global_scope, current_lexer)); -} -#line 9488 "built/tmp/cppBison.yxx.c" - break; - - case 745: /* formal_const_expr: formal_const_expr POINTSAT const_expr */ -#line 4189 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(POINTSAT, (yyvsp[-2].u.expr), (yyvsp[0].u.expr)); -} -#line 9496 "built/tmp/cppBison.yxx.c" - break; - - case 746: /* formal_const_expr: '(' const_expr_comma ')' */ -#line 4193 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[-1].u.expr); -} -#line 9504 "built/tmp/cppBison.yxx.c" - break; - - case 747: /* formal_const_operand: INTEGER */ -#line 4200 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.integer)); -} -#line 9512 "built/tmp/cppBison.yxx.c" - break; - - case 748: /* formal_const_operand: KW_TRUE */ -#line 4204 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(true); -} -#line 9520 "built/tmp/cppBison.yxx.c" - break; - - case 749: /* formal_const_operand: KW_FALSE */ -#line 4208 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(false); -} -#line 9528 "built/tmp/cppBison.yxx.c" - break; - - case 750: /* formal_const_operand: CHAR_TOK */ -#line 4212 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.integer)); -} -#line 9536 "built/tmp/cppBison.yxx.c" - break; - - case 751: /* formal_const_operand: REAL */ -#line 4216 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.real)); -} -#line 9544 "built/tmp/cppBison.yxx.c" - break; - - case 752: /* formal_const_operand: string_literal */ -#line 4220 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 9552 "built/tmp/cppBison.yxx.c" - break; - - case 753: /* formal_const_operand: CUSTOM_LITERAL */ -#line 4224 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 9560 "built/tmp/cppBison.yxx.c" - break; - - case 754: /* formal_const_operand: IDENTIFIER */ -#line 4228 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].u.identifier), current_scope, global_scope, current_lexer); -} -#line 9568 "built/tmp/cppBison.yxx.c" - break; - - case 755: /* formal_const_operand: KW_FINAL */ -#line 4232 "dtool/src/cppparser/cppBison.yxx" -{ - // A variable named "final". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("final", (yylsp[0])); - (yyval.u.expr) = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} -#line 9578 "built/tmp/cppBison.yxx.c" - break; - - case 756: /* formal_const_operand: KW_OVERRIDE */ -#line 4238 "dtool/src/cppparser/cppBison.yxx" -{ - // A variable named "override". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("override", (yylsp[0])); - (yyval.u.expr) = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} -#line 9588 "built/tmp/cppBison.yxx.c" - break; - - case 757: /* formal_const_operand: KW_NULLPTR */ -#line 4244 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression(CPPExpression::get_nullptr()); -} -#line 9596 "built/tmp/cppBison.yxx.c" - break; - - case 758: /* capture_list: empty */ -#line 4252 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.closure_type) = new CPPClosureType(); -} -#line 9604 "built/tmp/cppBison.yxx.c" - break; - - case 759: /* capture_list: '=' */ -#line 4256 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.closure_type) = new CPPClosureType(CPPClosureType::CT_by_value); -} -#line 9612 "built/tmp/cppBison.yxx.c" - break; - - case 760: /* capture_list: '&' */ -#line 4260 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.closure_type) = new CPPClosureType(CPPClosureType::CT_by_reference); -} -#line 9620 "built/tmp/cppBison.yxx.c" - break; - - case 761: /* capture_list: capture maybe_initialize */ -#line 4264 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.closure_type) = new CPPClosureType(); - (yyvsp[-1].u.capture)->_initializer = (yyvsp[0].u.expr); - (yyval.u.closure_type)->_captures.push_back(*(yyvsp[-1].u.capture)); - delete (yyvsp[-1].u.capture); -} -#line 9631 "built/tmp/cppBison.yxx.c" - break; - - case 762: /* capture_list: capture_list ',' capture maybe_initialize */ -#line 4271 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.closure_type) = (yyvsp[-3].u.closure_type); - (yyvsp[-1].u.capture)->_initializer = (yyvsp[0].u.expr); - (yyval.u.closure_type)->_captures.push_back(*(yyvsp[-1].u.capture)); - delete (yyvsp[-1].u.capture); -} -#line 9642 "built/tmp/cppBison.yxx.c" - break; - - case 763: /* capture: '&' name */ -#line 4281 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.capture) = new CPPClosureType::Capture; - (yyval.u.capture)->_name = (yyvsp[0].u.identifier)->get_simple_name(); - (yyval.u.capture)->_type = CPPClosureType::CT_by_reference; -} -#line 9652 "built/tmp/cppBison.yxx.c" - break; - - case 764: /* capture: '&' name ELLIPSIS */ -#line 4287 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.capture) = new CPPClosureType::Capture; - (yyval.u.capture)->_name = (yyvsp[-1].u.identifier)->get_simple_name(); - (yyval.u.capture)->_type = CPPClosureType::CT_by_reference; -} -#line 9662 "built/tmp/cppBison.yxx.c" - break; - - case 765: /* capture: name */ -#line 4293 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.capture) = new CPPClosureType::Capture; - (yyval.u.capture)->_name = (yyvsp[0].u.identifier)->get_simple_name(); - if ((yyval.u.capture)->_name == "this") { - (yyval.u.capture)->_type = CPPClosureType::CT_by_reference; - } else { - (yyval.u.capture)->_type = CPPClosureType::CT_by_value; - } -} -#line 9676 "built/tmp/cppBison.yxx.c" - break; - - case 766: /* capture: '*' name */ -#line 4303 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.capture) = new CPPClosureType::Capture; - (yyval.u.capture)->_name = (yyvsp[0].u.identifier)->get_simple_name(); - (yyval.u.capture)->_type = CPPClosureType::CT_by_value; - if ((yyval.u.capture)->_name != "this") { - yywarning("only capture name 'this' may be preceded by an asterisk", (yylsp[0])); - } -} -#line 9689 "built/tmp/cppBison.yxx.c" - break; - - case 767: /* class_derivation_name: name */ -#line 4315 "dtool/src/cppparser/cppBison.yxx" -{ - CPPType *type = (yyvsp[0].u.identifier)->find_type(current_scope, global_scope, true); - if (type == nullptr) { - type = CPPType::new_type(new CPPTBDType((yyvsp[0].u.identifier))); - } - (yyval.u.type) = type; -} -#line 9701 "built/tmp/cppBison.yxx.c" - break; - - case 768: /* class_derivation_name: KW_TYPENAME name */ -#line 4323 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.type) = CPPType::new_type(new CPPTBDType((yyvsp[0].u.identifier))); -} -#line 9709 "built/tmp/cppBison.yxx.c" - break; - - case 769: /* class_derivation_name: name ELLIPSIS */ -#line 4327 "dtool/src/cppparser/cppBison.yxx" -{ - CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter((yyvsp[-1].u.identifier)); - ctp->_packed = true; - (yyval.u.type) = CPPType::new_type(ctp); -} -#line 9719 "built/tmp/cppBison.yxx.c" - break; - - case 770: /* name: IDENTIFIER */ -#line 4357 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = (yyvsp[0].u.identifier); -} -#line 9727 "built/tmp/cppBison.yxx.c" - break; - - case 771: /* name: TYPENAME_IDENTIFIER */ -#line 4361 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = (yyvsp[0].u.identifier); -} -#line 9735 "built/tmp/cppBison.yxx.c" - break; - - case 772: /* name: TYPEPACK_IDENTIFIER */ -#line 4365 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = (yyvsp[0].u.identifier); -} -#line 9743 "built/tmp/cppBison.yxx.c" - break; - - case 773: /* name: KW_FINAL */ -#line 4369 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("final", (yylsp[0])); -} -#line 9751 "built/tmp/cppBison.yxx.c" - break; - - case 774: /* name: KW_OVERRIDE */ -#line 4373 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("override", (yylsp[0])); -} -#line 9759 "built/tmp/cppBison.yxx.c" - break; - - case 775: /* name: KW_SIGNED */ -#line 4377 "dtool/src/cppparser/cppBison.yxx" -{ - // This is not a keyword in Python, so it is useful to be able to use this - // in MAKE_PROPERTY definitions, etc. - (yyval.u.identifier) = new CPPIdentifier("signed", (yylsp[0])); -} -#line 9769 "built/tmp/cppBison.yxx.c" - break; - - case 776: /* name: KW_FLOAT */ -#line 4383 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("float", (yylsp[0])); -} -#line 9777 "built/tmp/cppBison.yxx.c" - break; - - case 777: /* name: KW_PUBLIC */ -#line 4387 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("public", (yylsp[0])); -} -#line 9785 "built/tmp/cppBison.yxx.c" - break; - - case 778: /* name: KW_PRIVATE */ -#line 4391 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("private", (yylsp[0])); -} -#line 9793 "built/tmp/cppBison.yxx.c" - break; - - case 779: /* name: KW_STATIC */ -#line 4395 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("static", (yylsp[0])); -} -#line 9801 "built/tmp/cppBison.yxx.c" - break; - - case 780: /* name: KW_DEFAULT */ -#line 4399 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("default", (yylsp[0])); -} -#line 9809 "built/tmp/cppBison.yxx.c" - break; - - case 781: /* name_no_final: IDENTIFIER */ -#line 4410 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = (yyvsp[0].u.identifier); -} -#line 9817 "built/tmp/cppBison.yxx.c" - break; - - case 782: /* name_no_final: TYPENAME_IDENTIFIER */ -#line 4414 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = (yyvsp[0].u.identifier); -} -#line 9825 "built/tmp/cppBison.yxx.c" - break; - - case 783: /* name_no_final: TYPEPACK_IDENTIFIER */ -#line 4418 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = (yyvsp[0].u.identifier); -} -#line 9833 "built/tmp/cppBison.yxx.c" - break; - - case 784: /* name_no_final: KW_OVERRIDE */ -#line 4422 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.identifier) = new CPPIdentifier("override", (yylsp[0])); -} -#line 9841 "built/tmp/cppBison.yxx.c" - break; - - case 785: /* string_literal: SIMPLE_STRING */ -#line 4430 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = new CPPExpression((yyvsp[0].str)); -} -#line 9849 "built/tmp/cppBison.yxx.c" - break; - - case 786: /* string_literal: STRING_LITERAL */ -#line 4434 "dtool/src/cppparser/cppBison.yxx" -{ - (yyval.u.expr) = (yyvsp[0].u.expr); -} -#line 9857 "built/tmp/cppBison.yxx.c" - break; - - case 787: /* string_literal: string_literal SIMPLE_STRING */ -#line 4438 "dtool/src/cppparser/cppBison.yxx" -{ - // The right string takes on the literal type of the left. - (yyval.u.expr) = (yyvsp[-1].u.expr); - (yyval.u.expr)->_str += (yyvsp[0].str); -} -#line 9867 "built/tmp/cppBison.yxx.c" - break; - - case 788: /* string_literal: string_literal STRING_LITERAL */ -#line 4444 "dtool/src/cppparser/cppBison.yxx" -{ - // We have to check that the two literal types match up. - (yyval.u.expr) = (yyvsp[-1].u.expr); - if ((yyvsp[0].u.expr)->_type != CPPExpression::T_string && (yyvsp[0].u.expr)->_type != (yyvsp[-1].u.expr)->_type) { - yywarning("cannot concatenate two string literals of different types", (yyloc)); - } - (yyval.u.expr)->_str += (yyvsp[0].u.expr)->_str; -} -#line 9880 "built/tmp/cppBison.yxx.c" - break; - - -#line 9884 "built/tmp/cppBison.yxx.c" - - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - - *++yyvsp = yyval; - *++yylsp = yyloc; - - /* Now 'shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - { - const int yylhs = yyr1[yyn] - YYNTOKENS; - const int yyi = yypgoto[yylhs] + *yyssp; - yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp - ? yytable[yyi] - : yydefgoto[yylhs]); - } - - goto yynewstate; - - -/*--------------------------------------. -| yyerrlab -- here on detecting error. | -`--------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; - yyerror (&yylloc, YY_("syntax error")); - } - - yyerror_range[1] = yylloc; - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval, &yylloc); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - /* Pacify compilers when the user code never invokes YYERROR and the - label yyerrorlab therefore never appears in user code. */ - if (0) - YYERROR; - ++yynerrs; - - /* Do not reclaim the symbols of the rule whose action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - /* Pop stack until we find a state that shifts the error token. */ - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYSYMBOL_YYerror; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - yyerror_range[1] = *yylsp; - yydestruct ("Error: popping", - YY_ACCESSING_SYMBOL (yystate), yyvsp, yylsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - yyerror_range[2] = yylloc; - ++yylsp; - YYLLOC_DEFAULT (*yylsp, yyerror_range, 2); - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturnlab; - - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturnlab; - - -/*-----------------------------------------------------------. -| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | -`-----------------------------------------------------------*/ -yyexhaustedlab: - yyerror (&yylloc, YY_("memory exhausted")); - yyresult = 2; - goto yyreturnlab; - - -/*----------------------------------------------------------. -| yyreturnlab -- parsing is finished, clean up and return. | -`----------------------------------------------------------*/ -yyreturnlab: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, &yylloc); - } - /* Do not reclaim the symbols of the rule whose action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - - return yyresult; -} - diff --git a/dtool/src/cppparser/cppBison.h.prebuilt b/dtool/src/cppparser/cppBison.h.prebuilt deleted file mode 100644 index 78032c0153c..00000000000 --- a/dtool/src/cppparser/cppBison.h.prebuilt +++ /dev/null @@ -1,394 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.8.2. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, - Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, - especially those whose name start with YY_ or yy_. They are - private implementation details that can be changed or removed. */ - -#ifndef YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED -# define YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int cppyydebug; -#endif - -/* Token kinds. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - YYEMPTY = -2, - YYEOF = 0, /* "end of file" */ - YYerror = 256, /* error */ - YYUNDEF = 257, /* "invalid token" */ - REAL = 258, /* REAL */ - INTEGER = 259, /* INTEGER */ - CHAR_TOK = 260, /* CHAR_TOK */ - SIMPLE_STRING = 261, /* SIMPLE_STRING */ - SIMPLE_IDENTIFIER = 262, /* SIMPLE_IDENTIFIER */ - STRING_LITERAL = 263, /* STRING_LITERAL */ - CUSTOM_LITERAL = 264, /* CUSTOM_LITERAL */ - IDENTIFIER = 265, /* IDENTIFIER */ - TYPENAME_IDENTIFIER = 266, /* TYPENAME_IDENTIFIER */ - TYPEPACK_IDENTIFIER = 267, /* TYPEPACK_IDENTIFIER */ - SCOPING = 268, /* SCOPING */ - TYPEDEFNAME = 269, /* TYPEDEFNAME */ - ELLIPSIS = 270, /* ELLIPSIS */ - OROR = 271, /* OROR */ - ANDAND = 272, /* ANDAND */ - EQCOMPARE = 273, /* EQCOMPARE */ - NECOMPARE = 274, /* NECOMPARE */ - LECOMPARE = 275, /* LECOMPARE */ - GECOMPARE = 276, /* GECOMPARE */ - SPACESHIP = 277, /* SPACESHIP */ - LSHIFT = 278, /* LSHIFT */ - RSHIFT = 279, /* RSHIFT */ - POINTSAT_STAR = 280, /* POINTSAT_STAR */ - DOT_STAR = 281, /* DOT_STAR */ - UNARY = 282, /* UNARY */ - UNARY_NOT = 283, /* UNARY_NOT */ - UNARY_NEGATE = 284, /* UNARY_NEGATE */ - UNARY_MINUS = 285, /* UNARY_MINUS */ - UNARY_PLUS = 286, /* UNARY_PLUS */ - UNARY_STAR = 287, /* UNARY_STAR */ - UNARY_REF = 288, /* UNARY_REF */ - POINTSAT = 289, /* POINTSAT */ - SCOPE = 290, /* SCOPE */ - PLUSPLUS = 291, /* PLUSPLUS */ - MINUSMINUS = 292, /* MINUSMINUS */ - TIMESEQUAL = 293, /* TIMESEQUAL */ - DIVIDEEQUAL = 294, /* DIVIDEEQUAL */ - MODEQUAL = 295, /* MODEQUAL */ - PLUSEQUAL = 296, /* PLUSEQUAL */ - MINUSEQUAL = 297, /* MINUSEQUAL */ - OREQUAL = 298, /* OREQUAL */ - ANDEQUAL = 299, /* ANDEQUAL */ - XOREQUAL = 300, /* XOREQUAL */ - LSHIFTEQUAL = 301, /* LSHIFTEQUAL */ - RSHIFTEQUAL = 302, /* RSHIFTEQUAL */ - ATTR_LEFT = 303, /* ATTR_LEFT */ - ATTR_RIGHT = 304, /* ATTR_RIGHT */ - KW_ALIGNAS = 305, /* KW_ALIGNAS */ - KW_ALIGNOF = 306, /* KW_ALIGNOF */ - KW_AUTO = 307, /* KW_AUTO */ - KW_BEGIN_PUBLISH = 308, /* KW_BEGIN_PUBLISH */ - KW_BLOCKING = 309, /* KW_BLOCKING */ - KW_BOOL = 310, /* KW_BOOL */ - KW_BUILTIN_VA_LIST = 311, /* KW_BUILTIN_VA_LIST */ - KW_CATCH = 312, /* KW_CATCH */ - KW_CHAR = 313, /* KW_CHAR */ - KW_CHAR8_T = 314, /* KW_CHAR8_T */ - KW_CHAR16_T = 315, /* KW_CHAR16_T */ - KW_CHAR32_T = 316, /* KW_CHAR32_T */ - KW_CLASS = 317, /* KW_CLASS */ - KW_CONST = 318, /* KW_CONST */ - KW_CONSTEVAL = 319, /* KW_CONSTEVAL */ - KW_CONSTEXPR = 320, /* KW_CONSTEXPR */ - KW_CONSTINIT = 321, /* KW_CONSTINIT */ - KW_CONST_CAST = 322, /* KW_CONST_CAST */ - KW_DECLTYPE = 323, /* KW_DECLTYPE */ - KW_DEFAULT = 324, /* KW_DEFAULT */ - KW_DELETE = 325, /* KW_DELETE */ - KW_DOUBLE = 326, /* KW_DOUBLE */ - KW_DYNAMIC_CAST = 327, /* KW_DYNAMIC_CAST */ - KW_ELSE = 328, /* KW_ELSE */ - KW_END_PUBLISH = 329, /* KW_END_PUBLISH */ - KW_ENUM = 330, /* KW_ENUM */ - KW_EXTENSION = 331, /* KW_EXTENSION */ - KW_EXTERN = 332, /* KW_EXTERN */ - KW_EXPLICIT = 333, /* KW_EXPLICIT */ - KW_EXPLICIT_LPAREN = 334, /* KW_EXPLICIT_LPAREN */ - KW_PUBLISHED = 335, /* KW_PUBLISHED */ - KW_FALSE = 336, /* KW_FALSE */ - KW_FINAL = 337, /* KW_FINAL */ - KW_FLOAT = 338, /* KW_FLOAT */ - KW_FRIEND = 339, /* KW_FRIEND */ - KW_FOR = 340, /* KW_FOR */ - KW_GOTO = 341, /* KW_GOTO */ - KW_HAS_VIRTUAL_DESTRUCTOR = 342, /* KW_HAS_VIRTUAL_DESTRUCTOR */ - KW_IF = 343, /* KW_IF */ - KW_INLINE = 344, /* KW_INLINE */ - KW_INT = 345, /* KW_INT */ - KW_IS_ABSTRACT = 346, /* KW_IS_ABSTRACT */ - KW_IS_BASE_OF = 347, /* KW_IS_BASE_OF */ - KW_IS_CLASS = 348, /* KW_IS_CLASS */ - KW_IS_CONSTRUCTIBLE = 349, /* KW_IS_CONSTRUCTIBLE */ - KW_IS_CONVERTIBLE_TO = 350, /* KW_IS_CONVERTIBLE_TO */ - KW_IS_DESTRUCTIBLE = 351, /* KW_IS_DESTRUCTIBLE */ - KW_IS_EMPTY = 352, /* KW_IS_EMPTY */ - KW_IS_ENUM = 353, /* KW_IS_ENUM */ - KW_IS_FINAL = 354, /* KW_IS_FINAL */ - KW_IS_FUNDAMENTAL = 355, /* KW_IS_FUNDAMENTAL */ - KW_IS_POD = 356, /* KW_IS_POD */ - KW_IS_POLYMORPHIC = 357, /* KW_IS_POLYMORPHIC */ - KW_IS_STANDARD_LAYOUT = 358, /* KW_IS_STANDARD_LAYOUT */ - KW_IS_TRIVIAL = 359, /* KW_IS_TRIVIAL */ - KW_IS_TRIVIALLY_COPYABLE = 360, /* KW_IS_TRIVIALLY_COPYABLE */ - KW_IS_UNION = 361, /* KW_IS_UNION */ - KW_LONG = 362, /* KW_LONG */ - KW_MAKE_MAP_KEYS_SEQ = 363, /* KW_MAKE_MAP_KEYS_SEQ */ - KW_MAKE_MAP_PROPERTY = 364, /* KW_MAKE_MAP_PROPERTY */ - KW_MAKE_PROPERTY = 365, /* KW_MAKE_PROPERTY */ - KW_MAKE_PROPERTY2 = 366, /* KW_MAKE_PROPERTY2 */ - KW_MAKE_SEQ = 367, /* KW_MAKE_SEQ */ - KW_MAKE_SEQ_PROPERTY = 368, /* KW_MAKE_SEQ_PROPERTY */ - KW_MUTABLE = 369, /* KW_MUTABLE */ - KW_NAMESPACE = 370, /* KW_NAMESPACE */ - KW_NEW = 371, /* KW_NEW */ - KW_NOEXCEPT = 372, /* KW_NOEXCEPT */ - KW_NOEXCEPT_LPAREN = 373, /* KW_NOEXCEPT_LPAREN */ - KW_NULLPTR = 374, /* KW_NULLPTR */ - KW_OPERATOR = 375, /* KW_OPERATOR */ - KW_OVERRIDE = 376, /* KW_OVERRIDE */ - KW_PRIVATE = 377, /* KW_PRIVATE */ - KW_PROTECTED = 378, /* KW_PROTECTED */ - KW_PUBLIC = 379, /* KW_PUBLIC */ - KW_REGISTER = 380, /* KW_REGISTER */ - KW_REINTERPRET_CAST = 381, /* KW_REINTERPRET_CAST */ - KW_RESTRICT = 382, /* KW_RESTRICT */ - KW_RETURN = 383, /* KW_RETURN */ - KW_SHORT = 384, /* KW_SHORT */ - KW_SIGNED = 385, /* KW_SIGNED */ - KW_SIZEOF = 386, /* KW_SIZEOF */ - KW_STATIC = 387, /* KW_STATIC */ - KW_STATIC_ASSERT = 388, /* KW_STATIC_ASSERT */ - KW_STATIC_CAST = 389, /* KW_STATIC_CAST */ - KW_STRUCT = 390, /* KW_STRUCT */ - KW_TEMPLATE = 391, /* KW_TEMPLATE */ - KW_THREAD_LOCAL = 392, /* KW_THREAD_LOCAL */ - KW_THROW = 393, /* KW_THROW */ - KW_TRUE = 394, /* KW_TRUE */ - KW_TRY = 395, /* KW_TRY */ - KW_TYPEDEF = 396, /* KW_TYPEDEF */ - KW_TYPEID = 397, /* KW_TYPEID */ - KW_TYPENAME = 398, /* KW_TYPENAME */ - KW_UNDERLYING_TYPE = 399, /* KW_UNDERLYING_TYPE */ - KW_UNION = 400, /* KW_UNION */ - KW_UNSIGNED = 401, /* KW_UNSIGNED */ - KW_USING = 402, /* KW_USING */ - KW_VIRTUAL = 403, /* KW_VIRTUAL */ - KW_VOID = 404, /* KW_VOID */ - KW_VOLATILE = 405, /* KW_VOLATILE */ - KW_WCHAR_T = 406, /* KW_WCHAR_T */ - KW_WHILE = 407, /* KW_WHILE */ - START_CPP = 408, /* START_CPP */ - START_CONST_EXPR = 409, /* START_CONST_EXPR */ - START_TYPE = 410 /* START_TYPE */ - }; - typedef enum yytokentype yytoken_kind_t; -#endif -/* Token kinds. */ -#define YYEMPTY -2 -#define YYEOF 0 -#define YYerror 256 -#define YYUNDEF 257 -#define REAL 258 -#define INTEGER 259 -#define CHAR_TOK 260 -#define SIMPLE_STRING 261 -#define SIMPLE_IDENTIFIER 262 -#define STRING_LITERAL 263 -#define CUSTOM_LITERAL 264 -#define IDENTIFIER 265 -#define TYPENAME_IDENTIFIER 266 -#define TYPEPACK_IDENTIFIER 267 -#define SCOPING 268 -#define TYPEDEFNAME 269 -#define ELLIPSIS 270 -#define OROR 271 -#define ANDAND 272 -#define EQCOMPARE 273 -#define NECOMPARE 274 -#define LECOMPARE 275 -#define GECOMPARE 276 -#define SPACESHIP 277 -#define LSHIFT 278 -#define RSHIFT 279 -#define POINTSAT_STAR 280 -#define DOT_STAR 281 -#define UNARY 282 -#define UNARY_NOT 283 -#define UNARY_NEGATE 284 -#define UNARY_MINUS 285 -#define UNARY_PLUS 286 -#define UNARY_STAR 287 -#define UNARY_REF 288 -#define POINTSAT 289 -#define SCOPE 290 -#define PLUSPLUS 291 -#define MINUSMINUS 292 -#define TIMESEQUAL 293 -#define DIVIDEEQUAL 294 -#define MODEQUAL 295 -#define PLUSEQUAL 296 -#define MINUSEQUAL 297 -#define OREQUAL 298 -#define ANDEQUAL 299 -#define XOREQUAL 300 -#define LSHIFTEQUAL 301 -#define RSHIFTEQUAL 302 -#define ATTR_LEFT 303 -#define ATTR_RIGHT 304 -#define KW_ALIGNAS 305 -#define KW_ALIGNOF 306 -#define KW_AUTO 307 -#define KW_BEGIN_PUBLISH 308 -#define KW_BLOCKING 309 -#define KW_BOOL 310 -#define KW_BUILTIN_VA_LIST 311 -#define KW_CATCH 312 -#define KW_CHAR 313 -#define KW_CHAR8_T 314 -#define KW_CHAR16_T 315 -#define KW_CHAR32_T 316 -#define KW_CLASS 317 -#define KW_CONST 318 -#define KW_CONSTEVAL 319 -#define KW_CONSTEXPR 320 -#define KW_CONSTINIT 321 -#define KW_CONST_CAST 322 -#define KW_DECLTYPE 323 -#define KW_DEFAULT 324 -#define KW_DELETE 325 -#define KW_DOUBLE 326 -#define KW_DYNAMIC_CAST 327 -#define KW_ELSE 328 -#define KW_END_PUBLISH 329 -#define KW_ENUM 330 -#define KW_EXTENSION 331 -#define KW_EXTERN 332 -#define KW_EXPLICIT 333 -#define KW_EXPLICIT_LPAREN 334 -#define KW_PUBLISHED 335 -#define KW_FALSE 336 -#define KW_FINAL 337 -#define KW_FLOAT 338 -#define KW_FRIEND 339 -#define KW_FOR 340 -#define KW_GOTO 341 -#define KW_HAS_VIRTUAL_DESTRUCTOR 342 -#define KW_IF 343 -#define KW_INLINE 344 -#define KW_INT 345 -#define KW_IS_ABSTRACT 346 -#define KW_IS_BASE_OF 347 -#define KW_IS_CLASS 348 -#define KW_IS_CONSTRUCTIBLE 349 -#define KW_IS_CONVERTIBLE_TO 350 -#define KW_IS_DESTRUCTIBLE 351 -#define KW_IS_EMPTY 352 -#define KW_IS_ENUM 353 -#define KW_IS_FINAL 354 -#define KW_IS_FUNDAMENTAL 355 -#define KW_IS_POD 356 -#define KW_IS_POLYMORPHIC 357 -#define KW_IS_STANDARD_LAYOUT 358 -#define KW_IS_TRIVIAL 359 -#define KW_IS_TRIVIALLY_COPYABLE 360 -#define KW_IS_UNION 361 -#define KW_LONG 362 -#define KW_MAKE_MAP_KEYS_SEQ 363 -#define KW_MAKE_MAP_PROPERTY 364 -#define KW_MAKE_PROPERTY 365 -#define KW_MAKE_PROPERTY2 366 -#define KW_MAKE_SEQ 367 -#define KW_MAKE_SEQ_PROPERTY 368 -#define KW_MUTABLE 369 -#define KW_NAMESPACE 370 -#define KW_NEW 371 -#define KW_NOEXCEPT 372 -#define KW_NOEXCEPT_LPAREN 373 -#define KW_NULLPTR 374 -#define KW_OPERATOR 375 -#define KW_OVERRIDE 376 -#define KW_PRIVATE 377 -#define KW_PROTECTED 378 -#define KW_PUBLIC 379 -#define KW_REGISTER 380 -#define KW_REINTERPRET_CAST 381 -#define KW_RESTRICT 382 -#define KW_RETURN 383 -#define KW_SHORT 384 -#define KW_SIGNED 385 -#define KW_SIZEOF 386 -#define KW_STATIC 387 -#define KW_STATIC_ASSERT 388 -#define KW_STATIC_CAST 389 -#define KW_STRUCT 390 -#define KW_TEMPLATE 391 -#define KW_THREAD_LOCAL 392 -#define KW_THROW 393 -#define KW_TRUE 394 -#define KW_TRY 395 -#define KW_TYPEDEF 396 -#define KW_TYPEID 397 -#define KW_TYPENAME 398 -#define KW_UNDERLYING_TYPE 399 -#define KW_UNION 400 -#define KW_UNSIGNED 401 -#define KW_USING 402 -#define KW_VIRTUAL 403 -#define KW_VOID 404 -#define KW_VOLATILE 405 -#define KW_WCHAR_T 406 -#define KW_WHILE 407 -#define START_CPP 408 -#define START_CONST_EXPR 409 -#define START_TYPE 410 - -/* Value type. */ - -/* Location type. */ -#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED -typedef struct YYLTYPE YYLTYPE; -struct YYLTYPE -{ - int first_line; - int first_column; - int last_line; - int last_column; -}; -# define YYLTYPE_IS_DECLARED 1 -# define YYLTYPE_IS_TRIVIAL 1 -#endif - - - - -int cppyyparse (void); - - -#endif /* !YY_CPPYY_BUILT_TMP_CPPBISON_YXX_H_INCLUDED */ diff --git a/dtool/src/cppparser/cppBison.yxx b/dtool/src/cppparser/cppBison.yxx deleted file mode 100644 index 8a249d1185f..00000000000 --- a/dtool/src/cppparser/cppBison.yxx +++ /dev/null @@ -1,4455 +0,0 @@ -/** - * @file cppBison.yxx - * @author drose - * @date 1999-01-16 - */ - -%{ - -#include "cppBisonDefs.h" -#include "cppParser.h" -#include "cppClosureType.h" -#include "cppExpression.h" -#include "cppSimpleType.h" -#include "cppExtensionType.h" -#include "cppStructType.h" -#include "cppEnumType.h" -#include "cppFunctionType.h" -#include "cppTBDType.h" -#include "cppMakeProperty.h" -#include "cppMakeSeq.h" -#include "cppParameterList.h" -#include "cppInstance.h" -#include "cppClassTemplateParameter.h" -#include "cppTemplateParameterList.h" -#include "cppInstanceIdentifier.h" -#include "cppTypedefType.h" -#include "cppTypeDeclaration.h" -#include "cppVisibility.h" -#include "cppIdentifier.h" -#include "cppScope.h" -#include "cppTemplateScope.h" -#include "cppNamespace.h" -#include "cppUsing.h" - -using std::stringstream; -using std::string; - -//////////////////////////////////////////////////////////////////// -// Defining the interface to the parser. -//////////////////////////////////////////////////////////////////// - -CPPScope *current_scope = nullptr; -CPPScope *global_scope = nullptr; -CPPPreprocessor *current_lexer = nullptr; - -static CPPStructType *current_struct = nullptr; -static CPPEnumType *current_enum = nullptr; -static int current_storage_class = 0; -static CPPType *current_type = nullptr; -static CPPExpression *current_expr = nullptr; -static CPPAttributeList current_attributes; -static int publish_nest_level = 0; -static CPPVisibility publish_previous; -static YYLTYPE publish_loc; - -static std::vector last_scopes; -static std::vector last_storage_classes; -static std::vector last_structs; - -int yyparse(); - -#define YYERROR_VERBOSE - -static void -yyerror(const string &msg) { - current_lexer->error(msg, current_lexer->_last_token_loc); -} - -static void -yyerror(YYLTYPE *loc, const string &msg) { - current_lexer->error(msg, *loc); -} - -static void -yyerror(const string &msg, YYLTYPE &loc) { - current_lexer->error(msg, loc); -} - -static void -yywarning(const string &msg, YYLTYPE &loc) { - current_lexer->warning(msg, loc); -} - -static int -yylex(YYSTYPE *lval, YYLTYPE *lloc) { - CPPToken token = current_lexer->get_next_token(); - *lval = token._lval; - *lloc = token._lloc; - return token._token; -} - -void -parse_cpp(CPPParser *cp) { - CPPScope *old_scope = current_scope; - CPPScope *old_global_scope = global_scope; - CPPPreprocessor *old_lexer = current_lexer; - - current_scope = cp; - global_scope = cp; - current_lexer = cp; - publish_nest_level = 0; - yyparse(); - - if (publish_nest_level != 0) { - yyerror("Unclosed __begin_publish", publish_loc); - publish_nest_level = 0; - } - - current_scope = old_scope; - global_scope = old_global_scope; - current_lexer = old_lexer; - -} - -CPPExpression * -parse_const_expr(CPPPreprocessor *pp, CPPScope *new_current_scope, - CPPScope *new_global_scope) { - CPPScope *old_scope = current_scope; - CPPScope *old_global_scope = global_scope; - CPPPreprocessor *old_lexer = current_lexer; - CPPExpression *old_expr = current_expr; - - current_scope = new_current_scope; - global_scope = new_global_scope; - current_expr = nullptr; - current_lexer = pp; - yyparse(); - - CPPExpression *result = current_expr; - - current_scope = old_scope; - global_scope = old_global_scope; - current_lexer = old_lexer; - current_expr = old_expr; - - return result; -} - -CPPType * -parse_type(CPPPreprocessor *pp, CPPScope *new_current_scope, - CPPScope *new_global_scope) { - CPPScope *old_scope = current_scope; - CPPScope *old_global_scope = global_scope; - CPPPreprocessor *old_lexer = current_lexer; - CPPType *old_type = current_type; - - current_scope = new_current_scope; - global_scope = new_global_scope; - current_type = nullptr; - current_lexer = pp; - yyparse(); - - CPPType *result = current_type; - - current_scope = old_scope; - global_scope = old_global_scope; - current_lexer = old_lexer; - current_type = old_type; - - return result; -} - -static void -push_scope(CPPScope *new_scope) { - last_scopes.push_back(current_scope); - if (new_scope != nullptr) { - current_scope = new_scope; - } -} - -static void -pop_scope() { - assert(!last_scopes.empty()); - current_scope = last_scopes.back(); - last_scopes.pop_back(); -} - -static void -push_storage_class(int new_storage_class) { - last_storage_classes.push_back(current_storage_class); - current_storage_class = new_storage_class; -} - -static void -pop_storage_class() { - assert(!last_storage_classes.empty()); - current_storage_class = last_storage_classes.back(); - last_storage_classes.pop_back(); -} - -static void -push_struct(CPPStructType *new_struct) { - last_structs.push_back(current_struct); - current_struct = new_struct; -} - -static void -pop_struct() { - assert(!last_structs.empty()); - current_struct = last_structs.back(); - last_structs.pop_back(); -} - -%} - -/* This is a bison-specific declaration to enable recursive calls to - yyparse(). It changes the calling sequence to yylex(), passing - pointers to the current yylval and yylloc. Bison 2.7 introduces a - different syntax that will also pass the current yylloc to yyerror, - but we have to support Bison versions as old as 2.5 for now. */ -/*%define api.pure full*/ -%pure-parser -%locations - -%token REAL -%token INTEGER -%token CHAR_TOK -%token SIMPLE_STRING SIMPLE_IDENTIFIER -%token STRING_LITERAL CUSTOM_LITERAL -%token IDENTIFIER TYPENAME_IDENTIFIER TYPEPACK_IDENTIFIER SCOPING -%token TYPEDEFNAME - -%token ELLIPSIS -%token OROR -%token ANDAND -%token EQCOMPARE -%token NECOMPARE -%token LECOMPARE -%token GECOMPARE -%token SPACESHIP -%token LSHIFT -%token RSHIFT -%token POINTSAT_STAR -%token DOT_STAR -%token UNARY -%token UNARY_NOT -%token UNARY_NEGATE -%token UNARY_MINUS -%token UNARY_PLUS -%token UNARY_STAR -%token UNARY_REF -%token POINTSAT -%token SCOPE -%token PLUSPLUS -%token MINUSMINUS -%token TIMESEQUAL -%token DIVIDEEQUAL -%token MODEQUAL -%token PLUSEQUAL -%token MINUSEQUAL -%token OREQUAL -%token ANDEQUAL -%token XOREQUAL -%token LSHIFTEQUAL -%token RSHIFTEQUAL -%token ATTR_LEFT -%token ATTR_RIGHT - -%token KW_ALIGNAS -%token KW_ALIGNOF -%token KW_AUTO -%token KW_BEGIN_PUBLISH -%token KW_BLOCKING -%token KW_BOOL -%token KW_BUILTIN_VA_LIST -%token KW_CATCH -%token KW_CHAR -%token KW_CHAR8_T -%token KW_CHAR16_T -%token KW_CHAR32_T -%token KW_CLASS -%token KW_CONST -%token KW_CONSTEVAL -%token KW_CONSTEXPR -%token KW_CONSTINIT -%token KW_CONST_CAST -%token KW_DECLTYPE -%token KW_DEFAULT -%token KW_DELETE -%token KW_DOUBLE -%token KW_DYNAMIC_CAST -%token KW_ELSE -%token KW_END_PUBLISH -%token KW_ENUM -%token KW_EXTENSION -%token KW_EXTERN -%token KW_EXPLICIT -%token KW_EXPLICIT_LPAREN -%token KW_PUBLISHED -%token KW_FALSE -%token KW_FINAL -%token KW_FLOAT -%token KW_FRIEND -%token KW_FOR -%token KW_GOTO -%token KW_HAS_VIRTUAL_DESTRUCTOR -%token KW_IF -%token KW_INLINE -%token KW_INT -%token KW_IS_ABSTRACT -%token KW_IS_BASE_OF -%token KW_IS_CLASS -%token KW_IS_CONSTRUCTIBLE -%token KW_IS_CONVERTIBLE_TO -%token KW_IS_DESTRUCTIBLE -%token KW_IS_EMPTY -%token KW_IS_ENUM -%token KW_IS_FINAL -%token KW_IS_FUNDAMENTAL -%token KW_IS_POD -%token KW_IS_POLYMORPHIC -%token KW_IS_STANDARD_LAYOUT -%token KW_IS_TRIVIAL -%token KW_IS_TRIVIALLY_COPYABLE -%token KW_IS_UNION -%token KW_LONG -%token KW_MAKE_MAP_KEYS_SEQ -%token KW_MAKE_MAP_PROPERTY -%token KW_MAKE_PROPERTY -%token KW_MAKE_PROPERTY2 -%token KW_MAKE_SEQ -%token KW_MAKE_SEQ_PROPERTY -%token KW_MUTABLE -%token KW_NAMESPACE -%token KW_NEW -%token KW_NOEXCEPT -%token KW_NOEXCEPT_LPAREN -%token KW_NULLPTR -%token KW_OPERATOR -%token KW_OVERRIDE -%token KW_PRIVATE -%token KW_PROTECTED -%token KW_PUBLIC -%token KW_REGISTER -%token KW_REINTERPRET_CAST -%token KW_RESTRICT -%token KW_RETURN -%token KW_SHORT -%token KW_SIGNED -%token KW_SIZEOF -%token KW_STATIC -%token KW_STATIC_ASSERT -%token KW_STATIC_CAST -%token KW_STRUCT -%token KW_TEMPLATE -%token KW_THREAD_LOCAL -%token KW_THROW -%token KW_TRUE -%token KW_TRY -%token KW_TYPEDEF -%token KW_TYPEID -%token KW_TYPENAME -%token KW_UNDERLYING_TYPE -%token KW_UNION -%token KW_UNSIGNED -%token KW_USING -%token KW_VIRTUAL -%token KW_VOID -%token KW_VOLATILE -%token KW_WCHAR_T -%token KW_WHILE - -/* These special tokens are used to set the starting state of the - parser. The lexer places the appropriate one of these on the head - of the input stream. */ -%token START_CPP -%token START_CONST_EXPR -%token START_TYPE - -%type optional_attributes -%type attribute_specifiers -%type attribute_specifier -%type storage_class -%type constructor_prototype -%type function_prototype -%type function_post -%type function_operator -%type template_formal_parameter -%type template_formal_parameter_type -%type instance_identifier -%type instance_identifier_and_maybe_trailing_return_type -%type function_parameter_list -%type function_parameters -%type formal_parameter_list -%type formal_parameters -%type capture_list -%type capture -%type template_parameter_maybe_initialize -%type maybe_initialize -%type maybe_initialize_or_constructor_body -%type maybe_initialize_or_function_body -%type function_parameter -%type formal_parameter -%type not_paren_formal_parameter_identifier -%type formal_parameter_identifier -%type parameter_pack_identifier -%type not_paren_empty_instance_identifier -%type empty_instance_identifier -%type type type_pack -%type type_decl -%type var_type_decl -%type predefined_type -%type full_type -%type anonymous_struct -%type named_struct -%type enum -%type enum_keyword -%type struct_keyword -%type simple_type -%type simple_int_type -%type simple_float_type -%type simple_void_type -%type class_derivation_name -%type enum_element_type -%type maybe_trailing_return_type -%type maybe_comma_identifier -/*%type typedefname*/ -%type name -%type name_no_final -%type string_literal - -/* We need to treat KW_OPERATOR as a scopable keyword. */ -%type KW_OPERATOR - -%type optional_const_expr -%type optional_const_expr_comma -%type const_expr_comma -%type no_angle_bracket_const_expr -%type const_expr -%type const_operand -%type formal_const_expr -%type formal_const_operand - - -/* Precedence rules. */ - -%left IDENTIFIER TYPENAME_IDENTIFIER TYPEDEFNAME KW_ENUM ELLIPSIS KW_OPERATOR KW_TYPENAME KW_INT KW_SHORT KW_UNSIGNED KW_SIGNED KW_LONG KW_FLOAT KW_DOUBLE KW_CHAR KW_WCHAR_T KW_CHAR8_T KW_CHAR16_T KW_CHAR32_T KW_BOOL - -%left '{' ',' ';' - -%nonassoc KW_THROW -%right ':' -%right '=' -%right '?' -%left OROR -%left ANDAND -%left '|' -%left '^' -%left '&' -%left EQCOMPARE NECOMPARE -%left LECOMPARE GECOMPARE '<' '>' -%left SPACESHIP -%left LSHIFT RSHIFT -%left '+' '-' -%left '*' '/' '%' -%left POINTSAT_STAR DOT_STAR -%right UNARY PLUSPLUS MINUSMINUS '~' -%left POINTSAT '.' '(' '[' - -%right SCOPE -%nonassoc KW_NEW KW_DELETE KW_TRY KW_CATCH - -%% - -grammar: - START_CPP cpp - | START_CONST_EXPR const_expr -{ - current_expr = $2; -} - | START_TYPE full_type -{ - current_type = $2; -} - ; - -cpp: - empty - | cpp optional_attributes ';' -{ - if (!$2.is_empty()) { - current_scope->add_declaration(new CPPDeclaration(@2.file, $2), global_scope, current_lexer, @2); - } -} - | cpp optional_attributes -{ - current_attributes = $2; -} - declaration -{ - current_attributes = CPPAttributeList(); -} - ; - -constructor_inits: - constructor_init - | constructor_inits ',' constructor_init - ; - -constructor_init: - name '(' optional_const_expr_comma ')' -{ - delete $3; -} - | name '(' optional_const_expr_comma ')' ELLIPSIS -{ - delete $3; -} - | name '{' optional_const_expr_comma '}' -{ - delete $3; -} - ; - -/* This is principally for the syntax: extern "C" { ... }. - - We use storage_class instead of simply KW_EXTERN to avoid - shift/reduce conflicts with yacc's limited differentiation - ability. */ -extern_c: - storage_class '{' -{ - push_storage_class((current_storage_class & ~CPPInstance::SC_c_binding) | - ($1 & CPPInstance::SC_c_binding)); -} - cpp '}' -{ - pop_storage_class(); -} - ; - -declaration: - type_like_declaration - | template_declaration - | extern_c - | namespace_declaration - | friend_declaration - | KW_TYPEDEF typedef_declaration - | KW_BEGIN_PUBLISH -{ - if (publish_nest_level != 0) { - yyerror("Unclosed __begin_publish", publish_loc); - publish_nest_level = 0; - current_scope->set_current_vis(V_public); - } - - publish_previous = current_scope->get_current_vis(); - publish_loc = @1; - publish_nest_level++; - current_scope->set_current_vis(V_published); -} - | KW_END_PUBLISH -{ - if (publish_nest_level != 1) { - yyerror("Unmatched __end_publish", @1); - } else { - current_scope->set_current_vis(publish_previous); - } - publish_nest_level = 0; -} - | KW_PUBLISHED ':' -{ - current_scope->set_current_vis(V_published); -} - | KW_PUBLIC ':' -{ - if (publish_nest_level > 0) { - current_scope->set_current_vis(V_published); - } else { - current_scope->set_current_vis(V_public); - } -} - | KW_PROTECTED ':' -{ - current_scope->set_current_vis(V_protected); -} - | KW_PRIVATE ':' -{ - current_scope->set_current_vis(V_private); -} - | KW_MAKE_PROPERTY '(' name ',' IDENTIFIER maybe_comma_identifier ')' ';' -{ - CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5); - } else { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - - if ($6 != nullptr) { - CPPDeclaration *setter = $6->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + $6->get_fully_scoped_name(), @6); - } else { - make_property->_set_function = setter->as_function_group(); - } - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @5); - - } else { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @7); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *deleter = $9->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + $9->get_fully_scoped_name(), @9); - } else { - make_property->_del_function = deleter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); - length_getter = nullptr; - } - - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); - length_getter = nullptr; - } - - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - - CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); - } else { - make_property->_set_function = setter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); - length_getter = nullptr; - } - - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - - CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *deleter = $11->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + $11->get_fully_scoped_name(), @11); - } else { - make_property->_del_function = deleter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_SEQ_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); - length_getter = nullptr; - } - - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_sequence, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - - CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *deleter = $11->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + $11->get_fully_scoped_name(), @11); - } else { - make_property->_del_function = deleter->as_function_group(); - } - - CPPDeclaration *inserter = $13->find_symbol(current_scope, global_scope, current_lexer); - if (inserter == nullptr || inserter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid append method: " + $13->get_fully_scoped_name(), @13); - } else { - make_property->_insert_function = inserter->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid item getter method: " + $5->get_fully_scoped_name(), @5); - - } else { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_mapping, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - - } else { - CPPMakeProperty *make_property; - make_property = new CPPMakeProperty($3, CPPMakeProperty::T_mapping, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_MAP_PROPERTY '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER maybe_comma_identifier ')' ';' -{ - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - - } else { - CPPMakeProperty *make_property = new CPPMakeProperty($3, CPPMakeProperty::T_mapping, current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); - } else { - make_property->_set_function = setter->as_function_group(); - } - - if ($10 != nullptr) { - CPPDeclaration *deleter = $10->find_symbol(current_scope, global_scope, current_lexer); - if (deleter == nullptr || deleter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid delete method: " + $10->get_fully_scoped_name(), @10); - } else { - make_property->_del_function = deleter->as_function_group(); - } - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_MAP_KEYS_SEQ '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); - length_getter = nullptr; - } - - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - getter = nullptr; - } - - if (getter != nullptr && length_getter != nullptr) { - CPPMakeProperty *make_property = nullptr; - for (size_t i = 0; i < current_scope->_declarations.size(); ++i) { - make_property = current_scope->_declarations[i]->as_make_property(); - if (make_property != nullptr) { - if (make_property->get_fully_scoped_name() == $3->get_fully_scoped_name()) { - break; - } else { - make_property = nullptr; - } - } - } - if (make_property != nullptr) { - make_property->_get_key_function = getter->as_function_group(); - make_property->_length_function = length_getter->as_function_group(); - } else { - yyerror("reference to non-existent MAKE_MAP_PROPERTY: " + $3->get_fully_scoped_name(), @3); - } - } -} - | KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - - } else { - CPPMakeProperty *make_property; - make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal, - current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_PROPERTY2 '(' name ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (getter == nullptr || getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("Reference to non-existent or invalid getter: " + $7->get_fully_scoped_name(), @7); - - } else { - CPPMakeProperty *make_property; - make_property = new CPPMakeProperty($3, CPPMakeProperty::T_normal, - current_scope, @1.file); - make_property->_get_function = getter->as_function_group(); - - CPPDeclaration *hasser = $5->find_symbol(current_scope, global_scope, current_lexer); - if (hasser == nullptr || hasser->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid has/find method: " + $5->get_fully_scoped_name(), @5); - } else { - make_property->_has_function = hasser->as_function_group(); - } - - CPPDeclaration *setter = $9->find_symbol(current_scope, global_scope, current_lexer); - if (setter == nullptr || setter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid setter: " + $9->get_fully_scoped_name(), @9); - } else { - make_property->_set_function = setter->as_function_group(); - } - - CPPDeclaration *clearer = $11->find_symbol(current_scope, global_scope, current_lexer); - if (clearer == nullptr || clearer->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid clear method: " + $11->get_fully_scoped_name(), @11); - } else { - make_property->_clear_function = clearer->as_function_group(); - } - - current_scope->add_declaration(make_property, global_scope, current_lexer, @1); - } -} - | KW_MAKE_SEQ '(' name ',' IDENTIFIER ',' IDENTIFIER ')' ';' -{ - CPPDeclaration *length_getter = $5->find_symbol(current_scope, global_scope, current_lexer); - if (length_getter == nullptr || length_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid length method: " + $5->get_fully_scoped_name(), @5); - length_getter = nullptr; - } - - CPPDeclaration *element_getter = $7->find_symbol(current_scope, global_scope, current_lexer); - if (element_getter == nullptr || element_getter->get_subtype() != CPPDeclaration::ST_function_group) { - yyerror("reference to non-existent or invalid element method: " + $7->get_fully_scoped_name(), @5); - element_getter = nullptr; - } - - if (length_getter != nullptr && element_getter != nullptr) { - CPPMakeSeq *make_seq = new CPPMakeSeq($3, - length_getter->as_function_group(), - element_getter->as_function_group(), - current_scope, @1.file); - current_scope->add_declaration(make_seq, global_scope, current_lexer, @1); - } -} - | KW_STATIC_ASSERT '(' const_expr ',' string_literal ')' ';' -{ - CPPExpression::Result result = $3->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("static_assert requires a constant expression", @3); - } else if (!result.as_boolean()) { - stringstream str; - str << *$5; - yywarning("static_assert failed: " + str.str(), @3); - } -} - | KW_STATIC_ASSERT '(' const_expr ')' ';' -{ - // This alternative version of static_assert was introduced in C++17. - CPPExpression::Result result = $3->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("static_assert requires a constant expression", @3); - } else if (!result.as_boolean()) { - yywarning("static_assert failed", @3); - } -} - ; - -friend_declaration: - KW_FRIEND -{ - CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("temp"), - V_public); - push_scope(new_scope); -} - declaration -{ - delete current_scope; - pop_scope(); -} - ; - - -storage_class: - empty -{ - $$ = 0; -} - | KW_CONST storage_class -{ - // This isn't really a storage class, but it helps with parsing. - $$ = $2 | (int)CPPInstance::SC_const; -} - | KW_EXTERN storage_class -{ - $$ = $2 | (int)CPPInstance::SC_extern; -} - | KW_EXTERN SIMPLE_STRING storage_class -{ - $$ = $3 | (int)CPPInstance::SC_extern; - if ($2 == "C") { - $$ |= (int)CPPInstance::SC_c_binding; - } else if ($2 == "C++") { - $$ &= ~(int)CPPInstance::SC_c_binding; - } else { - yywarning("Ignoring unknown linkage type \"" + $2 + "\"", @2); - } -} - | KW_STATIC storage_class -{ - $$ = $2 | (int)CPPInstance::SC_static; -} - | KW_INLINE storage_class -{ - $$ = $2 | (int)CPPInstance::SC_inline; -} - | KW_VIRTUAL storage_class -{ - $$ = $2 | (int)CPPInstance::SC_virtual; -} - | KW_EXPLICIT storage_class -{ - $$ = $2 | (int)CPPInstance::SC_explicit; -} - | KW_EXPLICIT_LPAREN const_expr ')' storage_class -{ - CPPExpression::Result result = $2->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("explicit() requires a constant expression", @2); - } else if (result.as_boolean()) { - $$ = $4 | (int)CPPInstance::SC_explicit; - } -} - | KW_REGISTER storage_class -{ - $$ = $2 | (int)CPPInstance::SC_register; -} - | KW_VOLATILE storage_class -{ - $$ = $2 | (int)CPPInstance::SC_volatile; -} - | KW_MUTABLE storage_class -{ - $$ = $2 | (int)CPPInstance::SC_mutable; -} - | KW_CONSTEVAL storage_class -{ - $$ = $2 | (int)CPPInstance::SC_consteval; -} - | KW_CONSTEXPR storage_class -{ - $$ = $2 | (int)CPPInstance::SC_constexpr; -} - | KW_CONSTINIT storage_class -{ - $$ = $2 | (int)CPPInstance::SC_constinit; -} - | KW_BLOCKING storage_class -{ - $$ = $2 | (int)CPPInstance::SC_blocking; -} - | KW_EXTENSION storage_class -{ - $$ = $2 | (int)CPPInstance::SC_extension; -} - | KW_THREAD_LOCAL storage_class -{ - $$ = $2 | (int)CPPInstance::SC_thread_local; -} - ; - -optional_attributes: - empty -{ - $$ = CPPAttributeList(); -} - | ATTR_LEFT attribute_specifiers ATTR_RIGHT optional_attributes -{ - $$ = $2; - $$.add_attributes_from($4); -} - | ATTR_LEFT KW_USING name ':' attribute_specifiers ATTR_RIGHT optional_attributes -{ - $$ = $5; - for (CPPAttributeList::Attribute &attr : $$._attributes) { - attr._ident->prepend($3); - } - $$.add_attributes_from($7); -} - | KW_ALIGNAS '(' const_expr ')' optional_attributes -{ - $$ = $5; - $$.add_alignas($3->as_expression()); -} - | KW_ALIGNAS '(' type_decl ')' optional_attributes -{ - $$ = $5; - $$.add_alignas($3->as_type()); -} - ; - -attribute_specifiers: - attribute_specifier -{ - $$ = $1; -} - | attribute_specifier ',' attribute_specifiers -{ - $$ = $1; - $$.add_attributes_from($3); -} - ; - -attribute_specifier: - name -{ - $$ = CPPAttributeList(); - $$.add_attribute($1); -} - | name '(' formal_parameter_list ')' -{ - $$ = CPPAttributeList(); - $$.add_attribute($1); -} - ; - -type_like_declaration: - storage_class var_type_decl -{ - // We don't need to push/pop type, because we can't nest - // type_like_declaration. - if ($2->as_type_declaration()) { - current_type = $2->as_type_declaration()->_type; - } else { - current_type = $2->as_type(); - } - push_storage_class($1); -} - multiple_instance_identifiers -{ - pop_storage_class(); -} - - | storage_class type_decl ';' -{ - // We don't really care about the storage class here. In fact, it's - // not actually legal to define a class or struct using a particular - // storage class, but we require it just to help yacc out in its - // parsing. - - current_scope->add_declaration($2, global_scope, current_lexer, @2); -} - | storage_class constructor_prototype -{ - if ($2 != nullptr) { - // Push the scope so that the initializers can make use of things defined - // in the class body. - push_scope($2->get_scope(current_scope, global_scope)); - $2->_storage_class |= (current_storage_class | $1); - } -} - maybe_initialize_or_constructor_body -{ - if ($2 != nullptr) { - pop_scope(); - current_scope->add_declaration($2, global_scope, current_lexer, @2); - $2->set_initializer($4); - } -} - | storage_class function_prototype maybe_initialize_or_function_body -{ - if ($2 != nullptr) { - $2->_storage_class |= (current_storage_class | $1); - current_scope->add_declaration($2, global_scope, current_lexer, @2); - $2->set_initializer($3); - } -} - | using_declaration - - /* We don't need to include a rule for variables that point to - functions, because we get those from the function_prototype - definition. */ - ; - -multiple_instance_identifiers: - instance_identifier_and_maybe_trailing_return_type maybe_initialize_or_function_body -{ - if (current_storage_class & CPPInstance::SC_const) { - $1->add_modifier(IIT_const); - } - $1->add_attributes(current_attributes); - CPPInstance *inst = new CPPInstance(current_type, $1, - current_storage_class, - @1.file); - inst->set_initializer($2); - current_scope->add_declaration(inst, global_scope, current_lexer, @1); -} - | instance_identifier_and_maybe_trailing_return_type maybe_initialize ',' multiple_instance_identifiers -{ - if (current_storage_class & CPPInstance::SC_const) { - $1->add_modifier(IIT_const); - } - $1->add_attributes(current_attributes); - CPPInstance *inst = new CPPInstance(current_type, $1, - current_storage_class, - @1.file); - inst->set_initializer($2); - current_scope->add_declaration(inst, global_scope, current_lexer, @1); -} - ; - - -typedef_declaration: - storage_class var_type_decl -{ - // We don't need to push/pop type, because we can't nest - // multiple_var_declarations. - if ($2->as_type_declaration()) { - current_type = $2->as_type_declaration()->_type; - } else { - current_type = $2->as_type(); - } - push_storage_class($1); -} - typedef_instance_identifiers -{ - pop_storage_class(); -} - | storage_class function_prototype maybe_initialize_or_function_body -{ - if ($2 != nullptr) { - CPPInstance *inst = $2->as_instance(); - if (inst != nullptr) { - inst->_storage_class |= (current_storage_class | $1); - current_scope->add_declaration(inst, global_scope, current_lexer, @2); - CPPTypedefType *typedef_type = new CPPTypedefType(inst->_type, inst->_ident, current_scope, inst->_attributes); - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @2); - } - } -} - ; - -typedef_instance_identifiers: - instance_identifier_and_maybe_trailing_return_type maybe_initialize_or_function_body -{ - if (current_storage_class & CPPInstance::SC_const) { - $1->add_modifier(IIT_const); - } - $1->add_attributes(current_attributes); - CPPType *target_type = current_type; - CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file); - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @1); -} - | instance_identifier_and_maybe_trailing_return_type maybe_initialize ',' typedef_instance_identifiers -{ - if (current_storage_class & CPPInstance::SC_const) { - $1->add_modifier(IIT_const); - } - $1->add_attributes(current_attributes); - CPPType *target_type = current_type; - CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file); - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @1); -} - ; - -constructor_prototype: - -/* Functions with implicit return types, and constructors */ - IDENTIFIER '(' -{ - // Create a scope for this function. - CPPScope *scope = new CPPScope($1->get_scope(current_scope, global_scope), - $1->_names.back(), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} - function_parameter_list ')' function_post optional_attributes -{ - CPPScope *scope = $1->get_scope(current_scope, global_scope); - CPPType *type; - std::string simple_name = $1->get_simple_name(); - if (!simple_name.empty() && simple_name[0] == '~') { - // A destructor has no return type. - type = new CPPSimpleType(CPPSimpleType::T_void); - } - else if (scope != nullptr && simple_name == scope->get_simple_name()) { - // Neither does a constructor. - type = new CPPSimpleType(CPPSimpleType::T_void); - } - else { - // This isn't a constructor, so it has an implicit return type of - // int. - yywarning("function has no return type, assuming int", @1); - type = new CPPSimpleType(CPPSimpleType::T_int); - } - pop_scope(); - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($1); - ii->add_func_modifier($4, $6, nullptr, $7); - ii->add_attributes(current_attributes); - - $$ = new CPPInstance(type, ii, 0, @1.file); -} -/* This is a hack to support functions with the identifier enveloped by a - pair of parentheses. */ - | TYPENAME_IDENTIFIER '(' IDENTIFIER ')' '(' -{ - // Create a scope for this function. - CPPScope *scope = new CPPScope($3->get_scope(current_scope, global_scope), - $3->_names.back(), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} - function_parameter_list ')' function_post optional_attributes -{ - pop_scope(); - CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert(type != nullptr); - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($3); - ii->add_func_modifier($7, $9, nullptr, $10); - ii->add_attributes(current_attributes); - - $$ = new CPPInstance(type, ii, 0, @1.file); -} - | TYPENAME_IDENTIFIER '(' -{ - // Create a scope for this function. - CPPScope *scope = new CPPScope($1->get_scope(current_scope, global_scope), - $1->_names.back(), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} - function_parameter_list ')' function_post optional_attributes -{ - pop_scope(); - CPPType *type; - if ($1->get_simple_name() == current_scope->get_simple_name()) { - // This is a constructor, and has no return. - type = new CPPSimpleType(CPPSimpleType::T_void); - } else { - // This isn't a constructor, so it has an implicit return type of - // int. - type = new CPPSimpleType(CPPSimpleType::T_int); - } - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier($1); - ii->add_func_modifier($4, $6, nullptr, $7); - ii->add_attributes(current_attributes); - - $$ = new CPPInstance(type, ii, 0, @1.file); -} - ; - -function_prototype: - -/* Destructors */ - '~' name '(' -{ - push_scope($2->get_scope(current_scope, global_scope)); -} - function_parameter_list ')' function_post optional_attributes -{ - pop_scope(); - if ($2->is_scoped()) { - yyerror("Invalid destructor name: ~" + $2->get_fully_scoped_name(), @2); - } else { - CPPIdentifier *ident = - new CPPIdentifier("~" + $2->get_simple_name(), @2); - delete $2; - - CPPType *type; - type = new CPPSimpleType(CPPSimpleType::T_void); - - CPPInstanceIdentifier *ii = new CPPInstanceIdentifier(ident); - ii->add_func_modifier($5, $7, nullptr, $8); - ii->add_attributes(current_attributes); - - $$ = new CPPInstance(type, ii, 0, @2.file); - } -} - -/* This is a special case: a function pointer declaration that looks - at first a lot like a constructor declaration. This is provided to - help yacc sort out the differences. It isn't an ideal solution, - because it doesn't catch a lot of subtle variants on this form--but - this will get at least the 99% most common uses. */ - - | TYPENAME_IDENTIFIER '(' '*' instance_identifier ')' '(' -{ - push_scope($4->get_scope(current_scope, global_scope)); -} - function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type -{ - pop_scope(); - CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert(type != nullptr); - - CPPInstanceIdentifier *ii = $4; - ii->add_modifier(IIT_pointer); - ii->add_func_modifier($8, $10, nullptr, $11); - ii->add_attributes(current_attributes); - $$ = new CPPInstance(type, ii, 0, @1.file); -} - | TYPENAME_IDENTIFIER '(' SCOPING '*' instance_identifier ')' '(' -{ - push_scope($5->get_scope(current_scope, global_scope)); -} - function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type -{ - pop_scope(); - CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert(type != nullptr); - - CPPInstanceIdentifier *ii = $5; - ii->add_scoped_pointer_modifier($3); - ii->add_func_modifier($9, $11, nullptr, $12); - ii->add_attributes(current_attributes); - $$ = new CPPInstance(type, ii, 0, @1.file); -} - -/* Typecast operators */ - | KW_OPERATOR type not_paren_formal_parameter_identifier '(' -{ - if ($1 != nullptr) { - push_scope($1->get_scope(current_scope, global_scope)); - } -} - function_parameter_list ')' function_post -{ - if ($1 != nullptr) { - pop_scope(); - } - - // We use formal_parameter_identifier, because that can match a type - // name with or without an identifier, but especially without, which - // is what follows the keyword "operator" in a typecast function. - // As an added bonus, the type of the formal_parameter will be the - // typecast type, i.e. the return type of the typecast function. - - // We give typecast operators the name "operator typecast ", - // where is a simple name of the type to be typecast. Use - // the method's return type to determine the full type description. - string name = "operator typecast " + $2->get_simple_name(); - CPPIdentifier *ident = $1; - if (ident == nullptr) { - ident = new CPPIdentifier(name, @2); - } else { - ident->add_name(name); - } - $$ = CPPInstance::make_typecast_function - (new CPPInstance($2, $3, 0, @3.file), ident, $6, $8); - $$->_attributes.add_attributes_from(current_attributes); -} - | KW_OPERATOR KW_CONST type not_paren_formal_parameter_identifier '(' -{ - if ($1 != nullptr) { - push_scope($1->get_scope(current_scope, global_scope)); - } -} - function_parameter_list ')' function_post -{ - if ($1 != nullptr) { - pop_scope(); - } - - CPPIdentifier *ident = $1; - if (ident == nullptr) { - ident = new CPPIdentifier("operator typecast", @4); - } else { - ident->add_name("operator typecast"); - } - $4->add_modifier(IIT_const); - $4->add_attributes(current_attributes); - $$ = CPPInstance::make_typecast_function - (new CPPInstance($3, $4, 0, @4.file), ident, $7, $9); -} - -/* Not actually a function prototype, but maybe a template - instantiation. Just included here (instead of somewhere else) to - avoid shift/reduce conflicts. */ - | IDENTIFIER -{ - CPPDeclaration *decl = - $1->find_symbol(current_scope, global_scope, current_lexer); - if (decl != nullptr) { - $$ = decl->as_instance(); - } else { - $$ = nullptr; - } -} - ; - -function_post: - empty -{ - $$ = 0; -} - | function_post KW_CONST -{ - $$ = $1 | (int)CPPFunctionType::F_const_method; -} - | function_post KW_VOLATILE -{ - $$ = $1 | (int)CPPFunctionType::F_volatile_method; -} - | function_post KW_NOEXCEPT -{ - $$ = $1 | (int)CPPFunctionType::F_noexcept; -} - | function_post KW_NOEXCEPT_LPAREN const_expr ')' -{ - CPPExpression::Result result = $3->evaluate(); - if (result._type == CPPExpression::RT_error) { - yywarning("noexcept() requires a constant expression", @3); - } else if (result.as_boolean()) { - $$ = $1 | (int)CPPFunctionType::F_noexcept; - } -} - | function_post KW_FINAL -{ - $$ = $1 | (int)CPPFunctionType::F_final; -} - | function_post KW_OVERRIDE -{ - $$ = $1 | (int)CPPFunctionType::F_override; -} - | function_post '&' -{ - $$ = $1 | (int)CPPFunctionType::F_lvalue_method; -} - | function_post ANDAND -{ - $$ = $1 | (int)CPPFunctionType::F_rvalue_method; -} - | function_post KW_MUTABLE -{ - // Used for lambdas, currently ignored. - $$ = $1; -} - | function_post KW_CONSTEXPR -{ - // Used for lambdas in C++17, currently ignored. - $$ = $1; -} - | function_post KW_THROW '(' ')' -{ - $$ = $1; -} - | function_post KW_THROW '(' name ')' -{ - $$ = $1; -} - | function_post KW_THROW '(' name ELLIPSIS ')' -{ - $$ = $1; -} - ; - -function_operator: - '!' -{ - $$ = "!"; -} - | '~' -{ - $$ = "~"; -} - | '*' -{ - $$ = "*"; -} - | '/' -{ - $$ = "/"; -} - | '%' -{ - $$ = "%"; -} - | '+' -{ - $$ = "+"; -} - | '-' -{ - $$ = "-"; -} - | '|' -{ - $$ = "|"; -} - | '&' -{ - $$ = "&"; -} - | '^' -{ - $$ = "^"; -} - | OROR -{ - $$ = "||"; -} - | ANDAND -{ - $$ = "&&"; -} - | EQCOMPARE -{ - $$ = "=="; -} - | NECOMPARE -{ - $$ = "!="; -} - | LECOMPARE -{ - $$ = "<="; -} - | GECOMPARE -{ - $$ = ">="; -} - | '<' -{ - $$ = "<"; -} - | '>' -{ - $$ = ">"; -} - | SPACESHIP -{ - $$ = "<=>"; -} - | LSHIFT -{ - $$ = "<<"; -} - | RSHIFT -{ - $$ = ">>"; -} - | '=' -{ - $$ = "="; -} - | ',' -{ - $$ = ","; -} - | PLUSPLUS -{ - $$ = "++"; -} - | MINUSMINUS -{ - $$ = "--"; -} - | TIMESEQUAL -{ - $$ = "*="; -} - | DIVIDEEQUAL -{ - $$ = "/="; -} - | MODEQUAL -{ - $$ = "%="; -} - | PLUSEQUAL -{ - $$ = "+="; -} - | MINUSEQUAL -{ - $$ = "-="; -} - | OREQUAL -{ - $$ = "|="; -} - | ANDEQUAL -{ - $$ = "&="; -} - | XOREQUAL -{ - $$ = "^="; -} - | LSHIFTEQUAL -{ - $$ = "<<="; -} - | RSHIFTEQUAL -{ - $$ = ">>="; -} - | POINTSAT -{ - $$ = "->"; -} - | '[' ']' -{ - $$ = "[]"; -} - | '(' ')' -{ - $$ = "()"; -} - | KW_NEW -{ - $$ = "new"; -} - | KW_DELETE -{ - $$ = "delete"; -} - ; - -more_template_declaration: - type_like_declaration - | template_declaration - | friend_declaration - ; - -template_declaration: - KW_EXTERN template_declaration - | KW_TEMPLATE -{ - push_scope(new CPPTemplateScope(current_scope)); -} - '<' template_formal_parameters '>' more_template_declaration -{ - pop_scope(); -} - | KW_TEMPLATE type_like_declaration - | KW_TEMPLATE friend_declaration - ; - -template_formal_parameters: - empty - | template_nonempty_formal_parameters - ; - -template_nonempty_formal_parameters: - template_formal_parameter -{ - CPPTemplateScope *ts = current_scope->as_template_scope(); - assert(ts != nullptr); - ts->add_template_parameter($1); -} - | template_nonempty_formal_parameters ',' template_formal_parameter -{ - CPPTemplateScope *ts = current_scope->as_template_scope(); - assert(ts != nullptr); - ts->add_template_parameter($3); -} - ; - -typename_keyword: - KW_CLASS - | KW_TYPENAME - ; - -template_formal_parameter: - typename_keyword -{ - $$ = CPPType::new_type(new CPPClassTemplateParameter(nullptr)); -} - | typename_keyword name -{ - $$ = CPPType::new_type(new CPPClassTemplateParameter($2)); -} - | typename_keyword name '=' full_type -{ - $$ = CPPType::new_type(new CPPClassTemplateParameter($2, $4)); -} - | typename_keyword ELLIPSIS -{ - CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter(nullptr); - ctp->_packed = true; - $$ = CPPType::new_type(ctp); -} - | typename_keyword ELLIPSIS name -{ - CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($3); - ctp->_packed = true; - $$ = CPPType::new_type(ctp); -} - | template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize -{ - CPPInstance *inst = new CPPInstance($1, $2, 0, @2.file); - inst->set_initializer($3); - $$ = inst; -} - | KW_CONST template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize -{ - $3->add_modifier(IIT_const); - CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file); - inst->set_initializer($4); - $$ = inst; -} - | template_formal_parameter_type parameter_pack_identifier -{ - CPPInstance *inst = new CPPInstance($1, $2, 0, @2.file); - $$ = inst; -} - | KW_CONST template_formal_parameter_type parameter_pack_identifier -{ - $3->add_modifier(IIT_const); - CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file); - $$ = inst; -} - | KW_VOLATILE template_formal_parameter_type formal_parameter_identifier template_parameter_maybe_initialize -{ - $3->add_modifier(IIT_volatile); - CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file); - inst->set_initializer($4); - $$ = inst; -} - | KW_VOLATILE template_formal_parameter_type parameter_pack_identifier -{ - $3->add_modifier(IIT_volatile); - CPPInstance *inst = new CPPInstance($2, $3, 0, @3.file); - $$ = inst; -} - ; - -template_formal_parameter_type: - simple_type -{ - $$ = CPPType::new_type($1); -} - | IDENTIFIER -{ - yywarning("Not a type: " + $1->get_fully_scoped_name(), @1); - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); -} - | TYPENAME_IDENTIFIER -{ - $$ = $1->find_type(current_scope, global_scope, false, current_lexer); - if ($$ == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert($$ != nullptr); -} - | TYPEPACK_IDENTIFIER -{ - $$ = $1->find_type(current_scope, global_scope, false, current_lexer); - if ($$ == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert($$ != nullptr); -} - ; - - -instance_identifier: - name_no_final optional_attributes -{ - $$ = new CPPInstanceIdentifier($1, $2); -} - | KW_OPERATOR function_operator optional_attributes -{ - // For an operator function. We implement this simply by building a - // ficticious name for the function; in other respects it's just - // like a regular function. - CPPIdentifier *ident = $1; - if (ident == nullptr) { - ident = new CPPIdentifier("operator "+$2, @2); - } else { - ident->_names.push_back("operator "+$2); - } - - $$ = new CPPInstanceIdentifier(ident, $3); -} - | KW_OPERATOR SIMPLE_STRING IDENTIFIER optional_attributes -{ - // A C++11 literal operator. - if (!$2.empty()) { - yyerror("expected empty string", @2); - } - CPPIdentifier *ident = $1; - if (ident == nullptr) { - ident = new CPPIdentifier("operator \"\" "+$3->get_simple_name(), @3); - } else { - ident->_names.push_back("operator \"\" "+$3->get_simple_name()); - } - - $$ = new CPPInstanceIdentifier(ident, $4); -} - | KW_CONST instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_const); -} - | KW_VOLATILE instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_volatile); -} - | '*' optional_attributes instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_pointer, $2); -} - | '&' optional_attributes instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_reference, $2); -} - | ANDAND optional_attributes instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_rvalue_reference, $2); -} - | SCOPING '*' optional_attributes instance_identifier %prec UNARY -{ - $$ = $4; - $$->add_scoped_pointer_modifier($1, $3); -} - | instance_identifier '[' optional_const_expr ']' optional_attributes -{ - $$ = $1; - $$->add_array_modifier($3, $5); -} - | '(' instance_identifier ')' -{ - $$ = $2; - $$->add_modifier(IIT_paren); -} - | instance_identifier '(' -{ - // Create a scope for this function (in case it is a function) - CPPScope *scope = new CPPScope($1->get_scope(current_scope, global_scope), - CPPNameComponent(""), V_private); - - // It still needs to be able to pick up any template arguments, if this is - // a definition for a method template. Add a fake "using" declaration to - // accomplish this. - scope->_using.insert(current_scope); - - push_scope(scope); -} - formal_parameter_list ')' function_post optional_attributes -{ - pop_scope(); - $$ = $1; - if ($4->is_parameter_expr() && $6 == 0) { - // Oops, this must have been an instance declaration with a - // parameter list, not a function prototype. - $$->add_initializer_modifier($4); - } - else { - // This was (probably) a function prototype. - $$->add_func_modifier($4, $6, nullptr, $7); - } -} - ; - - -instance_identifier_and_maybe_trailing_return_type: - instance_identifier maybe_trailing_return_type -{ - // This is handled a bit awkwardly right now. Ideally it'd be wrapped - // up in the instance_identifier rule, but then more needs to happen in - // order to avoid shift/reduce conflicts. - if ($2 != nullptr) { - $1->add_trailing_return_type($2); - } - $$ = $1; -} - | instance_identifier ':' const_expr -{ - // Bitfield definition. - $1->_bit_width = $3; - $$ = $1; -} - ; - - -maybe_trailing_return_type: - empty -{ - $$ = nullptr; -} - | POINTSAT predefined_type empty_instance_identifier -{ - $$ = $3->unroll_type($2); -} - | POINTSAT KW_CONST predefined_type empty_instance_identifier -{ - $4->add_modifier(IIT_const); - $$ = $4->unroll_type($3); -} - ; - - -maybe_comma_identifier: - empty -{ - $$ = nullptr; -} - | ',' IDENTIFIER -{ - $$ = $2; -} - ; - - -function_parameter_list: - empty -{ - $$ = new CPPParameterList; -} - | ELLIPSIS -{ - $$ = new CPPParameterList; - $$->_includes_ellipsis = true; -} - | function_parameters -{ - $$ = $1; -} - | function_parameters ',' ELLIPSIS -{ - $$ = $1; - $$->_includes_ellipsis = true; -} - | function_parameters ELLIPSIS -{ - $$ = $1; - $$->_includes_ellipsis = true; -} - ; - -function_parameters: - function_parameter -{ - $$ = new CPPParameterList; - $$->_parameters.push_back($1); -} - | function_parameters ',' function_parameter -{ - $$ = $1; - $$->_parameters.push_back($3); -} - ; - -formal_parameter_list: - empty -{ - $$ = new CPPParameterList; -} - | ELLIPSIS -{ - $$ = new CPPParameterList; - $$->_includes_ellipsis = true; -} - | formal_parameters -{ - $$ = $1; -} - | formal_parameters ',' ELLIPSIS -{ - $$ = $1; - $$->_includes_ellipsis = true; -} - | formal_parameters ELLIPSIS -{ - $$ = $1; - $$->_includes_ellipsis = true; -} - ; - -formal_parameters: - formal_parameter -{ - $$ = new CPPParameterList; - $$->_parameters.push_back($1); -} - | formal_parameters ',' formal_parameter -{ - $$ = $1; - $$->_parameters.push_back($3); -} - ; - -template_parameter_maybe_initialize: - empty -{ - $$ = nullptr; -} - | '=' no_angle_bracket_const_expr -{ - $$ = $2; -} - ; - -maybe_initialize: - empty -{ - $$ = nullptr; -} - | '=' const_expr -{ - $$ = $2; -} - ; - -maybe_initialize_or_constructor_body: - ';' -{ - $$ = nullptr; -} - | '{' code '}' -{ - $$ = nullptr; -} - | ':' constructor_inits '{' code '}' -{ - $$ = nullptr; -} - | '=' KW_DEFAULT ';' -{ - $$ = new CPPExpression(CPPExpression::get_default()); -} - | '=' KW_DELETE ';' -{ - $$ = new CPPExpression(CPPExpression::get_delete()); -} - ; - -maybe_initialize_or_function_body: - ';' -{ - $$ = nullptr; -} - | '{' code '}' -{ - $$ = nullptr; -} - | '=' const_expr ';' -{ - $$ = $2; -} - | '=' KW_DEFAULT ';' -{ - $$ = new CPPExpression(CPPExpression::get_default()); -} - | '=' KW_DELETE ';' -{ - $$ = new CPPExpression(CPPExpression::get_delete()); -} - | '=' '{' structure_init '}' -{ - $$ = nullptr; -} - ; - -structure_init: - empty - | structure_init_body - | structure_init_body ',' - ; - -structure_init_body: - const_expr -{ -} - | '{' structure_init '}' - | structure_init_body ',' const_expr - | structure_init_body ',' '{' structure_init '}' - ; - -function_parameter: - optional_attributes storage_class type formal_parameter_identifier maybe_initialize -{ - if ($2 & CPPInstance::SC_const) { - $4->add_modifier(IIT_const); - } - if ($2 & CPPInstance::SC_volatile) { - $4->add_modifier(IIT_volatile); - } - $4->add_attributes($1); - $$ = new CPPInstance($3, $4, 0, @4.file); - $$->set_initializer($5); -} - | optional_attributes storage_class type_pack parameter_pack_identifier maybe_initialize -{ - if ($2 & CPPInstance::SC_const) { - $4->add_modifier(IIT_const); - } - if ($2 & CPPInstance::SC_volatile) { - $4->add_modifier(IIT_volatile); - } - $4->add_attributes($1); - $$ = new CPPInstance($3, $4, 0, @4.file); - $$->set_initializer($5); -} - ; - -/* A "formal parameter" is like a function parameter, except that it parses - * instance declarations (that look like functions declaration) as well, and - * as such accepts constexpr parameters. - */ -formal_parameter: - function_parameter -{ - $$ = $1; -} - | formal_const_expr -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_parameter)); - $$ = new CPPInstance(type, "expr"); - $$->set_initializer($1); -} - ; - -not_paren_formal_parameter_identifier: - empty -{ - $$ = new CPPInstanceIdentifier(nullptr); -} - | name_no_final optional_attributes -{ - $$ = new CPPInstanceIdentifier($1, $2); -} - | KW_CONST not_paren_formal_parameter_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_const); -} - | KW_VOLATILE not_paren_formal_parameter_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_volatile); -} - | KW_RESTRICT not_paren_formal_parameter_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_restrict); -} - | '*' optional_attributes not_paren_formal_parameter_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_pointer, $2); -} - | '&' optional_attributes not_paren_formal_parameter_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_reference, $2); -} - | ANDAND optional_attributes not_paren_formal_parameter_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_rvalue_reference, $2); -} - | SCOPING '*' optional_attributes not_paren_formal_parameter_identifier %prec UNARY -{ - $$ = $4; - $$->add_scoped_pointer_modifier($1, $3); -} - | not_paren_formal_parameter_identifier '[' optional_const_expr ']' optional_attributes -{ - $$ = $1; - $$->add_array_modifier($3, $5); -} - ; - -formal_parameter_identifier: - empty -{ - $$ = new CPPInstanceIdentifier(nullptr); -} - | name_no_final optional_attributes -{ - $$ = new CPPInstanceIdentifier($1, $2); -} - | KW_CONST formal_parameter_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_const); -} - | KW_VOLATILE formal_parameter_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_volatile); -} - | KW_RESTRICT formal_parameter_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_restrict); -} - | '*' optional_attributes formal_parameter_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_pointer, $2); -} - | '&' optional_attributes formal_parameter_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_reference, $2); -} - | ANDAND optional_attributes formal_parameter_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_rvalue_reference, $2); -} - | SCOPING '*' optional_attributes formal_parameter_identifier %prec UNARY -{ - $$ = $4; - $$->add_scoped_pointer_modifier($1, $3); -} - | formal_parameter_identifier '[' optional_const_expr ']' optional_attributes -{ - $$ = $1; - $$->add_array_modifier($3, $5); -} - | '(' formal_parameter_identifier ')' '(' function_parameter_list ')' function_post optional_attributes -{ - $$ = $2; - $$->add_modifier(IIT_paren); - $$->add_func_modifier($5, $7, nullptr, $8); -} - | '(' formal_parameter_identifier ')' -{ - $$ = $2; - $$->add_modifier(IIT_paren); -} - ; - -parameter_pack_identifier: - ELLIPSIS -{ - $$ = new CPPInstanceIdentifier(nullptr); - $$->_packed = true; -} - | ELLIPSIS name optional_attributes -{ - $$ = new CPPInstanceIdentifier($2, $3); - $$->_packed = true; -} - | KW_CONST parameter_pack_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_const); -} - | KW_VOLATILE parameter_pack_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_volatile); -} - | KW_RESTRICT parameter_pack_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_restrict); -} - | '*' optional_attributes parameter_pack_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_pointer, $2); -} - | '&' optional_attributes parameter_pack_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_reference, $2); -} - | ANDAND optional_attributes parameter_pack_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_rvalue_reference, $2); -} - | SCOPING '*' optional_attributes parameter_pack_identifier %prec UNARY -{ - $$ = $4; - $$->add_scoped_pointer_modifier($1, $3); -} - | parameter_pack_identifier '[' optional_const_expr ']' optional_attributes -{ - $$ = $1; - $$->add_array_modifier($3, $5); -} - | '(' parameter_pack_identifier ')' '(' function_parameter_list ')' function_post optional_attributes -{ - $$ = $2; - $$->add_modifier(IIT_paren); - $$->add_func_modifier($5, $7, nullptr, $8); -} - | '(' parameter_pack_identifier ')' -{ - $$ = $2; - $$->add_modifier(IIT_paren); -} - ; - -not_paren_empty_instance_identifier: - empty -{ - $$ = new CPPInstanceIdentifier(nullptr); -} - | ELLIPSIS -{ - $$ = new CPPInstanceIdentifier(nullptr); - $$->_packed = true; -} - | ELLIPSIS name optional_attributes -{ - $$ = new CPPInstanceIdentifier($2, $3); - $$->_packed = true; -} - | KW_CONST not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_const); -} - | KW_VOLATILE not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_volatile); -} - | KW_RESTRICT not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_restrict); -} - | '*' optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_pointer, $2); -} - | '&' optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_reference, $2); -} - | ANDAND optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_rvalue_reference, $2); -} - | SCOPING '*' optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $4; - $$->add_scoped_pointer_modifier($1, $3); -} - | not_paren_empty_instance_identifier '[' optional_const_expr ']' optional_attributes -{ - $$ = $1; - $$->add_array_modifier($3, $5); -} - ; - -empty_instance_identifier: - empty -{ - $$ = new CPPInstanceIdentifier(nullptr); -} - | ELLIPSIS -{ - $$ = new CPPInstanceIdentifier(nullptr); - $$->_packed = true; -} - | ELLIPSIS name optional_attributes -{ - $$ = new CPPInstanceIdentifier($2, $3); - $$->_packed = true; -} - | KW_CONST empty_instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_const); -} - | KW_VOLATILE empty_instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_volatile); -} - | KW_RESTRICT empty_instance_identifier %prec UNARY -{ - $$ = $2; - $$->add_modifier(IIT_restrict); -} - | '*' optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_pointer, $2); -} - | '&' optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_reference, $2); -} - | ANDAND optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $3; - $$->add_modifier(IIT_rvalue_reference, $2); -} - | SCOPING '*' optional_attributes not_paren_empty_instance_identifier %prec UNARY -{ - $$ = $4; - $$->add_scoped_pointer_modifier($1, $3); -} - | not_paren_empty_instance_identifier '[' optional_const_expr ']' optional_attributes -{ - $$ = $1; - $$->add_array_modifier($3, $5); -} - | '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type -{ - $$ = new CPPInstanceIdentifier(nullptr); - $$->add_modifier(IIT_paren); - $$->add_func_modifier($2, $4, $6, $5); -} - | '(' '*' optional_attributes not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type -{ - $$ = $4; - $$->add_modifier(IIT_pointer, $3); - $$->add_modifier(IIT_paren); - $$->add_func_modifier($7, $9, $11, $10); -} - | '(' '&' optional_attributes not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type -{ - $$ = $4; - $$->add_modifier(IIT_reference, $3); - $$->add_modifier(IIT_paren); - $$->add_func_modifier($7, $9, $11, $10); -} - | '(' ANDAND optional_attributes not_paren_empty_instance_identifier ')' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type -{ - $$ = $4; - $$->add_modifier(IIT_rvalue_reference, $3); - $$->add_modifier(IIT_paren); - $$->add_func_modifier($7, $9, $11, $10); -} - ; - -type: - simple_type -{ - $$ = CPPType::new_type($1); -} - | TYPENAME_IDENTIFIER -{ - $$ = $1->find_type(current_scope, global_scope, false, current_lexer); - if ($$ == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert($$ != nullptr); -} - | KW_TYPENAME name -{ - $$ = CPPType::new_type(new CPPTBDType($2)); -} - | anonymous_struct -{ - $$ = CPPType::new_type($1); -} - | named_struct -{ - $$ = CPPType::new_type($1); -} - | enum -{ - $$ = CPPType::new_type($1); -} - | struct_keyword optional_attributes name -{ - CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - $$ = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file, $2)) - ->as_extension_type(); - CPPScope *scope = $3->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - $$ = et; - } -} - | enum_keyword optional_attributes name_no_final ':' enum_element_type -{ - CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - $$ = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file, $2)) - ->as_extension_type(); - CPPScope *scope = $3->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - $$ = et; - } -} - | KW_DECLTYPE '(' const_expr ')' -{ - $$ = $3->determine_type(); - if ($$ == nullptr) { - stringstream str; - str << *$3; - yyerror("could not determine type of " + str.str(), @3); - } -} - | KW_DECLTYPE '(' KW_AUTO ')' -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} - | KW_UNDERLYING_TYPE '(' full_type ')' -{ - CPPEnumType *enum_type = $3->as_enum_type(); - if (enum_type == nullptr) { - yyerror("an enumeration type is required", @3); - $$ = $3; - } else { - $$ = enum_type->get_underlying_type(); - } -} - | KW_AUTO -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} - | KW_BUILTIN_VA_LIST -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_va_list)); -} - ; - -type_pack: - TYPEPACK_IDENTIFIER -{ - $$ = $1->find_type(current_scope, global_scope, false, current_lexer); - if ($$ == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert($$ != nullptr); -} - ; - -type_decl: - simple_type -{ - $$ = CPPType::new_type($1); -} - | TYPENAME_IDENTIFIER -{ - $$ = $1->find_type(current_scope, global_scope, false, current_lexer); - if ($$ == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert($$ != nullptr); -} - | KW_TYPENAME name -{ - $$ = CPPType::new_type(new CPPTBDType($2)); -} - | anonymous_struct -{ - $$ = CPPType::new_type($1); -} - | named_struct -{ - $$ = new CPPTypeDeclaration(CPPType::new_type($1)); -} - | enum -{ - $$ = new CPPTypeDeclaration(CPPType::new_type($1)); -} - | struct_keyword optional_attributes name -{ - CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - $$ = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file, $2)) - ->as_extension_type(); - CPPScope *scope = $3->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - $$ = et; - } -} - | enum_keyword optional_attributes name_no_final ':' enum_element_type -{ - CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - $$ = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file, $2)) - ->as_extension_type(); - CPPScope *scope = $3->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - $$ = et; - } -} - | enum_keyword optional_attributes name -{ - yywarning(string("C++ does not permit forward declaration of untyped enum ") + $3->get_fully_scoped_name(), @1); - - CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - $$ = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file, $2)) - ->as_extension_type(); - CPPScope *scope = $3->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - $$ = et; - } -} - | KW_DECLTYPE '(' const_expr ')' -{ - $$ = $3->determine_type(); - if ($$ == nullptr) { - stringstream str; - str << *$3; - yyerror("could not determine type of " + str.str(), @3); - } -} - | KW_DECLTYPE '(' KW_AUTO ')' -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} - | KW_UNDERLYING_TYPE '(' full_type ')' -{ - CPPEnumType *enum_type = $3->as_enum_type(); - if (enum_type == nullptr) { - yyerror("an enumeration type is required", @3); - $$ = $3; - } else { - $$ = enum_type->get_underlying_type(); - } -} - | KW_AUTO -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} - | KW_BUILTIN_VA_LIST -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_va_list)); -} - ; - -predefined_type: - simple_type -{ - $$ = CPPType::new_type($1); -} - | TYPENAME_IDENTIFIER -{ - $$ = $1->find_type(current_scope, global_scope, false, current_lexer); - if ($$ == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert($$ != nullptr); -} - | KW_TYPENAME name -{ - $$ = CPPType::new_type(new CPPTBDType($2)); -} - | struct_keyword optional_attributes name -{ - CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - $$ = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file, $2)) - ->as_extension_type(); - CPPScope *scope = $3->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - $$ = et; - } -} - | enum_keyword optional_attributes name -{ - CPPType *type = $3->find_type(current_scope, global_scope, false, current_lexer); - if (type != nullptr) { - $$ = type; - } else { - CPPExtensionType *et = - CPPType::new_type(new CPPExtensionType($1, $3, current_scope, @1.file, $2)) - ->as_extension_type(); - CPPScope *scope = $3->get_scope(current_scope, global_scope); - if (scope != nullptr) { - scope->define_extension_type(et); - } - $$ = et; - } -} - | KW_DECLTYPE '(' const_expr ')' -{ - $$ = $3->determine_type(); - if ($$ == nullptr) { - stringstream str; - str << *$3; - yyerror("could not determine type of " + str.str(), @3); - } -} - | KW_UNDERLYING_TYPE '(' full_type ')' -{ - CPPEnumType *enum_type = $3->as_enum_type(); - if (enum_type == nullptr) { - yyerror("an enumeration type is required", @3); - $$ = $3; - } else { - $$ = enum_type->get_underlying_type(); - } -} - | KW_AUTO -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_auto)); -} - | KW_BUILTIN_VA_LIST -{ - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_va_list)); -} - ; - -var_type_decl: - type_decl -{ - $$ = $1; -} - | IDENTIFIER -{ - yyerror(string("unknown type '") + $1->get_fully_scoped_name() + "'", @1); - - $$ = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); -} - -full_type: - type empty_instance_identifier -{ - $$ = $2->unroll_type($1); -} - | KW_CONST type empty_instance_identifier -{ - $3->add_modifier(IIT_const); - $$ = $3->unroll_type($2); -} - | type_pack empty_instance_identifier -{ - $$ = $2->unroll_type($1); -} - | KW_CONST type_pack empty_instance_identifier -{ - $3->add_modifier(IIT_const); - $$ = $3->unroll_type($2); -} - ; - -anonymous_struct: - struct_keyword optional_attributes '{' -{ - CPPVisibility starting_vis = - ($1 == CPPExtensionType::T_class) ? V_private : V_public; - - CPPScope *new_scope = new CPPScope(current_scope, CPPNameComponent("anon"), - starting_vis); - CPPStructType *st = new CPPStructType($1, nullptr, current_scope, - new_scope, @1.file, $2); - new_scope->set_struct_type(st); - - push_scope(new_scope); - push_struct(st); -} - cpp '}' -{ - $$ = current_struct; - current_struct->_incomplete = false; - pop_struct(); - pop_scope(); -} - ; - -named_struct: - struct_keyword optional_attributes name_no_final -{ - CPPVisibility starting_vis = - ($1 == CPPExtensionType::T_class) ? V_private : V_public; - - CPPScope *scope = $3->get_scope(current_scope, global_scope, current_lexer); - if (scope == nullptr) { - scope = current_scope; - } - CPPScope *new_scope = new CPPScope(scope, $3->_names.back(), - starting_vis); - - CPPStructType *st = new CPPStructType($1, $3, current_scope, - new_scope, @1.file, $2); - new_scope->set_struct_type(st); - current_scope->define_extension_type(st); - - push_scope(new_scope); - push_struct(st); -} - maybe_final maybe_class_derivation '{' cpp '}' -{ - $$ = current_struct; - current_struct->_incomplete = false; - pop_struct(); - pop_scope(); -} - ; - -maybe_final: - empty - | KW_FINAL -{ - current_struct->_final = true; -} - ; - -maybe_class_derivation: - empty - | class_derivation - ; - -class_derivation: - ':' base_specification - | class_derivation ',' base_specification - ; - -base_specification: - class_derivation_name -{ - current_struct->append_derivation($1, V_unknown, false); -} - | KW_PUBLIC class_derivation_name -{ - current_struct->append_derivation($2, V_public, false); -} - | KW_PROTECTED class_derivation_name -{ - current_struct->append_derivation($2, V_protected, false); -} - | KW_PRIVATE class_derivation_name -{ - current_struct->append_derivation($2, V_private, false); -} - | KW_VIRTUAL KW_PUBLIC class_derivation_name -{ - current_struct->append_derivation($3, V_public, true); -} - | KW_VIRTUAL KW_PROTECTED class_derivation_name -{ - current_struct->append_derivation($3, V_protected, true); -} - | KW_VIRTUAL KW_PRIVATE class_derivation_name -{ - current_struct->append_derivation($3, V_private, true); -} - | KW_PUBLIC KW_VIRTUAL class_derivation_name -{ - current_struct->append_derivation($3, V_public, true); -} - | KW_PROTECTED KW_VIRTUAL class_derivation_name -{ - current_struct->append_derivation($3, V_protected, true); -} - | KW_PRIVATE KW_VIRTUAL class_derivation_name -{ - current_struct->append_derivation($3, V_private, true); -} - ; - -enum: - enum_decl -{ - if (current_enum->_scope != nullptr) { - push_scope(current_enum->_scope); - } -} - '{' enum_body '}' -{ - if (current_enum->_scope != nullptr) { - pop_scope(); - } - $$ = current_enum; - current_enum = nullptr; -} - ; - -enum_decl: - enum_keyword optional_attributes ':' enum_element_type -{ - current_enum = new CPPEnumType($1, nullptr, $4, current_scope, nullptr, @1.file, $2); -} - | enum_keyword optional_attributes -{ - current_enum = new CPPEnumType($1, nullptr, current_scope, nullptr, @1.file, $2); -} - | enum_keyword optional_attributes name_no_final ':' enum_element_type -{ - CPPScope *new_scope = new CPPScope(current_scope, $3->_names.back(), V_public); - current_enum = new CPPEnumType($1, $3, $5, current_scope, new_scope, @1.file, $2); -} - | enum_keyword optional_attributes name_no_final -{ - CPPScope *new_scope = new CPPScope(current_scope, $3->_names.back(), V_public); - current_enum = new CPPEnumType($1, $3, current_scope, new_scope, @1.file, $2); -} - ; - -enum_element_type: - simple_int_type -{ - $$ = CPPType::new_type($1); -} - | TYPENAME_IDENTIFIER -{ - $$ = $1->find_type(current_scope, global_scope, false, current_lexer); -} - ; - -enum_body_trailing_comma: - empty - | enum_body_trailing_comma name optional_attributes ',' -{ - assert(current_enum != nullptr); - current_enum->add_element($2->get_simple_name(), nullptr, current_lexer, @2, $3); -} - | enum_body_trailing_comma name optional_attributes '=' const_expr ',' -{ - assert(current_enum != nullptr); - current_enum->add_element($2->get_simple_name(), $5, current_lexer, @2, $3); -}; - -enum_body: - enum_body_trailing_comma - | enum_body_trailing_comma name optional_attributes -{ - assert(current_enum != nullptr); - current_enum->add_element($2->get_simple_name(), nullptr, current_lexer, @2, $3); -} - | enum_body_trailing_comma name optional_attributes '=' const_expr -{ - assert(current_enum != nullptr); - current_enum->add_element($2->get_simple_name(), $5, current_lexer, @2, $3); -} - ; - -enum_keyword: - KW_ENUM -{ - $$ = CPPExtensionType::T_enum; -} - | KW_ENUM KW_CLASS -{ - $$ = CPPExtensionType::T_enum_class; -} - | KW_ENUM KW_STRUCT -{ - $$ = CPPExtensionType::T_enum_struct; -} - ; - -struct_keyword: - KW_CLASS -{ - $$ = CPPExtensionType::T_class; -} - | KW_STRUCT -{ - $$ = CPPExtensionType::T_struct; -} - | KW_UNION -{ - $$ = CPPExtensionType::T_union; -} - ; - -namespace_declaration: - KW_NAMESPACE optional_attributes name '{' -{ - CPPScope *scope = $3->find_scope(current_scope, global_scope, current_lexer); - if (scope == nullptr) { - // This must be a new namespace declaration. - CPPScope *parent_scope = - $3->get_scope(current_scope, global_scope, current_lexer); - if (parent_scope == nullptr) { - parent_scope = current_scope; - } - scope = new CPPScope(parent_scope, $3->_names.back(), V_public); - } - - CPPNamespace *nspace = new CPPNamespace($3, scope, @1.file, $2); - current_scope->add_declaration(nspace, global_scope, current_lexer, @1); - current_scope->define_namespace(nspace); - push_scope(scope); -} - cpp '}' -{ - pop_scope(); -} - | KW_INLINE KW_NAMESPACE name '{' -{ - CPPScope *scope = $3->find_scope(current_scope, global_scope, current_lexer); - if (scope == nullptr) { - // This must be a new namespace declaration. - CPPScope *parent_scope = - $3->get_scope(current_scope, global_scope, current_lexer); - if (parent_scope == nullptr) { - parent_scope = current_scope; - } - scope = new CPPScope(parent_scope, $3->_names.back(), V_public); - } - - CPPNamespace *nspace = new CPPNamespace($3, scope, @2.file); - nspace->_is_inline = true; - current_scope->add_declaration(nspace, global_scope, current_lexer, @2); - current_scope->define_namespace(nspace); - push_scope(scope); -} - cpp '}' -{ - pop_scope(); -} - | KW_NAMESPACE '{' cpp '}' - | KW_INLINE KW_NAMESPACE '{' cpp '}' - ; - -using_declaration: - KW_USING name ';' -{ - CPPUsing *using_decl = new CPPUsing($2, false, @1.file); - current_scope->add_declaration(using_decl, global_scope, current_lexer, @1); - current_scope->add_using(using_decl, global_scope, current_lexer); -} - | KW_USING name optional_attributes '=' full_type ';' -{ - // This is really just an alternative way to declare a typedef. - CPPTypedefType *typedef_type = new CPPTypedefType($5, $2, current_scope, $3); - typedef_type->_using = true; - current_scope->add_declaration(CPPType::new_type(typedef_type), global_scope, current_lexer, @1); -} - | KW_USING KW_NAMESPACE name ';' -{ - CPPUsing *using_decl = new CPPUsing($3, true, @1.file); - current_scope->add_declaration(using_decl, global_scope, current_lexer, @1); - current_scope->add_using(using_decl, global_scope, current_lexer); -} - | KW_USING KW_ENUM name ';' -{ - CPPUsing *using_decl = new CPPUsing($3, false, @1.file); - current_scope->add_declaration(using_decl, global_scope, current_lexer, @1); - current_scope->add_using(using_decl, global_scope, current_lexer); -} - ; - -simple_type: - simple_int_type - | simple_float_type - | simple_void_type - ; - -simple_int_type: - KW_BOOL -{ - $$ = new CPPSimpleType(CPPSimpleType::T_bool); -} - | KW_CHAR -{ - $$ = new CPPSimpleType(CPPSimpleType::T_char); -} - | KW_WCHAR_T -{ - $$ = new CPPSimpleType(CPPSimpleType::T_wchar_t); -} - | KW_CHAR8_T -{ - $$ = new CPPSimpleType(CPPSimpleType::T_char8_t); -} - | KW_CHAR16_T -{ - $$ = new CPPSimpleType(CPPSimpleType::T_char16_t); -} - | KW_CHAR32_T -{ - $$ = new CPPSimpleType(CPPSimpleType::T_char32_t); -} - | KW_SHORT -{ - $$ = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_short); -} - | KW_LONG -{ - $$ = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_long); -} - | KW_UNSIGNED -{ - $$ = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_unsigned); -} - | KW_SIGNED -{ - $$ = new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_signed); -} - | KW_INT -{ - $$ = new CPPSimpleType(CPPSimpleType::T_int); -} - | KW_SHORT simple_int_type -{ - $$ = $2; - $$->_flags |= CPPSimpleType::F_short; -} - | KW_LONG simple_int_type -{ - $$ = $2; - if ($$->_flags & CPPSimpleType::F_long) { - $$->_flags |= CPPSimpleType::F_longlong; - } else { - $$->_flags |= CPPSimpleType::F_long; - } -} - | KW_UNSIGNED simple_int_type -{ - $$ = $2; - $$->_flags |= CPPSimpleType::F_unsigned; -} - | KW_SIGNED simple_int_type -{ - $$ = $2; - $$->_flags |= CPPSimpleType::F_signed; -} - ; - -simple_float_type: - KW_FLOAT -{ - $$ = new CPPSimpleType(CPPSimpleType::T_float); -} - | KW_DOUBLE -{ - $$ = new CPPSimpleType(CPPSimpleType::T_double); -} - | KW_LONG KW_DOUBLE -{ - $$ = new CPPSimpleType(CPPSimpleType::T_double, - CPPSimpleType::F_long); -} - ; - -simple_void_type: - KW_VOID -{ - $$ = new CPPSimpleType(CPPSimpleType::T_void); -} - ; - -/* We don't care what the code is. We just want to be sure we match - up opening and closing braces properly. For anything else, we'll - accept just token salad. */ -code: -{ - current_lexer->_resolve_identifiers = false; -} - code_block -{ - current_lexer->_resolve_identifiers = true; -} - ; - -code_block: - empty - | code_block element - ; - -element: - REAL - | INTEGER - | SIMPLE_STRING - | STRING_LITERAL - | CUSTOM_LITERAL - | CHAR_TOK - | IDENTIFIER - | TYPENAME_IDENTIFIER - | TYPEPACK_IDENTIFIER - | SCOPING - | SIMPLE_IDENTIFIER - | ELLIPSIS | OROR | ANDAND - | EQCOMPARE | NECOMPARE | LECOMPARE | GECOMPARE | SPACESHIP - | LSHIFT | RSHIFT | POINTSAT_STAR | DOT_STAR | POINTSAT - | SCOPE | PLUSPLUS | MINUSMINUS - | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL - | OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL - | ATTR_LEFT | ATTR_RIGHT - | KW_ALIGNAS | KW_ALIGNOF | KW_AUTO | KW_BOOL | KW_BUILTIN_VA_LIST - | KW_CATCH | KW_CHAR | KW_CHAR8_T | KW_CHAR16_T | KW_CHAR32_T | KW_CLASS - | KW_CONST | KW_CONSTEVAL | KW_CONSTEXPR | KW_CONSTINIT | KW_CONST_CAST - | KW_DECLTYPE | KW_DEFAULT | KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST - | KW_ELSE | KW_ENUM | KW_EXTERN | KW_EXPLICIT | KW_EXPLICIT_LPAREN - | KW_FALSE | KW_FINAL | KW_FLOAT | KW_FRIEND | KW_FOR - | KW_GOTO | KW_IF | KW_INLINE | KW_INT | KW_LONG | KW_MUTABLE - | KW_NAMESPACE | KW_NEW | KW_NOEXCEPT | KW_NOEXCEPT_LPAREN | KW_NULLPTR - | KW_OPERATOR | KW_OVERRIDE | KW_PRIVATE | KW_PROTECTED - | KW_PUBLIC | KW_PUBLISHED | KW_REGISTER | KW_REINTERPRET_CAST - | KW_RESTRICT | KW_RETURN | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC - | KW_STATIC_ASSERT | KW_STATIC_CAST | KW_STRUCT | KW_TEMPLATE - | KW_THREAD_LOCAL | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF - | KW_TYPEID | KW_TYPENAME | KW_UNDERLYING_TYPE | KW_UNION - | KW_UNSIGNED | KW_USING | KW_VIRTUAL | KW_VOID | KW_VOLATILE - | KW_WCHAR_T | KW_WHILE -{ -} - | '+' | '-' | '*' | '/' | '&' | '|' | '^' | '!' | '~' | '=' | '%' - | '<' | '>' | '(' | ')' | '.' | ',' | ';' | ':' | '[' | ']' - | '?' | '{' code_block '}' - ; - -optional_const_expr: - empty -{ - $$ = nullptr; -} - | const_expr -{ - $$ = $1; -} - ; - -optional_const_expr_comma: - empty -{ - $$ = nullptr; -} - | const_expr_comma -{ - $$ = $1; -} - ; - -const_expr_comma: - const_expr -{ - $$ = $1; -} - | const_expr_comma ',' const_expr -{ - $$ = new CPPExpression(',', $1, $3); -} - ; - -no_angle_bracket_const_expr: - const_operand -{ - $$ = $1; -} - | '(' full_type ')' no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::typecast_op($2, $4)); -} - | KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_static_cast)); -} - | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_dynamic_cast)); -} - | KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_const_cast)); -} - | KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_reinterpret_cast)); -} - | KW_SIZEOF '(' full_type ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_func($3)); -} - | KW_SIZEOF no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_func($2)); -} - | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4)); -} - | KW_ALIGNOF '(' full_type ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::alignof_func($3)); -} - | '!' no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_NOT, $2); -} - | '~' no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_NEGATE, $2); -} - | '-' no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_MINUS, $2); -} - | '+' no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_PLUS, $2); -} - | '*' no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_STAR, $2); -} - | '&' no_angle_bracket_const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_REF, $2); -} - | no_angle_bracket_const_expr '*' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('*', $1, $3); -} - | no_angle_bracket_const_expr '/' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('/', $1, $3); -} - | no_angle_bracket_const_expr '%' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('%', $1, $3); -} - | no_angle_bracket_const_expr '+' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('+', $1, $3); -} - | no_angle_bracket_const_expr '-' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('-', $1, $3); -} - | no_angle_bracket_const_expr '|' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('|', $1, $3); -} - | no_angle_bracket_const_expr '^' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('^', $1, $3); -} - | no_angle_bracket_const_expr '&' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('&', $1, $3); -} - | no_angle_bracket_const_expr OROR no_angle_bracket_const_expr -{ - $$ = new CPPExpression(OROR, $1, $3); -} - | no_angle_bracket_const_expr ANDAND no_angle_bracket_const_expr -{ - $$ = new CPPExpression(ANDAND, $1, $3); -} - | no_angle_bracket_const_expr EQCOMPARE no_angle_bracket_const_expr -{ - $$ = new CPPExpression(EQCOMPARE, $1, $3); -} - | no_angle_bracket_const_expr NECOMPARE no_angle_bracket_const_expr -{ - $$ = new CPPExpression(NECOMPARE, $1, $3); -} - | no_angle_bracket_const_expr LECOMPARE no_angle_bracket_const_expr -{ - $$ = new CPPExpression(LECOMPARE, $1, $3); -} - | no_angle_bracket_const_expr GECOMPARE no_angle_bracket_const_expr -{ - $$ = new CPPExpression(GECOMPARE, $1, $3); -} - | no_angle_bracket_const_expr SPACESHIP no_angle_bracket_const_expr -{ - $$ = new CPPExpression(SPACESHIP, $1, $3); -} - | no_angle_bracket_const_expr LSHIFT no_angle_bracket_const_expr -{ - $$ = new CPPExpression(LSHIFT, $1, $3); -} - | no_angle_bracket_const_expr RSHIFT no_angle_bracket_const_expr -{ - $$ = new CPPExpression(RSHIFT, $1, $3); -} - | no_angle_bracket_const_expr '?' no_angle_bracket_const_expr ':' no_angle_bracket_const_expr -{ - $$ = new CPPExpression('?', $1, $3, $5); -} - | no_angle_bracket_const_expr '[' const_expr ']' -{ - $$ = new CPPExpression('[', $1, $3); -} - | no_angle_bracket_const_expr '(' const_expr_comma ')' -{ - $$ = new CPPExpression('f', $1, $3); -} - | no_angle_bracket_const_expr '(' ')' -{ - $$ = new CPPExpression('f', $1); -} - | no_angle_bracket_const_expr '.' name -{ - $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer)); -} - | no_angle_bracket_const_expr POINTSAT no_angle_bracket_const_expr -{ - $$ = new CPPExpression(POINTSAT, $1, $3); -} - | '(' const_expr_comma ')' -{ - $$ = $2; -} - ; - - -const_expr: - const_operand -{ - $$ = $1; -} - | '(' full_type ')' const_expr %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::typecast_op($2, $4)); -} - | KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_static_cast)); -} - | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_dynamic_cast)); -} - | KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_const_cast)); -} - | KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_reinterpret_cast)); -} - | TYPENAME_IDENTIFIER '(' optional_const_expr_comma ')' -{ - // A constructor call. - CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert(type != nullptr); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | TYPENAME_IDENTIFIER '{' optional_const_expr_comma '}' -{ - // Aggregate initialization. - CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); - if (type == nullptr) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert(type != nullptr); - $$ = new CPPExpression(CPPExpression::aggregate_init_op(type, $3)); -} - | KW_INT '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_CHAR '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_WCHAR_T '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_CHAR8_T '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char8_t)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_CHAR16_T '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_CHAR32_T '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_BOOL '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_SHORT '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_short)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_LONG '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_long)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_UNSIGNED '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_unsigned)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_SIGNED '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_signed)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_FLOAT '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_float)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_DOUBLE '(' optional_const_expr_comma ')' -{ - CPPType *type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double)); - $$ = new CPPExpression(CPPExpression::construct_op(type, $3)); -} - | KW_SIZEOF '(' full_type ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_func($3)); -} - | KW_SIZEOF const_expr %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_func($2)); -} - | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4)); -} - | KW_ALIGNOF '(' full_type ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::alignof_func($3)); -} - | KW_NEW predefined_type %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::new_op($2)); -} - | KW_NEW predefined_type '(' optional_const_expr_comma ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::new_op($2, $4)); -} - | KW_TYPEID '(' full_type ')' -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", @1); - } - $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); -} - | KW_TYPEID '(' const_expr ')' -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", @1); - } - $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); -} - | '!' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_NOT, $2); -} - | '~' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_NEGATE, $2); -} - | '-' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_MINUS, $2); -} - | '+' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_PLUS, $2); -} - | '*' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_STAR, $2); -} - | '&' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_REF, $2); -} - | const_expr '*' const_expr -{ - $$ = new CPPExpression('*', $1, $3); -} - | const_expr '/' const_expr -{ - $$ = new CPPExpression('/', $1, $3); -} - | const_expr '%' const_expr -{ - $$ = new CPPExpression('%', $1, $3); -} - | const_expr '+' const_expr -{ - $$ = new CPPExpression('+', $1, $3); -} - | const_expr '-' const_expr -{ - $$ = new CPPExpression('-', $1, $3); -} - | const_expr '|' const_expr -{ - $$ = new CPPExpression('|', $1, $3); -} - | const_expr '^' const_expr -{ - $$ = new CPPExpression('^', $1, $3); -} - | const_expr '&' const_expr -{ - $$ = new CPPExpression('&', $1, $3); -} - | const_expr OROR const_expr -{ - $$ = new CPPExpression(OROR, $1, $3); -} - | const_expr ANDAND const_expr -{ - $$ = new CPPExpression(ANDAND, $1, $3); -} - | const_expr EQCOMPARE const_expr -{ - $$ = new CPPExpression(EQCOMPARE, $1, $3); -} - | const_expr NECOMPARE const_expr -{ - $$ = new CPPExpression(NECOMPARE, $1, $3); -} - | const_expr LECOMPARE const_expr -{ - $$ = new CPPExpression(LECOMPARE, $1, $3); -} - | const_expr GECOMPARE const_expr -{ - $$ = new CPPExpression(GECOMPARE, $1, $3); -} - | const_expr SPACESHIP const_expr -{ - $$ = new CPPExpression(SPACESHIP, $1, $3); -} - | const_expr '<' const_expr -{ - $$ = new CPPExpression('<', $1, $3); -} - | const_expr '>' const_expr -{ - $$ = new CPPExpression('>', $1, $3); -} - | const_expr LSHIFT const_expr -{ - $$ = new CPPExpression(LSHIFT, $1, $3); -} - | const_expr RSHIFT const_expr -{ - $$ = new CPPExpression(RSHIFT, $1, $3); -} - | const_expr '?' const_expr ':' const_expr -{ - $$ = new CPPExpression('?', $1, $3, $5); -} - | const_expr '[' const_expr ']' -{ - $$ = new CPPExpression('[', $1, $3); -} - | const_expr '(' const_expr_comma ')' -{ - $$ = new CPPExpression('f', $1, $3); -} - | const_expr '(' ')' -{ - $$ = new CPPExpression('f', $1); -} - | KW_NOEXCEPT_LPAREN const_expr ')' -{ - $$ = new CPPExpression(KW_NOEXCEPT, $2); -} - | const_expr '.' name -{ - $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer)); -} - | const_expr POINTSAT const_expr -{ - $$ = new CPPExpression(POINTSAT, $1, $3); -} - | '(' const_expr_comma ')' -{ - $$ = $2; -} - ; - -const_operand: - INTEGER -{ - $$ = new CPPExpression($1); -} - | KW_TRUE -{ - $$ = new CPPExpression(true); -} - | KW_FALSE -{ - $$ = new CPPExpression(false); -} - | CHAR_TOK -{ - $$ = new CPPExpression($1); -} - | REAL -{ - $$ = new CPPExpression($1); -} - | string_literal -{ - $$ = $1; -} - | CUSTOM_LITERAL -{ - $$ = $1; -} - | IDENTIFIER -{ - $$ = new CPPExpression($1, current_scope, global_scope, current_lexer); -} - | KW_FINAL -{ - // A variable named "final". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("final", @1); - $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} - | KW_OVERRIDE -{ - // A variable named "override". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("override", @1); - $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} - | KW_NULLPTR -{ - $$ = new CPPExpression(CPPExpression::get_nullptr()); -} - | '[' capture_list ']' function_post optional_attributes maybe_trailing_return_type '{' code '}' -{ - $2->_flags = $4; - $2->_attributes = $5; - $2->_return_type = $6; - $$ = new CPPExpression(CPPExpression::lambda($2)); -} - | '[' capture_list ']' '(' function_parameter_list ')' function_post optional_attributes maybe_trailing_return_type '{' code '}' -{ - $2->_parameters = $5; - $2->_flags = $7; - $2->_attributes = $8; - $2->_return_type = $9; - $$ = new CPPExpression(CPPExpression::lambda($2)); -} - | KW_HAS_VIRTUAL_DESTRUCTOR '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_HAS_VIRTUAL_DESTRUCTOR, $3)); -} - | KW_IS_ABSTRACT '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ABSTRACT, $3)); -} - | KW_IS_BASE_OF '(' full_type ',' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3, $5)); -} - | KW_IS_CLASS '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CLASS, $3)); -} - | KW_IS_CONSTRUCTIBLE '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3)); -} - | KW_IS_CONSTRUCTIBLE '(' full_type ',' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONSTRUCTIBLE, $3, $5)); -} - | KW_IS_CONVERTIBLE_TO '(' full_type ',' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_CONVERTIBLE_TO, $3, $5)); -} - | KW_IS_DESTRUCTIBLE '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_DESTRUCTIBLE, $3)); -} - | KW_IS_EMPTY '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_EMPTY, $3)); -} - | KW_IS_ENUM '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_ENUM, $3)); -} - | KW_IS_FINAL '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FINAL, $3)); -} - | KW_IS_FUNDAMENTAL '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_FUNDAMENTAL, $3)); -} - | KW_IS_POD '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POD, $3)); -} - | KW_IS_POLYMORPHIC '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_POLYMORPHIC, $3)); -} - | KW_IS_STANDARD_LAYOUT '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_STANDARD_LAYOUT, $3)); -} - | KW_IS_TRIVIAL '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_TRIVIAL, $3)); -} - | KW_IS_TRIVIALLY_COPYABLE '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_TRIVIALLY_COPYABLE, $3)); -} - | KW_IS_UNION '(' full_type ')' -{ - $$ = new CPPExpression(CPPExpression::type_trait(KW_IS_UNION, $3)); -} - ; - -/* This is used for a const_expr as a "formal parameter", which really - means an instance declaration using a parameter list (which looks a - lot like a function prototype). It differs from const_expr mainly - in that it forbids some expressions unless they are parenthesized, - to avoid shift/reduce conflicts with the actual formal parameter - definition. */ - -formal_const_expr: - formal_const_operand -{ - $$ = $1; -} - | '(' full_type ')' const_expr %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::typecast_op($2, $4)); -} - | KW_STATIC_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_static_cast)); -} - | KW_DYNAMIC_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_dynamic_cast)); -} - | KW_CONST_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_const_cast)); -} - | KW_REINTERPRET_CAST '<' full_type '>' '(' const_expr_comma ')' -{ - $$ = new CPPExpression(CPPExpression::typecast_op($3, $6, CPPExpression::T_reinterpret_cast)); -} - | KW_SIZEOF '(' full_type ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_func($3)); -} - | KW_SIZEOF formal_const_expr %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_func($2)); -} - | KW_SIZEOF ELLIPSIS '(' name ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::sizeof_ellipsis_func($4)); -} - | KW_ALIGNOF '(' full_type ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::alignof_func($3)); -} - | KW_NEW predefined_type %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::new_op($2)); -} - | KW_NEW predefined_type '(' optional_const_expr_comma ')' %prec UNARY -{ - $$ = new CPPExpression(CPPExpression::new_op($2, $4)); -} - | KW_TYPEID '(' full_type ')' -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", @1); - } - $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); -} - | KW_TYPEID '(' const_expr ')' -{ - CPPIdentifier ident(""); - ident.add_name("std"); - ident.add_name("type_info"); - CPPType *std_type_info = ident.find_type(current_scope, global_scope, false, current_lexer); - if (!std_type_info) { - yywarning("cannot use typeid before including ", @1); - } - $$ = new CPPExpression(CPPExpression::typeid_op($3, std_type_info)); -} - | '!' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_NOT, $2); -} - | '~' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_NEGATE, $2); -} - | '-' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_MINUS, $2); -} - | '+' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_PLUS, $2); -} - | '&' const_expr %prec UNARY -{ - $$ = new CPPExpression(UNARY_REF, $2); -} - | formal_const_expr '*' const_expr -{ - $$ = new CPPExpression('*', $1, $3); -} - | formal_const_expr '/' const_expr -{ - $$ = new CPPExpression('/', $1, $3); -} - | formal_const_expr '%' const_expr -{ - $$ = new CPPExpression('%', $1, $3); -} - | formal_const_expr '+' const_expr -{ - $$ = new CPPExpression('+', $1, $3); -} - | formal_const_expr '-' const_expr -{ - $$ = new CPPExpression('-', $1, $3); -} - | formal_const_expr '|' const_expr -{ - $$ = new CPPExpression('|', $1, $3); -} - | formal_const_expr '^' const_expr -{ - $$ = new CPPExpression('^', $1, $3); -} - | formal_const_expr '&' const_expr -{ - $$ = new CPPExpression('&', $1, $3); -} - | formal_const_expr OROR const_expr -{ - $$ = new CPPExpression(OROR, $1, $3); -} - | formal_const_expr ANDAND const_expr -{ - $$ = new CPPExpression(ANDAND, $1, $3); -} - | formal_const_expr EQCOMPARE const_expr -{ - $$ = new CPPExpression(EQCOMPARE, $1, $3); -} - | formal_const_expr NECOMPARE const_expr -{ - $$ = new CPPExpression(NECOMPARE, $1, $3); -} - | formal_const_expr LECOMPARE const_expr -{ - $$ = new CPPExpression(LECOMPARE, $1, $3); -} - | formal_const_expr GECOMPARE const_expr -{ - $$ = new CPPExpression(GECOMPARE, $1, $3); -} - | formal_const_expr SPACESHIP const_expr -{ - $$ = new CPPExpression(SPACESHIP, $1, $3); -} - | formal_const_expr '<' const_expr -{ - $$ = new CPPExpression('<', $1, $3); -} - | formal_const_expr '>' const_expr -{ - $$ = new CPPExpression('>', $1, $3); -} - | formal_const_expr LSHIFT const_expr -{ - $$ = new CPPExpression(LSHIFT, $1, $3); -} - | formal_const_expr RSHIFT const_expr -{ - $$ = new CPPExpression(RSHIFT, $1, $3); -} - | formal_const_expr '?' const_expr ':' const_expr -{ - $$ = new CPPExpression('?', $1, $3, $5); -} - | formal_const_expr '[' const_expr ']' -{ - $$ = new CPPExpression('[', $1, $3); -} - | formal_const_expr '(' const_expr_comma ')' -{ - $$ = new CPPExpression('f', $1, $3); -} - | formal_const_expr '(' ')' -{ - $$ = new CPPExpression('f', $1); -} - | formal_const_expr '.' name -{ - $$ = new CPPExpression('.', $1, new CPPExpression($3, current_scope, global_scope, current_lexer)); -} - | formal_const_expr POINTSAT const_expr -{ - $$ = new CPPExpression(POINTSAT, $1, $3); -} - | '(' const_expr_comma ')' -{ - $$ = $2; -} - ; - -formal_const_operand: - INTEGER -{ - $$ = new CPPExpression($1); -} - | KW_TRUE -{ - $$ = new CPPExpression(true); -} - | KW_FALSE -{ - $$ = new CPPExpression(false); -} - | CHAR_TOK -{ - $$ = new CPPExpression($1); -} - | REAL -{ - $$ = new CPPExpression($1); -} - | string_literal -{ - $$ = $1; -} - | CUSTOM_LITERAL -{ - $$ = $1; -} - | IDENTIFIER -{ - $$ = new CPPExpression($1, current_scope, global_scope, current_lexer); -} - | KW_FINAL -{ - // A variable named "final". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("final", @1); - $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} - | KW_OVERRIDE -{ - // A variable named "override". C++11 explicitly permits this. - CPPIdentifier *ident = new CPPIdentifier("override", @1); - $$ = new CPPExpression(ident, current_scope, global_scope, current_lexer); -} - | KW_NULLPTR -{ - $$ = new CPPExpression(CPPExpression::get_nullptr()); -} - ; - -/* The contents of the [] list preceding a lambda expression. */ -capture_list: - empty -{ - $$ = new CPPClosureType(); -} - | '=' -{ - $$ = new CPPClosureType(CPPClosureType::CT_by_value); -} - | '&' -{ - $$ = new CPPClosureType(CPPClosureType::CT_by_reference); -} - | capture maybe_initialize -{ - $$ = new CPPClosureType(); - $1->_initializer = $2; - $$->_captures.push_back(*$1); - delete $1; -} - | capture_list ',' capture maybe_initialize -{ - $$ = $1; - $3->_initializer = $4; - $$->_captures.push_back(*$3); - delete $3; -} - ; - -capture: - '&' name -{ - $$ = new CPPClosureType::Capture; - $$->_name = $2->get_simple_name(); - $$->_type = CPPClosureType::CT_by_reference; -} - | '&' name ELLIPSIS -{ - $$ = new CPPClosureType::Capture; - $$->_name = $2->get_simple_name(); - $$->_type = CPPClosureType::CT_by_reference; -} - | name -{ - $$ = new CPPClosureType::Capture; - $$->_name = $1->get_simple_name(); - if ($$->_name == "this") { - $$->_type = CPPClosureType::CT_by_reference; - } else { - $$->_type = CPPClosureType::CT_by_value; - } -} - | '*' name -{ - $$ = new CPPClosureType::Capture; - $$->_name = $2->get_simple_name(); - $$->_type = CPPClosureType::CT_by_value; - if ($$->_name != "this") { - yywarning("only capture name 'this' may be preceded by an asterisk", @2); - } -} - ; - -class_derivation_name: - name -{ - CPPType *type = $1->find_type(current_scope, global_scope, true); - if (type == nullptr) { - type = CPPType::new_type(new CPPTBDType($1)); - } - $$ = type; -} - | KW_TYPENAME name -{ - $$ = CPPType::new_type(new CPPTBDType($2)); -} - | name ELLIPSIS -{ - CPPClassTemplateParameter *ctp = new CPPClassTemplateParameter($1); - ctp->_packed = true; - $$ = CPPType::new_type(ctp); -} - ; - -/* -typedefname: - TYPENAME_IDENTIFIER -{ - CPPType *type = $1->find_type(current_scope, global_scope, false, current_lexer); - if (type == NULL) { - yyerror(string("internal error resolving type ") + $1->get_fully_scoped_name(), @1); - } - assert(type != NULL); - $$ = type; -} - | KW_TYPENAME name -{ - $$ = CPPType::new_type(new CPPTBDType($2)); -} - ; -*/ - - -/* Note that we should also accept "final" and "override" as valid names, - * according to C++11. */ -name: - IDENTIFIER -{ - $$ = $1; -} - | TYPENAME_IDENTIFIER -{ - $$ = $1; -} - | TYPEPACK_IDENTIFIER -{ - $$ = $1; -} - | KW_FINAL -{ - $$ = new CPPIdentifier("final", @1); -} - | KW_OVERRIDE -{ - $$ = new CPPIdentifier("override", @1); -} - | KW_SIGNED -{ - // This is not a keyword in Python, so it is useful to be able to use this - // in MAKE_PROPERTY definitions, etc. - $$ = new CPPIdentifier("signed", @1); -} - | KW_FLOAT -{ - $$ = new CPPIdentifier("float", @1); -} - | KW_PUBLIC -{ - $$ = new CPPIdentifier("public", @1); -} - | KW_PRIVATE -{ - $$ = new CPPIdentifier("private", @1); -} - | KW_STATIC -{ - $$ = new CPPIdentifier("static", @1); -} - | KW_DEFAULT -{ - $$ = new CPPIdentifier("default", @1); -} - ; - - -/* A variant on name that's used for structs, where we disallow final - * to disambiguate the case of struct A final {}; - */ -name_no_final: - IDENTIFIER -{ - $$ = $1; -} - | TYPENAME_IDENTIFIER -{ - $$ = $1; -} - | TYPEPACK_IDENTIFIER -{ - $$ = $1; -} - | KW_OVERRIDE -{ - $$ = new CPPIdentifier("override", @1); -} - ; - - -string_literal: - SIMPLE_STRING -{ - $$ = new CPPExpression($1); -} - | STRING_LITERAL -{ - $$ = $1; -} - | string_literal SIMPLE_STRING -{ - // The right string takes on the literal type of the left. - $$ = $1; - $$->_str += $2; -} - | string_literal STRING_LITERAL -{ - // We have to check that the two literal types match up. - $$ = $1; - if ($2->_type != CPPExpression::T_string && $2->_type != $1->_type) { - yywarning("cannot concatenate two string literals of different types", @$); - } - $$->_str += $2->_str; -} - ; - -empty: - ; diff --git a/dtool/src/cppparser/cppBisonDefs.h b/dtool/src/cppparser/cppBisonDefs.h deleted file mode 100644 index 2859ee30abb..00000000000 --- a/dtool/src/cppparser/cppBisonDefs.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppBisonDefs.h - * @author drose - * @date 1999-01-17 - */ - -#ifndef CPPBISON_H -#define CPPBISON_H - -// This header file defines the interface to the yacc (actually, bison) parser -// and grammar. None of these interfaces are intended to be used directly; -// they're defined here strictly to be used by the CPPParser and -// CPPExpressionParser classes. - -#include "dtoolbase.h" - -#include - -#include "cppAttributeList.h" -#include "cppClosureType.h" -#include "cppExtensionType.h" -#include "cppFile.h" - -class CPPParser; -class CPPExpression; -class CPPPreprocessor; -class CPPDeclaration; -class CPPInstance; -class CPPType; -class CPPStructType; -class CPPEnumType; -class CPPSimpleType; -class CPPInstanceIdentifier; -class CPPParameterList; -class CPPTemplateParameterList; -class CPPScope; -class CPPIdentifier; -class CPPCaptureType; - -void parse_cpp(CPPParser *cp); -CPPExpression *parse_const_expr(CPPPreprocessor *pp, - CPPScope *new_current_scope, - CPPScope *new_global_scope); -CPPType *parse_type(CPPPreprocessor *pp, - CPPScope *new_current_scope, - CPPScope *new_global_scope); - -extern CPPScope *current_scope; -extern CPPScope *global_scope; -extern CPPPreprocessor *current_lexer; - - -// This structure holds the return value for each token. Traditionally, this -// is a union, and is declared with the %union declaration in the parser.y -// file, but unions are pretty worthless in C++ (you can't include an object -// that has member functions in a union), so we'll use a class instead. That -// means we need to declare it externally, here. - -class cppyystype { -public: - std::string str; - CPPAttributeList attr_list; - union { - unsigned long long integer; - long double real; - CPPScope *scope; - CPPDeclaration *decl; - CPPInstance *instance; - CPPType *type; - CPPStructType *struct_type; - CPPEnumType *enum_type; - CPPSimpleType *simple_type; - CPPInstanceIdentifier *inst_ident; - CPPParameterList *param_list; - CPPTemplateParameterList *template_param_list; - CPPExtensionType::Type extension_enum; - CPPExpression *expr; - CPPIdentifier *identifier; - CPPClosureType *closure_type; - CPPClosureType::Capture *capture; - } u; -}; -#define YYSTYPE cppyystype - -// This structure takes advantage of a bison feature to track the exact -// location in the file of each token, for more useful error reporting. We -// define it up here so we can reference it in the lexer. - -struct cppyyltype { - // Bison expects these members to be part of this struct. - int first_line; - int first_column; - int last_line; - int last_column; - - // Early versions of bison (1.25 and earlier) expected these members to be - // in this struct as well. - int timestamp; - char *text; - - // The remaining members are added for this application and have no meaning - // to bison. - CPPFile file; -}; -#define YYLTYPE cppyyltype - -// Beginning around bison 1.35 or so, we need to define this macro as well, to -// tell bison how to collect multiple locations together. (The default -// implementation copies only first_line through last_column, whereas here we -// use the struct assignment operator to copy all the members of the -// structure). -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - (Current) = (Rhs)[1]; \ - (Current).last_line = (Rhs)[N].last_line; \ - (Current).last_column = (Rhs)[N].last_column; - -#endif diff --git a/dtool/src/cppparser/cppClassTemplateParameter.cxx b/dtool/src/cppparser/cppClassTemplateParameter.cxx deleted file mode 100644 index 7c85eb6c24e..00000000000 --- a/dtool/src/cppparser/cppClassTemplateParameter.cxx +++ /dev/null @@ -1,126 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppClassTemplateParameter.cxx - * @author drose - * @date 1999-10-28 - */ - -#include "cppClassTemplateParameter.h" -#include "cppIdentifier.h" - -/** - * - */ -CPPClassTemplateParameter:: -CPPClassTemplateParameter(CPPIdentifier *ident, CPPType *default_type) : - CPPType(CPPFile()), - _ident(ident), - _default_type(default_type), - _packed(false) -{ -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPClassTemplateParameter:: -is_fully_specified() const { - return false; -} - -/** - * - */ -void CPPClassTemplateParameter:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - if (complete) { - out << "class"; - if (_packed) { - out << "..."; - } - if (_ident != nullptr) { - out << " "; - _ident->output(out, scope); - } - if (_default_type) { - out << " = "; - _default_type->output(out, indent_level, scope, false); - } - } else { - _ident->output(out, scope); - } -} - - -/** - * - */ -CPPDeclaration::SubType CPPClassTemplateParameter:: -get_subtype() const { - return ST_class_template_parameter; -} - -/** - * - */ -CPPClassTemplateParameter *CPPClassTemplateParameter:: -as_class_template_parameter() { - return this; -} - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPClassTemplateParameter:: -is_equal(const CPPDeclaration *other) const { - const CPPClassTemplateParameter *ot = ((CPPDeclaration *)other)->as_class_template_parameter(); - assert(ot != nullptr); - - if (_default_type != ot->_default_type) { - return false; - } - - if (_packed != ot->_packed) { - return false; - } - - if (_ident == nullptr || ot->_ident == nullptr) { - return _ident == ot->_ident; - } - - return *_ident == *ot->_ident; -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPClassTemplateParameter:: -is_less(const CPPDeclaration *other) const { - const CPPClassTemplateParameter *ot = ((CPPDeclaration *)other)->as_class_template_parameter(); - assert(ot != nullptr); - - if (_default_type != ot->_default_type) { - return _default_type < ot->_default_type; - } - - if (_packed != ot->_packed) { - return _packed < ot->_packed; - } - - if (_ident == nullptr || ot->_ident == nullptr) { - return _ident < ot->_ident; - } - - return *_ident < *ot->_ident; -} diff --git a/dtool/src/cppparser/cppClassTemplateParameter.h b/dtool/src/cppparser/cppClassTemplateParameter.h deleted file mode 100644 index 8ff6fe15389..00000000000 --- a/dtool/src/cppparser/cppClassTemplateParameter.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppClassTemplateParameter.h - * @author drose - * @date 1999-10-28 - */ - -#ifndef CPPCLASSTEMPLATEPARAMETER_H -#define CPPCLASSTEMPLATEPARAMETER_H - -#include "dtoolbase.h" - -#include "cppType.h" - -class CPPIdentifier; - -/** - * - */ -class CPPClassTemplateParameter : public CPPType { -public: - CPPClassTemplateParameter(CPPIdentifier *ident, - CPPType *default_type = nullptr); - - virtual bool is_fully_specified() const; - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPClassTemplateParameter *as_class_template_parameter(); - - CPPIdentifier *_ident; - CPPType *_default_type; - bool _packed; - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppClosureType.cxx b/dtool/src/cppparser/cppClosureType.cxx deleted file mode 100644 index 5c201580f14..00000000000 --- a/dtool/src/cppparser/cppClosureType.cxx +++ /dev/null @@ -1,200 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppClosureType.cxx - * @author rdb - * @date 2017-01-14 - */ - -#include "cppClosureType.h" -#include "cppParameterList.h" -#include "cppExpression.h" - -/** - * - */ -CPPClosureType:: -CPPClosureType(CaptureType default_capture) : - CPPFunctionType(nullptr, nullptr, 0), - _default_capture(default_capture) { -} - -/** - * - */ -CPPClosureType:: -CPPClosureType(const CPPClosureType ©) : - CPPFunctionType(copy), - _captures(copy._captures), - _default_capture(copy._default_capture) -{ -} - -/** - * - */ -void CPPClosureType:: -operator = (const CPPClosureType ©) { - CPPFunctionType::operator = (copy); - _captures = copy._captures; - _default_capture = copy._default_capture; -} - -/** - * Adds a new capture to the beginning of the capture list. - */ -void CPPClosureType:: -add_capture(std::string name, CaptureType type, CPPExpression *initializer) { - if (type == CT_none) { - if (name == "this") { - type = CT_by_reference; - } else { - type = CT_by_value; - } - } - - Capture capture = {std::move(name), type, initializer}; - _captures.insert(_captures.begin(), std::move(capture)); -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPClosureType:: -is_fully_specified() const { - return CPPFunctionType::is_fully_specified(); -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPClosureType:: -is_default_constructible() const { - return false; -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPClosureType:: -is_copy_constructible() const { - return true; -} - -/** - * Returns true if the type is destructible. - */ -bool CPPClosureType:: -is_destructible() const { - return true; -} - -/** - * - */ -void CPPClosureType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - out.put('['); - - bool have_capture = false; - switch (_default_capture) { - case CT_none: - break; - case CT_by_reference: - out.put('&'); - have_capture = true; - break; - case CT_by_value: - out.put('='); - have_capture = true; - break; - } - - Captures::const_iterator it; - for (it = _captures.begin(); it != _captures.end(); ++it) { - const Capture &capture = *it; - if (have_capture) { - out << ", "; - } - if (capture._name == "this") { - if (capture._type == CT_by_value) { - out.put('*'); - } - } else { - if (capture._type == CT_by_reference) { - out.put('&'); - } - } - out << capture._name; - - if (capture._initializer != nullptr) { - out << " = " << *capture._initializer; - } - - have_capture = true; - } - out.put(']'); - - if (_parameters != nullptr) { - out.put('('); - _parameters->output(out, scope, true, -1); - out.put(')'); - } - - if (_flags & F_noexcept) { - out << " noexcept"; - } - - if (!_attributes.is_empty()) { - out << " " << _attributes; - } - - if (_return_type != nullptr) { - out << " -> "; - _return_type->output(out, indent_level, scope, false); - } - - out << " {}"; -} - -/** - * - */ -CPPDeclaration::SubType CPPClosureType:: -get_subtype() const { - return ST_closure; -} - -/** - * - */ -CPPClosureType *CPPClosureType:: -as_closure_type() { - return this; -} - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPClosureType:: -is_equal(const CPPDeclaration *other) const { - return (this == other); -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPClosureType:: -is_less(const CPPDeclaration *other) const { - return (this < other); -} diff --git a/dtool/src/cppparser/cppClosureType.h b/dtool/src/cppparser/cppClosureType.h deleted file mode 100644 index 9e11a2f1245..00000000000 --- a/dtool/src/cppparser/cppClosureType.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppClosureType.h - * @author rdb - * @date 2017-01-14 - */ - -#ifndef CPPCLOSURETYPE_H -#define CPPCLOSURETYPE_H - -#include "dtoolbase.h" - -#include "cppFunctionType.h" - -/** - * The type of a lambda expression. This is like a function, but with - * additional captures defined. - */ -class CPPClosureType : public CPPFunctionType { -public: - enum CaptureType { - CT_none, - CT_by_reference, - CT_by_value, - }; - - CPPClosureType(CaptureType default_capture = CT_none); - CPPClosureType(const CPPClosureType ©); - void operator = (const CPPClosureType ©); - - struct Capture { - std::string _name; - CaptureType _type; - CPPExpression *_initializer; - }; - typedef std::vector Captures; - Captures _captures; - - CaptureType _default_capture; - - void add_capture(std::string name, CaptureType type, CPPExpression *initializer = nullptr); - - virtual bool is_fully_specified() const; - - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_destructible() const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - virtual CPPClosureType *as_closure_type(); - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppCommentBlock.h b/dtool/src/cppparser/cppCommentBlock.h deleted file mode 100644 index e31b3b6278f..00000000000 --- a/dtool/src/cppparser/cppCommentBlock.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppCommentBlock.h - * @author drose - * @date 2000-08-15 - */ - -#ifndef CPPCOMMENTBLOCK_H -#define CPPCOMMENTBLOCK_H - -#include "dtoolbase.h" - -#include "cppFile.h" - -#include - -/** - * This represents a comment appearing in the source code. The - * CPPPreprocessor collects these, and saves the complete list of comments - * encountered; it also stores a list of the comment blocks appearing before - * each declaration. - */ -class CPPCommentBlock { -public: - CPPFile _file; - int _line_number; - int _col_number; - int _last_line; - bool _c_style; - std::string _comment; -}; - -typedef std::list CPPComments; - -#endif diff --git a/dtool/src/cppparser/cppConstType.cxx b/dtool/src/cppparser/cppConstType.cxx deleted file mode 100644 index 585f545b636..00000000000 --- a/dtool/src/cppparser/cppConstType.cxx +++ /dev/null @@ -1,240 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppConstType.cxx - * @author drose - * @date 1999-10-28 - */ - -#include "cppConstType.h" - -/** - * - */ -CPPConstType:: -CPPConstType(CPPType *wrapped_around) : - CPPType(CPPFile()), - _wrapped_around(wrapped_around) -{ -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPConstType:: -is_fully_specified() const { - return CPPType::is_fully_specified() && - _wrapped_around->is_fully_specified(); -} - -/** - * - */ -CPPDeclaration *CPPConstType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - return (*si).second; - } - - CPPConstType *rep = new CPPConstType(*this); - rep->_wrapped_around = - _wrapped_around->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - - if (rep->_wrapped_around == _wrapped_around) { - delete rep; - rep = this; - } - rep = CPPType::new_type(rep)->as_const_type(); - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPConstType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPType *ptype = _wrapped_around->resolve_type(current_scope, global_scope); - - if (ptype != _wrapped_around) { - CPPConstType *rep = new CPPConstType(*this); - rep->_wrapped_around = ptype; - return CPPType::new_type(rep); - } - return this; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPConstType:: -is_tbd() const { - return _wrapped_around->is_tbd(); -} - -/** - * Returns true if the type is considered a fundamental type. - */ -bool CPPConstType:: -is_fundamental() const { - return _wrapped_around->is_fundamental(); -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPConstType:: -is_standard_layout() const { - return _wrapped_around->is_standard_layout(); -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPConstType:: -is_trivial() const { - return _wrapped_around->is_trivial(); -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPConstType:: -is_trivially_copyable() const { - return _wrapped_around->is_trivially_copyable(); -} - -/** - * Returns true if the type can be constructed using the given argument. - */ -bool CPPConstType:: -is_constructible(const CPPType *given_type) const { - return _wrapped_around->is_constructible(given_type); -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPConstType:: -is_default_constructible() const { - return _wrapped_around->is_default_constructible(); -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPConstType:: -is_copy_constructible() const { - return _wrapped_around->is_copy_constructible(); -} - -/** - * Returns true if the type is destructible. - */ -bool CPPConstType:: -is_destructible() const { - return _wrapped_around->is_destructible(); -} - -/** - * Returns true if variables of this type may be implicitly converted to - * the other type. - */ -bool CPPConstType:: -is_convertible_to(const CPPType *other) const { - return _wrapped_around->is_convertible_to(other); -} - -/** - * This is a little more forgiving than is_equal(): it returns true if the - * types appear to be referring to the same thing, even if they may have - * different pointers or somewhat different definitions. It's useful for - * parameter matching, etc. - */ -bool CPPConstType:: -is_equivalent(const CPPType &other) const { - const CPPConstType *ot = ((CPPType *)&other)->as_const_type(); - if (ot == nullptr) { - return CPPType::is_equivalent(other); - } - - return _wrapped_around->is_equivalent(*ot->_wrapped_around); -} - -/** - * - */ -void CPPConstType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - _wrapped_around->output(out, indent_level, scope, complete); - out << " const"; -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPConstType:: -output_instance(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const { - _wrapped_around->output_instance(out, indent_level, scope, complete, - "const " + prename, name); -} - -/** - * - */ -CPPDeclaration::SubType CPPConstType:: -get_subtype() const { - return ST_const; -} - -/** - * - */ -CPPConstType *CPPConstType:: -as_const_type() { - return this; -} - - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPConstType:: -is_equal(const CPPDeclaration *other) const { - const CPPConstType *ot = ((CPPDeclaration *)other)->as_const_type(); - assert(ot != nullptr); - - return _wrapped_around == ot->_wrapped_around; -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPConstType:: -is_less(const CPPDeclaration *other) const { - const CPPConstType *ot = ((CPPDeclaration *)other)->as_const_type(); - assert(ot != nullptr); - - return _wrapped_around < ot->_wrapped_around; -} diff --git a/dtool/src/cppparser/cppConstType.h b/dtool/src/cppparser/cppConstType.h deleted file mode 100644 index 81db17884ab..00000000000 --- a/dtool/src/cppparser/cppConstType.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppConstType.h - * @author drose - * @date 1999-10-28 - */ - -#ifndef CPPCONSTTYPE_H -#define CPPCONSTTYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" - -/** - * - */ -class CPPConstType : public CPPType { -public: - CPPConstType(CPPType *wrapped_around); - - CPPType *_wrapped_around; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_tbd() const; - virtual bool is_fundamental() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *type) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_destructible() const; - virtual bool is_convertible_to(const CPPType *other) const; - virtual bool is_equivalent(const CPPType &other) const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const; - - virtual SubType get_subtype() const; - - virtual CPPConstType *as_const_type(); - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppDeclaration.cxx b/dtool/src/cppparser/cppDeclaration.cxx deleted file mode 100644 index ef7e87bdf6c..00000000000 --- a/dtool/src/cppparser/cppDeclaration.cxx +++ /dev/null @@ -1,379 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppDeclaration.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppDeclaration.h" -#include "cppPreprocessor.h" - -/** - * - */ -CPPDeclaration:: -CPPDeclaration(const CPPFile &file, CPPAttributeList attr) : - _file(file), - _attributes(std::move(attr)) -{ - _vis = V_unknown; - _template_scope = nullptr; - _leading_comment = nullptr; -} - -/** - * - */ -CPPDeclaration:: -CPPDeclaration(const CPPDeclaration ©) : - _vis(copy._vis), - _template_scope(copy._template_scope), - _file(copy._file), - _leading_comment(copy._leading_comment), - _attributes(copy._attributes) -{ -} - -/** - * - */ -CPPDeclaration &CPPDeclaration:: -operator = (const CPPDeclaration ©) { - _vis = copy._vis; - _template_scope = copy._template_scope; - _file = copy._file; - _leading_comment = copy._leading_comment; - _attributes = copy._attributes; - return *this; -} - -/** - * - */ -bool CPPDeclaration:: -operator == (const CPPDeclaration &other) const { - if (get_subtype() != other.get_subtype()) { - return false; - } - return is_equal(&other); -} - -/** - * - */ -bool CPPDeclaration:: -operator != (const CPPDeclaration &other) const { - return !(*this == other); -} - -/** - * - */ -bool CPPDeclaration:: -operator < (const CPPDeclaration &other) const { - if (get_subtype() != other.get_subtype()) { - return get_subtype() < other.get_subtype(); - } - return is_less(&other); -} - -/** - * Returns true if this is a template declaration of some kind: a template - * function or a template class, typically. - */ -bool CPPDeclaration:: -is_template() const { - return _template_scope != nullptr; -} - -/** - * If is_template(), above, returns true, this returns the CPPTemplateScope in - * which this particular template declaration is defined. This scope includes - * the information about the template parameters. - */ -CPPTemplateScope *CPPDeclaration:: -get_template_scope() const { - return _template_scope; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPDeclaration:: -is_fully_specified() const { - return !is_template(); -} - -/** - * - */ -CPPDeclaration *CPPDeclaration:: -instantiate(const CPPTemplateParameterList *, - CPPScope *, CPPScope *, - CPPPreprocessor *error_sink) const { - if (error_sink != nullptr) { - error_sink->warning("Ignoring template parameters"); - } - return (CPPDeclaration *)this; -} - -/** - * - */ -CPPDeclaration *CPPDeclaration:: -substitute_decl(SubstDecl &subst, CPPScope *, CPPScope *) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - assert((*si).second != nullptr); - return (*si).second; - } - return this; -} - -/** - * - */ -void CPPDeclaration:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - out << _attributes; -} - -/** - * - */ -CPPDeclaration::SubType CPPDeclaration:: -get_subtype() const { - return ST_empty; -} - -/** - * - */ -CPPInstance *CPPDeclaration:: -as_instance() { - return nullptr; -} - -/** - * - */ -CPPClassTemplateParameter *CPPDeclaration:: -as_class_template_parameter() { - return nullptr; -} - -/** - * - */ -CPPTypedefType *CPPDeclaration:: -as_typedef_type() { - return nullptr; -} - -/** - * - */ -CPPTypeDeclaration *CPPDeclaration:: -as_type_declaration() { - return nullptr; -} - -/** - * - */ -CPPExpression *CPPDeclaration:: -as_expression() { - return nullptr; -} - -/** - * - */ -CPPType *CPPDeclaration:: -as_type() { - return nullptr; -} - -/** - * - */ -CPPNamespace *CPPDeclaration:: -as_namespace() { - return nullptr; -} - -/** - * - */ -CPPUsing *CPPDeclaration:: -as_using() { - return nullptr; -} - -/** - * - */ -CPPSimpleType *CPPDeclaration:: -as_simple_type() { - return nullptr; -} - -/** - * - */ -CPPPointerType *CPPDeclaration:: -as_pointer_type() { - return nullptr; -} - -/** - * - */ -CPPReferenceType *CPPDeclaration:: -as_reference_type() { - return nullptr; -} - -/** - * - */ -CPPArrayType *CPPDeclaration:: -as_array_type() { - return nullptr; -} - -/** - * - */ -CPPConstType *CPPDeclaration:: -as_const_type() { - return nullptr; -} - -/** - * - */ -CPPFunctionType *CPPDeclaration:: -as_function_type() { - return nullptr; -} - -/** - * - */ -CPPFunctionGroup *CPPDeclaration:: -as_function_group() { - return nullptr; -} - -/** - * - */ -CPPExtensionType *CPPDeclaration:: -as_extension_type() { - return nullptr; -} - -/** - * - */ -CPPStructType *CPPDeclaration:: -as_struct_type() { - return nullptr; -} - -/** - * - */ -CPPEnumType *CPPDeclaration:: -as_enum_type() { - return nullptr; -} - -/** - * - */ -CPPTBDType *CPPDeclaration:: -as_tbd_type() { - return nullptr; -} - -/** - * - */ -CPPTypeProxy *CPPDeclaration:: -as_type_proxy() { - return nullptr; -} - -/** - * - */ -CPPMakeProperty *CPPDeclaration:: -as_make_property() { - return nullptr; -} - -/** - * - */ -CPPMakeSeq *CPPDeclaration:: -as_make_seq() { - return nullptr; -} - -/** - * - */ -CPPClosureType *CPPDeclaration:: -as_closure_type() { - return nullptr; -} - -/** - * Called by CPPDeclaration to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPDeclaration:: -is_equal(const CPPDeclaration *other) const { - return this == other; -} - -/** - * Called by CPPDeclaration to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPDeclaration:: -is_less(const CPPDeclaration *other) const { - return this < other; -} - - -std::ostream & -operator << (std::ostream &out, const CPPDeclaration::SubstDecl &subst) { - CPPDeclaration::SubstDecl::const_iterator it; - for (it = subst.begin(); it != subst.end(); ++it) { - out << " "; - if (it->first == nullptr) { - out << "(null)"; - } else { - out << *(it->first); - } - out << " -> "; - if (it->second == nullptr) { - out << "(null)"; - } else { - out << *(it->second); - } - out << "\n"; - } - return out; -} diff --git a/dtool/src/cppparser/cppDeclaration.h b/dtool/src/cppparser/cppDeclaration.h deleted file mode 100644 index 73c8fd49bbf..00000000000 --- a/dtool/src/cppparser/cppDeclaration.h +++ /dev/null @@ -1,239 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppDeclaration.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPDECLARATION_H -#define CPPDECLARATION_H - -#include "dtoolbase.h" - -#include "cppVisibility.h" -#include "cppFile.h" -#include "cppCommentBlock.h" -#include "cppAttributeList.h" - -#include -#include -#include -#include - -class CPPInstance; -class CPPTemplateParameterList; -class CPPTypedefType; -class CPPTypeDeclaration; -class CPPExpression; -class CPPType; -class CPPNamespace; -class CPPUsing; -class CPPSimpleType; -class CPPPointerType; -class CPPReferenceType; -class CPPArrayType; -class CPPConstType; -class CPPFunctionType; -class CPPFunctionGroup; -class CPPExtensionType; -class CPPStructType; -class CPPEnumType; -class CPPTypeProxy; -class CPPMakeProperty; -class CPPMakeSeq; -class CPPClosureType; -class CPPClassTemplateParameter; -class CPPTBDType; -class CPPScope; -class CPPTemplateScope; -class CPPPreprocessor; - -/** - * - */ -class CPPDeclaration { -public: - enum SubType { - // Empty declaration - ST_empty, - - // Subtypes of CPPDeclaration - ST_instance, - ST_type_declaration, - ST_expression, - ST_type, - ST_namespace, - ST_using, - ST_make_property, - ST_make_seq, - - // Subtypes of CPPType - ST_simple, - ST_pointer, - ST_reference, - ST_array, - ST_const, - ST_function, - ST_function_group, - ST_extension, - ST_struct, - ST_enum, - ST_class_template_parameter, - ST_tbd, - ST_type_proxy, - ST_typedef, - ST_closure, - }; - - CPPDeclaration(const CPPFile &file, CPPAttributeList attr = CPPAttributeList()); - CPPDeclaration(const CPPDeclaration ©); - virtual ~CPPDeclaration() {}; - - CPPDeclaration &operator = (const CPPDeclaration ©); - - bool operator == (const CPPDeclaration &other) const; - bool operator != (const CPPDeclaration &other) const; - bool operator < (const CPPDeclaration &other) const; - - bool is_template() const; - CPPTemplateScope *get_template_scope() const; - virtual bool is_fully_specified() const; - virtual CPPDeclaration * - instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - typedef std::map SubstDecl; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - typedef std::set Instantiations; - Instantiations _instantiations; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - - virtual SubType get_subtype() const; - - virtual CPPInstance *as_instance(); - virtual CPPClassTemplateParameter *as_class_template_parameter(); - virtual CPPTypedefType *as_typedef_type(); - virtual CPPTypeDeclaration *as_type_declaration(); - virtual CPPExpression *as_expression(); - virtual CPPType *as_type(); - virtual CPPNamespace *as_namespace(); - virtual CPPUsing *as_using(); - virtual CPPSimpleType *as_simple_type(); - virtual CPPPointerType *as_pointer_type(); - virtual CPPReferenceType *as_reference_type(); - virtual CPPArrayType *as_array_type(); - virtual CPPConstType *as_const_type(); - virtual CPPFunctionType *as_function_type(); - virtual CPPFunctionGroup *as_function_group(); - virtual CPPExtensionType *as_extension_type(); - virtual CPPStructType *as_struct_type(); - virtual CPPEnumType *as_enum_type(); - virtual CPPTBDType *as_tbd_type(); - virtual CPPTypeProxy *as_type_proxy(); - virtual CPPMakeProperty *as_make_property(); - virtual CPPMakeSeq *as_make_seq(); - virtual CPPClosureType *as_closure_type(); - - inline const CPPInstance *as_instance() const { - return ((CPPDeclaration *)this)->as_instance(); - } - inline const CPPClassTemplateParameter *as_class_template_parameter() const { - return ((CPPDeclaration *)this)->as_class_template_parameter(); - } - inline const CPPTypedefType *as_typedef_type() const { - return ((CPPDeclaration *)this)->as_typedef_type(); - } - inline const CPPTypeDeclaration *as_type_declaration() const { - return ((CPPDeclaration *)this)->as_type_declaration(); - } - inline const CPPExpression *as_expression() const { - return ((CPPDeclaration *)this)->as_expression(); - } - inline const CPPType *as_type() const { - return ((CPPDeclaration *)this)->as_type(); - } - inline const CPPNamespace *as_namespace() const { - return ((CPPDeclaration *)this)->as_namespace(); - } - inline const CPPUsing *as_using() const { - return ((CPPDeclaration *)this)->as_using(); - } - inline const CPPSimpleType *as_simple_type() const { - return ((CPPDeclaration *)this)->as_simple_type(); - } - inline const CPPPointerType *as_pointer_type() const { - return ((CPPDeclaration *)this)->as_pointer_type(); - } - inline const CPPReferenceType *as_reference_type() const { - return ((CPPDeclaration *)this)->as_reference_type(); - } - inline const CPPArrayType *as_array_type() const { - return ((CPPDeclaration *)this)->as_array_type(); - } - inline const CPPConstType *as_const_type() const { - return ((CPPDeclaration *)this)->as_const_type(); - } - inline const CPPFunctionType *as_function_type() const { - return ((CPPDeclaration *)this)->as_function_type(); - } - inline const CPPFunctionGroup *as_function_group() const { - return ((CPPDeclaration *)this)->as_function_group(); - } - inline const CPPExtensionType *as_extension_type() const { - return ((CPPDeclaration *)this)->as_extension_type(); - } - inline const CPPStructType *as_struct_type() const { - return ((CPPDeclaration *)this)->as_struct_type(); - } - inline const CPPEnumType *as_enum_type() const { - return ((CPPDeclaration *)this)->as_enum_type(); - } - inline const CPPTBDType *as_tbd_type() const { - return ((CPPDeclaration *)this)->as_tbd_type(); - } - inline const CPPTypeProxy *as_type_proxy() const { - return ((CPPDeclaration *)this)->as_type_proxy(); - } - inline const CPPMakeProperty *as_make_property() const { - return ((CPPDeclaration *)this)->as_make_property(); - } - inline const CPPMakeSeq *as_make_seq() const { - return ((CPPDeclaration *)this)->as_make_seq(); - } - inline const CPPClosureType *as_closure_type() const { - return ((CPPDeclaration *)this)->as_closure_type(); - } - - CPPVisibility _vis; - CPPTemplateScope *_template_scope; - CPPFile _file; - CPPCommentBlock *_leading_comment; - CPPAttributeList _attributes; - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPDeclaration &decl) { - decl.output(out, 0, nullptr, false); - return out; -} - -std::ostream & -operator << (std::ostream &out, const CPPDeclaration::SubstDecl &decl); - -#endif diff --git a/dtool/src/cppparser/cppEnumType.cxx b/dtool/src/cppparser/cppEnumType.cxx deleted file mode 100644 index 1e0e133cade..00000000000 --- a/dtool/src/cppparser/cppEnumType.cxx +++ /dev/null @@ -1,328 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppEnumType.cxx - * @author drose - * @date 1999-10-25 - */ - -#include "cppEnumType.h" -#include "cppTypedefType.h" -#include "cppExpression.h" -#include "cppSimpleType.h" -#include "cppConstType.h" -#include "cppScope.h" -#include "cppParser.h" -#include "cppIdentifier.h" -#include "indent.h" - -/** - * Creates an untyped enum. - */ -CPPEnumType:: -CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope, - CPPScope *scope, const CPPFile &file, CPPAttributeList attr) : - CPPExtensionType(type, ident, current_scope, file, std::move(attr)), - _scope(scope), - _element_type(nullptr), - _last_value(nullptr) -{ - _parent_scope = (type == T_enum) ? current_scope : scope; - - if (ident != nullptr) { - ident->_native_scope = current_scope; - } -} - -/** - * Creates a typed enum. - */ -CPPEnumType:: -CPPEnumType(Type type, CPPIdentifier *ident, CPPType *element_type, - CPPScope *current_scope, CPPScope *scope, const CPPFile &file, - CPPAttributeList attr) : - CPPExtensionType(type, ident, current_scope, file, std::move(attr)), - _scope(scope), - _element_type(element_type), - _last_value(nullptr) -{ - _parent_scope = (type == T_enum) ? current_scope : scope; - if (ident != nullptr) { - ident->_native_scope = current_scope; - } -} - -/** - * Returns true if this is a scoped enum. - */ -bool CPPEnumType:: -is_scoped() const { - return (_type != T_enum); -} - -/** - * Returns the integral type used to store enum values. - */ -CPPType *CPPEnumType:: -get_underlying_type() { - if (_element_type == nullptr) { - // This enum is untyped. Use a suitable default, ie. 'int'. In the - // future, we might want to check whether it fits in an int. - static CPPType *default_element_type = nullptr; - if (default_element_type == nullptr) { - default_element_type = - CPPType::new_type(new CPPConstType(new CPPSimpleType(CPPSimpleType::T_int, 0))); - } - - return default_element_type; - } else { - // This enum has an explicit type, so use that. - return CPPType::new_type(new CPPConstType(_element_type)); - } -} - -/** - * - */ -CPPInstance *CPPEnumType:: -add_element(const std::string &name, CPPExpression *value, - CPPPreprocessor *preprocessor, const cppyyltype &pos, - CPPAttributeList attr) { - CPPIdentifier *ident = new CPPIdentifier(name); - ident->_native_scope = _parent_scope; - - CPPInstance *inst; - if (_type == T_enum) { - // Weakly typed enum. - inst = new CPPInstance(get_underlying_type(), ident); - } else { - // C++11-style strongly typed enum. - inst = new CPPInstance(this, ident); - } - inst->_storage_class |= CPPInstance::SC_constexpr; - inst->_attributes = std::move(attr); - _elements.push_back(inst); - - if (value == nullptr) { - if (_last_value == nullptr) { - // This is the first value, and should therefore be 0. - static CPPExpression *const zero = new CPPExpression(0); - value = zero; - - } else if (_last_value->_type == CPPExpression::T_integer) { - value = new CPPExpression(_last_value->_u._integer + 1); - - } else if (_last_value->_type == CPPExpression::T_binary_operation && - _last_value->_u._op._operator == '+' && - _last_value->_u._op._op2->_type == CPPExpression::T_integer) { - // Prevent an endless expansion of + expressions. - value = new CPPExpression('+', - _last_value->_u._op._op1, - new CPPExpression(_last_value->_u._op._op2->_u._integer + 1)); - - } else { - // We may not be able to determine the value just yet. No problem; - // we'll just define it as another expression. - static CPPExpression *const one = new CPPExpression(1); - value = new CPPExpression('+', _last_value, one); - } - } - inst->_initializer = value; - _last_value = value; - - if (preprocessor != nullptr) { - // Same-line comment? - CPPCommentBlock *comment = - preprocessor->get_comment_on(pos.first_line, pos.file); - - if (comment == nullptr) { - // Nope. Check for a comment before this line. - comment = - preprocessor->get_comment_before(pos.first_line, pos.file); - - if (comment != nullptr) { - // This is a bit of a hack, but it prevents us from picking up a same- - // line comment from the previous line. - if (comment->_line_number != pos.first_line - 1 || - comment->_col_number <= pos.first_column) { - - inst->_leading_comment = comment; - } - } - } else { - inst->_leading_comment = comment; - } - } - - // Add the value to the enum scope (as per C++11), assuming it's not anonymous. - if (_scope != nullptr) { - _scope->add_enum_value(inst); - } - - // Now add it to the containing scope as well if it's not an "enum class". - if (!is_scoped() && _parent_scope != nullptr) { - _parent_scope->add_enum_value(inst); - } - - return inst; -} - -/** - * Returns true if the type has not yet been fully specified, false if it has. - */ -bool CPPEnumType:: -is_incomplete() const { - return false; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPEnumType:: -is_fully_specified() const { - if (!CPPDeclaration::is_fully_specified()) { - return false; - } - - if (_ident != nullptr && !_ident->is_fully_specified()) { - return false; - } - - if (_element_type != nullptr && !_element_type->is_fully_specified()) { - return false; - } - - Elements::const_iterator ei; - for (ei = _elements.begin(); ei != _elements.end(); ++ei) { - if (!(*ei)->is_fully_specified()) { - return false; - } - } - - return true; -} - -/** - * - */ -CPPDeclaration *CPPEnumType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - return (*si).second; - } - - CPPEnumType *rep = new CPPEnumType(*this); - - if (_ident != nullptr) { - rep->_ident = - _ident->substitute_decl(subst, current_scope, global_scope); - } - - if (_element_type != nullptr) { - rep->_element_type = - _element_type->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - } - - bool any_changed = false; - - for (size_t i = 0; i < _elements.size(); ++i) { - // We don't just do substitute_decl on the instance, which could lead to - // an infinite recursion. - CPPInstance *element = _elements[i]; - CPPExpression *value = element->_initializer-> - substitute_decl(subst, current_scope, global_scope)->as_expression(); - - if (is_scoped()) { - // For a strong enum, we consider the elements to be of this type. - if (value != element->_initializer) { - rep->_elements[i] = new CPPInstance(rep, element->_ident); - rep->_elements[i]->_initializer = value; - any_changed = true; - } - } else if (value != element->_initializer || - rep->get_underlying_type() != get_underlying_type()) { - // In an unscoped enum, the elements are integers. - rep->_elements[i] = new CPPInstance(rep->get_underlying_type(), element->_ident); - rep->_elements[i]->_initializer = value; - any_changed = true; - } - } - - if (rep->_ident == _ident && - rep->_element_type == _element_type && - !any_changed) { - delete rep; - rep = this; - } - rep = CPPType::new_type(rep)->as_enum_type(); - subst.insert(SubstDecl::value_type(this, rep)); - - return rep; -} - -/** - * - */ -void CPPEnumType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - if (!complete && _ident != nullptr) { - // If we have a name, use it. - if (cppparser_output_class_keyword) { - out << _type << " "; - } - out << _ident->get_local_name(scope); - } - else { - out << _type; - if (!_attributes.is_empty()) { - out << " " << _attributes; - } - if (_ident != nullptr) { - out << " " << _ident->get_local_name(scope); - } - if (_element_type != nullptr) { - out << " : " << _element_type->get_local_name(scope); - } - - out << " {\n"; - for (CPPInstance *element : _elements) { - indent(out, indent_level + 2) << element->get_local_name(); - - if (!element->_attributes.is_empty()) { - out << " " << element->_attributes; - } - - if (element->_initializer != nullptr) { - out << " = " << *element->_initializer; - } - out << ",\n"; - } - indent(out, indent_level) << "}"; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPEnumType:: -get_subtype() const { - return ST_enum; -} - -/** - * - */ -CPPEnumType *CPPEnumType:: -as_enum_type() { - return this; -} diff --git a/dtool/src/cppparser/cppEnumType.h b/dtool/src/cppparser/cppEnumType.h deleted file mode 100644 index f2be4891c46..00000000000 --- a/dtool/src/cppparser/cppEnumType.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppEnumType.h - * @author drose - * @date 1999-10-25 - */ - -#ifndef CPPENUMTYPE_H -#define CPPENUMTYPE_H - -#include "dtoolbase.h" - -#include "cppBisonDefs.h" -#include "cppExtensionType.h" - -#include - -class CPPExpression; -class CPPInstance; -class CPPScope; - - -/** - * - */ -class CPPEnumType : public CPPExtensionType { -public: - CPPEnumType(Type type, CPPIdentifier *ident, CPPScope *current_scope, - CPPScope *scope, const CPPFile &file, - CPPAttributeList attr = CPPAttributeList()); - CPPEnumType(Type type, CPPIdentifier *ident, CPPType *element_type, - CPPScope *current_scope, CPPScope *scope, const CPPFile &file, - CPPAttributeList attr = CPPAttributeList()); - - bool is_scoped() const; - CPPType *get_underlying_type(); - - CPPInstance *add_element(const std::string &name, CPPExpression *value, - CPPPreprocessor *preprocessor, const cppyyltype &pos, - CPPAttributeList attr = CPPAttributeList()); - - virtual bool is_incomplete() const; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPEnumType *as_enum_type(); - - CPPScope *_parent_scope; - CPPScope *_scope; - CPPType *_element_type; - - typedef std::vector Elements; - Elements _elements; - CPPExpression *_last_value; -}; - - -#endif diff --git a/dtool/src/cppparser/cppExpression.cxx b/dtool/src/cppparser/cppExpression.cxx deleted file mode 100644 index 21797c76f72..00000000000 --- a/dtool/src/cppparser/cppExpression.cxx +++ /dev/null @@ -1,2450 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppExpression.cxx - * @author drose - * @date 1999-10-25 - */ - -#include "cppExpression.h" -#include "cppToken.h" -#include "cppIdentifier.h" -#include "cppType.h" -#include "cppSimpleType.h" -#include "cppPointerType.h" -#include "cppEnumType.h" -#include "cppConstType.h" -#include "cppArrayType.h" -#include "cppPreprocessor.h" -#include "cppInstance.h" -#include "cppFunctionGroup.h" -#include "cppFunctionType.h" -#include "cppClosureType.h" -#include "cppReferenceType.h" -#include "cppStructType.h" -#include "cppBison.h" -#include "pdtoa.h" - -#include - -using std::cerr; -using std::string; - -/** - * - */ -CPPExpression::Result:: -Result() { - _type = RT_error; -} - -/** - * - */ -CPPExpression::Result:: -Result(int value) { - _type = RT_integer; - _u._integer = value; -} - -/** - * - */ -CPPExpression::Result:: -Result(double value) { - _type = RT_real; - _u._real = value; -} - -/** - * - */ -CPPExpression::Result:: -Result(void *value) { - _type = RT_pointer; - _u._pointer = value; -} - - -/** - * - */ -int CPPExpression::Result:: -as_integer() const { - switch (_type) { - case RT_integer: - return _u._integer; - - case RT_real: - return (int)_u._real; - - case RT_pointer: - // We don't mind if this loses precision. - return (int)(intptr_t)(_u._pointer); - - default: - cerr << "Invalid type\n"; - assert(false); - return 0; - } -} - -/** - * - */ -double CPPExpression::Result:: -as_real() const { - switch (_type) { - case RT_integer: - return (double)_u._integer; - - case RT_real: - return _u._real; - - case RT_pointer: - // We don't mind if this loses precision. - return (double)(uintptr_t)(_u._pointer); - - default: - cerr << "Invalid type\n"; - assert(false); - return 0.0; - } -} - -/** - * - */ -void *CPPExpression::Result:: -as_pointer() const { - switch (_type) { - case RT_integer: - return (void *)(intptr_t)_u._integer; - - case RT_real: - return (void *)(uintptr_t)_u._real; - - case RT_pointer: - return _u._pointer; - - default: - cerr << "Invalid type\n"; - assert(false); - return nullptr; - } -} - -/** - * - */ -bool CPPExpression::Result:: -as_boolean() const { - switch (_type) { - case RT_integer: - return (_u._integer != 0); - - case RT_real: - return (_u._real != 0.0); - - case RT_pointer: - return (_u._pointer != nullptr); - - default: - cerr << "Invalid type\n"; - assert(false); - return false; - } -} - -/** - * - */ -void CPPExpression::Result:: -output(std::ostream &out) const { - switch (_type) { - case RT_integer: - out << _u._integer; - break; - - case RT_real: - out << _u._real; - break; - - case RT_pointer: - out << _u._pointer; - break; - - case RT_error: - out << "(error)"; - break; - - default: - out << "(**invalid type**)\n"; - } -} - -/** - * - */ -CPPExpression:: -CPPExpression(bool value) : - CPPDeclaration(CPPFile()) -{ - _type = T_boolean; - _u._boolean = value; -} - -/** - * - */ -CPPExpression:: -CPPExpression(unsigned long long value) : - CPPDeclaration(CPPFile()) -{ - _type = T_integer; - _u._integer = value; -} - -/** - * - */ -CPPExpression:: -CPPExpression(int value) : - CPPDeclaration(CPPFile()) -{ - _type = T_integer; - _u._integer = value; -} - -/** - * - */ -CPPExpression:: -CPPExpression(long double value) : - CPPDeclaration(CPPFile()) -{ - _type = T_real; - _u._real = value; -} - -/** - * - */ -CPPExpression:: -CPPExpression(const string &value) : - CPPDeclaration(CPPFile()) -{ - _type = T_string; - _str = value; -} - -/** - * - */ -CPPExpression:: -CPPExpression(CPPIdentifier *ident, CPPScope *current_scope, - CPPScope *global_scope, CPPPreprocessor *error_sink) : - CPPDeclaration(CPPFile()) -{ - CPPDeclaration *decl = - ident->find_symbol(current_scope, global_scope); - - if (decl != nullptr) { - CPPInstance *inst = decl->as_instance(); - if (inst != nullptr) { - _type = T_variable; - _u._variable = inst; - return; - } - /*CPPFunctionGroup *fgroup = decl->as_function_group(); - if (fgroup != nullptr) { - _type = T_function; - _u._fgroup = fgroup; - return; - }*/ - } - - _type = T_unknown_ident; - _u._ident = ident; - // _u._ident->_native_scope = current_scope; -} - -/** - * - */ -CPPExpression:: -CPPExpression(int unary_operator, CPPExpression *op1) : - CPPDeclaration(CPPFile()) -{ - _type = T_unary_operation; - _u._op._operator = unary_operator; - _u._op._op1 = op1; - _u._op._op2 = nullptr; - _u._op._op3 = nullptr; -} - -/** - * - */ -CPPExpression:: -CPPExpression(int binary_operator, CPPExpression *op1, CPPExpression *op2) : - CPPDeclaration(CPPFile()) -{ - _type = T_binary_operation; - _u._op._operator = binary_operator; - _u._op._op1 = op1; - _u._op._op2 = op2; - _u._op._op3 = nullptr; -} - -/** - * - */ -CPPExpression:: -CPPExpression(int trinary_operator, CPPExpression *op1, CPPExpression *op2, - CPPExpression *op3) : - CPPDeclaration(CPPFile()) -{ - _type = T_trinary_operation; - _u._op._operator = trinary_operator; - _u._op._op1 = op1; - _u._op._op2 = op2; - _u._op._op3 = op3; -} - -/** - * Creates an expression that represents a typecast operation. - */ -CPPExpression CPPExpression:: -typecast_op(CPPType *type, CPPExpression *op1, Type cast_type) { - assert(cast_type >= T_typecast && cast_type <= T_reinterpret_cast); - CPPExpression expr(0); - expr._type = cast_type; - expr._u._typecast._to = type; - expr._u._typecast._op1 = op1; - return expr; -} - -/** - * Creates an expression that represents a constructor call. - */ -CPPExpression CPPExpression:: -construct_op(CPPType *type, CPPExpression *op1) { - CPPExpression expr(0); - if (op1 == nullptr) { - // A default constructor call--no parameters. - expr._type = T_default_construct; - expr._u._typecast._to = type; - expr._u._typecast._op1 = nullptr; - } else { - // A normal constructor call, with parameters. - expr._type = T_construct; - expr._u._typecast._to = type; - expr._u._typecast._op1 = op1; - } - return expr; -} - -/** - * Creates an expression that represents an aggregate initialization. - */ -CPPExpression CPPExpression:: -aggregate_init_op(CPPType *type, CPPExpression *op1) { - CPPExpression expr(0); - if (op1 == nullptr) { - expr._type = T_empty_aggregate_init; - } else { - expr._type = T_aggregate_init; - } - expr._u._typecast._to = type; - expr._u._typecast._op1 = op1; - return expr; -} - -/** - * Creates an expression that represents a use of the new operator. - */ -CPPExpression CPPExpression:: -new_op(CPPType *type, CPPExpression *op1) { - CPPExpression expr(0); - if (op1 == nullptr) { - // A default new operation--no parameters. - expr._type = T_default_new; - expr._u._typecast._to = type; - expr._u._typecast._op1 = nullptr; - } else { - // A normal new operation, with parameters. - expr._type = T_new; - expr._u._typecast._to = type; - expr._u._typecast._op1 = op1; - } - return expr; -} - -/** - * Creates an expression that represents a use of the typeid operator. - */ -CPPExpression CPPExpression:: -typeid_op(CPPType *type, CPPType *std_type_info) { - CPPExpression expr(0); - expr._type = T_typeid_type; - expr._u._typeid._type = type; - expr._u._typeid._std_type_info = std_type_info; - return expr; -} - -/** - * Creates an expression that represents a use of the typeid operator. - */ -CPPExpression CPPExpression:: -typeid_op(CPPExpression *op1, CPPType *std_type_info) { - CPPExpression expr(0); - expr._type = T_typeid_expr; - expr._u._typeid._expr = op1; - expr._u._typeid._std_type_info = std_type_info; - return expr; -} - -/** - * Creates an expression that returns a particular type trait. - */ -CPPExpression CPPExpression:: -type_trait(int trait, CPPType *type, CPPType *arg) { - CPPExpression expr(0); - expr._type = T_type_trait; - expr._u._type_trait._trait = trait; - expr._u._type_trait._type = type; - expr._u._type_trait._arg = arg; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -sizeof_func(CPPType *type) { - CPPExpression expr(0); - expr._type = T_sizeof_type; - expr._u._typecast._to = type; - expr._u._typecast._op1 = nullptr; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -sizeof_func(CPPExpression *op1) { - CPPExpression expr(0); - expr._type = T_sizeof_expr; - expr._u._typecast._to = nullptr; - expr._u._typecast._op1 = op1; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -sizeof_ellipsis_func(CPPIdentifier *ident) { - CPPExpression expr(0); - expr._type = T_sizeof_ellipsis; - expr._u._ident = ident; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -alignof_func(CPPType *type) { - CPPExpression expr(0); - expr._type = T_alignof; - expr._u._typecast._to = type; - expr._u._typecast._op1 = nullptr; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -lambda(CPPClosureType *type) { - CPPExpression expr(0); - expr._type = T_lambda; - expr._u._closure_type = type; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -literal(unsigned long long value, CPPInstance *lit_op) { - CPPExpression expr(0); - expr._type = T_literal; - expr._u._literal._value = new CPPExpression(value); - expr._u._literal._operator = lit_op; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -literal(long double value, CPPInstance *lit_op) { - CPPExpression expr(0); - expr._type = T_literal; - expr._u._literal._value = new CPPExpression(value); - expr._u._literal._operator = lit_op; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -literal(CPPExpression *value, CPPInstance *lit_op) { - CPPExpression expr(0); - expr._type = T_literal; - expr._u._literal._value = value; - expr._u._literal._operator = lit_op; - return expr; -} - -/** - * - */ -CPPExpression CPPExpression:: -raw_literal(const string &raw, CPPInstance *lit_op) { - CPPExpression expr(0); - expr._type = T_raw_literal; - expr._str = raw; - expr._u._literal._value = nullptr; - expr._u._literal._operator = lit_op; - return expr; -} - -/** - * - */ -const CPPExpression &CPPExpression:: -get_nullptr() { - static CPPExpression expr(0); - expr._type = T_nullptr; - return expr; -} - -/** - * - */ -const CPPExpression &CPPExpression:: -get_default() { - static CPPExpression expr(0); - expr._type = T_default; - return expr; -} - -/** - * - */ -const CPPExpression &CPPExpression:: -get_delete() { - static CPPExpression expr(0); - expr._type = T_delete; - return expr; -} - -/** - * - */ -CPPExpression::Result CPPExpression:: -evaluate() const { - Result r1, r2; - - switch (_type) { - case T_nullptr: - return Result(nullptr); - - case T_boolean: - return Result((int)_u._boolean); - - case T_integer: - return Result((int)_u._integer); - - case T_real: - return Result((double)_u._real); - - case T_string: - case T_wstring: - case T_u8string: - case T_u16string: - case T_u32string: - return Result(); - - case T_variable: - if (_u._variable->_type != nullptr && - _u._variable->_initializer != nullptr) { - // A constexpr variable, which is treated as const. - if (_u._variable->_storage_class & (CPPInstance::SC_constexpr | CPPInstance::SC_constinit)) { - return _u._variable->_initializer->evaluate(); - } - // A const variable. Fetch its assigned value. - CPPConstType *const_type = _u._variable->_type->as_const_type(); - if (const_type != nullptr) { - return _u._variable->_initializer->evaluate(); - } - } - return Result(); - - case T_function: - return Result(); - - case T_unknown_ident: - return Result(); - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - assert(_u._typecast._op1 != nullptr); - r1 = _u._typecast._op1->evaluate(); - if (r1._type != RT_error) { - CPPSimpleType *stype = _u._typecast._to->as_simple_type(); - if (stype != nullptr) { - if (stype->_type == CPPSimpleType::T_bool) { - return Result(r1.as_boolean()); - - } else if (stype->_type == CPPSimpleType::T_int) { - return Result(r1.as_integer()); - - } else if (stype->_type == CPPSimpleType::T_float || - stype->_type == CPPSimpleType::T_double) { - return Result(r1.as_real()); - } - } - if (_u._typecast._to->as_pointer_type()) { - return Result(r1.as_pointer()); - } - } - return Result(); - - case T_construct: - case T_default_construct: - case T_aggregate_init: - case T_empty_aggregate_init: - case T_new: - case T_default_new: - case T_sizeof_type: - case T_sizeof_expr: - case T_sizeof_ellipsis: - return Result(); - - case T_alignof: - if (_u._typecast._to != nullptr) { - // Check if the type is defined with an alignas. TODO: this should - // probably be moved to a virtual getter on CPPType. - CPPExtensionType *etype = _u._typecast._to->as_extension_type(); - if (etype != nullptr && etype->_alignment != nullptr) { - return etype->_alignment->evaluate(); - } - } - return Result(); - - case T_binary_operation: - assert(_u._op._op2 != nullptr); - r2 = _u._op._op2->evaluate(); - - // The operators && and || are special cases: these are shirt-circuiting - // operators. Thus, if we are using either of these it might be - // acceptable for the second operand to be invalid, since we might never - // evaluate it. - - // In all other cases, both operands must be valid in order for the - // operation to be valid. - if (r2._type == RT_error && - (_u._op._operator != OROR && _u._op._operator != ANDAND)) { - return r2; - } - // Fall through - - - case T_trinary_operation: - // The trinary operator is also a short-circuiting operator: we don't test - // the second or third operands until we need them. The only critical one - // is the first operand. - - // Fall through - - case T_unary_operation: - assert(_u._op._op1 != nullptr); - r1 = _u._op._op1->evaluate(); - if (r1._type == RT_error) { - // Here's one more special case: if the first operand is invalid, it - // really means we don't know how to evaluate it. However, if the - // operator is ||, then it might not matter as long as we can evaluate - // the second one *and* that comes out to be true. - if (_u._op._operator == OROR && r2._type == RT_integer && - r2.as_boolean()) { - return r2; - } - - // Ditto for the operator being && and the second one coming out false. - if (_u._op._operator == ANDAND && r2._type == RT_integer && - !r2.as_boolean()) { - return r2; - } - - // Also for the operator being [] and the operand being a string. - if (_u._op._operator == '[' && r2._type == RT_integer && - (_u._op._op1->_type == T_string || - _u._op._op1->_type == T_u8string)) { - - int index = (int)r2.as_integer(); - if ((size_t)index == _u._op._op1->_str.size()) { - return Result(0); - } else if (index >= 0 && (size_t)index < _u._op._op1->_str.size()) { - return Result(_u._op._op1->_str[(size_t)index]); - } else { - cerr << "array index " << index << " out of bounds of string literal " - << *_u._op._op1 << "\n"; - } - } - - return r1; - } - - switch (_u._op._operator) { - case UNARY_NOT: - return Result(!r1.as_boolean()); - - case UNARY_NEGATE: - return Result(~r1.as_integer()); - - case UNARY_MINUS: - return (r1._type == RT_real) ? Result(-r1.as_real()) : Result(-r1.as_integer()); - - case UNARY_PLUS: - return r1; - - case UNARY_STAR: - case UNARY_REF: - return Result(); - - case '*': - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() * r2.as_real()); - } else { - return Result(r1.as_integer() * r2.as_integer()); - } - - case '/': - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() / r2.as_real()); - } else { - return Result(r1.as_integer() / r2.as_integer()); - } - - case '%': - return Result(r1.as_integer() % r2.as_integer()); - - case '+': - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() + r2.as_real()); - } else { - return Result(r1.as_integer() + r2.as_integer()); - } - - case '-': - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() - r2.as_real()); - } else { - return Result(r1.as_integer() - r2.as_integer()); - } - - case '|': - return Result(r1.as_integer() | r2.as_integer()); - - case '&': - return Result(r1.as_integer() & r2.as_integer()); - - case OROR: - if (r1.as_boolean()) { - return r1; - } else { - return r2; - } - - case ANDAND: - if (r1.as_boolean()) { - return r2; - } else { - return r1; - } - - case EQCOMPARE: - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() == r2.as_real()); - } else { - return Result(r1.as_integer() == r2.as_integer()); - } - - case NECOMPARE: - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() != r2.as_real()); - } else { - return Result(r1.as_integer() != r2.as_integer()); - } - - case LECOMPARE: - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() <= r2.as_real()); - } else { - return Result(r1.as_integer() <= r2.as_integer()); - } - - case GECOMPARE: - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() >= r2.as_real()); - } else { - return Result(r1.as_integer() >= r2.as_integer()); - } - - case SPACESHIP: - if (r1._type == RT_real || r2._type == RT_real) { - return Result((r1.as_real() > r2.as_real()) - (r1.as_real() < r2.as_real())); - } else { - return Result((r1.as_integer() > r2.as_integer()) - (r1.as_integer() < r2.as_integer())); - } - - case '<': - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() < r2.as_real()); - } else { - return Result(r1.as_integer() < r2.as_integer()); - } - - case '>': - if (r1._type == RT_real || r2._type == RT_real) { - return Result(r1.as_real() > r2.as_real()); - } else { - return Result(r1.as_integer() > r2.as_integer()); - } - - case LSHIFT: - return Result(r1.as_integer() << r2.as_integer()); - - case RSHIFT: - return Result(r1.as_integer() >> r2.as_integer()); - - case '?': - return r1.as_integer() ? - _u._op._op2->evaluate() : _u._op._op3->evaluate(); - - case '.': - case POINTSAT: - return Result(); - - case '[': // Array element reference - return Result(); - - case 'f': // Function evaluation - return Result(); - - case ',': - return r2; - - case KW_NOEXCEPT: - return Result(); - - default: - cerr << "**unexpected operator**\n"; - abort(); - } - - case T_literal: - case T_raw_literal: - return Result(); - - case T_typeid_type: - case T_typeid_expr: - return Result(); - - case T_type_trait: - switch (_u._type_trait._trait) { - case KW_HAS_VIRTUAL_DESTRUCTOR: - { - CPPStructType *struct_type = _u._type_trait._type->as_struct_type(); - return Result(struct_type != nullptr && struct_type->has_virtual_destructor()); - } - - case KW_IS_ABSTRACT: - { - CPPStructType *struct_type = _u._type_trait._type->as_struct_type(); - return Result(struct_type != nullptr && struct_type->is_abstract()); - } - - case KW_IS_BASE_OF: - { - CPPStructType *struct_type1 = _u._type_trait._type->as_struct_type(); - CPPStructType *struct_type2 = _u._type_trait._arg->as_struct_type(); - return Result(struct_type1 != nullptr && struct_type2 != nullptr && struct_type1->is_base_of(struct_type2)); - } - - case KW_IS_CLASS: - { - CPPExtensionType *ext_type = _u._type_trait._type->as_extension_type(); - return Result(ext_type != nullptr && ( - ext_type->_type == CPPExtensionType::T_class || - ext_type->_type == CPPExtensionType::T_struct)); - } - - case KW_IS_CONSTRUCTIBLE: - if (_u._type_trait._arg == nullptr) { - return Result(_u._type_trait._type->is_default_constructible()); - } else { - return Result(_u._type_trait._type->is_constructible(_u._type_trait._arg)); - } - - case KW_IS_CONVERTIBLE_TO: - assert(_u._type_trait._arg != nullptr); - return Result(_u._type_trait._type->is_convertible_to(_u._type_trait._arg)); - - case KW_IS_DESTRUCTIBLE: - return Result(_u._type_trait._type->is_destructible()); - - case KW_IS_EMPTY: - { - CPPStructType *struct_type = _u._type_trait._type->as_struct_type(); - return Result(struct_type != nullptr && struct_type->is_empty()); - } - - case KW_IS_ENUM: - return Result(_u._type_trait._type->is_enum()); - - case KW_IS_FINAL: - { - CPPStructType *struct_type = _u._type_trait._type->as_struct_type(); - return Result(struct_type != nullptr && struct_type->is_final()); - } - - case KW_IS_FUNDAMENTAL: - return Result(_u._type_trait._type->is_fundamental()); - - case KW_IS_POD: - return Result(_u._type_trait._type->is_trivial() && - _u._type_trait._type->is_standard_layout()); - - case KW_IS_POLYMORPHIC: - { - CPPStructType *struct_type = _u._type_trait._type->as_struct_type(); - return Result(struct_type != nullptr && struct_type->is_polymorphic()); - } - - case KW_IS_STANDARD_LAYOUT: - return Result(_u._type_trait._type->is_standard_layout()); - - case KW_IS_TRIVIAL: - return Result(_u._type_trait._type->is_trivial()); - - case KW_IS_TRIVIALLY_COPYABLE: - return Result(_u._type_trait._type->is_trivially_copyable()); - - case KW_IS_UNION: - { - CPPExtensionType *ext_type = _u._type_trait._type->as_extension_type(); - return Result(ext_type != nullptr && - ext_type->_type == CPPExtensionType::T_union); - } - - default: - cerr << "**unexpected type trait**\n"; - abort(); - } - - default: - cerr << "**invalid operand**\n"; - abort(); - } - - return Result(); // Compiler kludge; can't get here. -} - -/** - * Returns the type of the expression, if it is known, or NULL if the type - * cannot be determined. - */ -CPPType *CPPExpression:: -determine_type() const { - CPPType *t1 = nullptr; - CPPType *t2 = nullptr; - - static CPPType *nullptr_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_nullptr)); - - static CPPType *int_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int)); - - static CPPType *unsigned_long_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int, - CPPSimpleType::F_unsigned | - CPPSimpleType::F_long)); - - static CPPType *bool_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_bool)); - - static CPPType *float_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_double)); - - static CPPType *char_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char)); - - static CPPType *wchar_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t)); - - static CPPType *char16_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t)); - - static CPPType *char32_type = - CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t)); - - static CPPType *char_str_type = CPPType::new_type( - new CPPPointerType(CPPType::new_type(new CPPConstType(char_type)))); - - static CPPType *wchar_str_type = CPPType::new_type( - new CPPPointerType(CPPType::new_type(new CPPConstType(wchar_type)))); - - static CPPType *char16_str_type = CPPType::new_type( - new CPPPointerType(CPPType::new_type(new CPPConstType(char16_type)))); - - static CPPType *char32_str_type = CPPType::new_type( - new CPPPointerType(CPPType::new_type(new CPPConstType(char32_type)))); - - switch (_type) { - case T_nullptr: - return nullptr_type; - - case T_boolean: - return bool_type; - - case T_integer: - return int_type; - - case T_real: - return float_type; - - case T_string: - return char_str_type; - - case T_wstring: - return wchar_str_type; - - case T_u8string: - return char_str_type; - - case T_u16string: - return char16_str_type; - - case T_u32string: - return char32_str_type; - - case T_variable: - return _u._variable->_type; - - case T_function: - if (_u._fgroup->get_return_type() == nullptr) { - // There are multiple functions by this name that have different return - // types. We could attempt to differentiate them based on the parameter - // list, but that's a lot of work. Let's just give up. - return nullptr; - } - return _u._fgroup->_instances.front()->_type; - - case T_unknown_ident: - return nullptr; - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - case T_construct: - case T_default_construct: - case T_aggregate_init: - case T_empty_aggregate_init: - return _u._typecast._to; - - case T_new: - case T_default_new: - return CPPType::new_type(new CPPPointerType(_u._typecast._to)); - - case T_sizeof_type: - case T_sizeof_expr: - case T_sizeof_ellipsis: - case T_alignof: - // Note: this should actually be size_t, but that is defined as a typedef - // in parser-inc. We could try to resolve it, but that's hacky. Eh, it's - // probably not worth the effort to get this right. - return unsigned_long_type; - - case T_binary_operation: - case T_trinary_operation: - assert(_u._op._op2 != nullptr); - t2 = _u._op._op2->determine_type(); - // Fall through - - case T_unary_operation: - assert(_u._op._op1 != nullptr); - t1 = _u._op._op1->determine_type(); - - switch (_u._op._operator) { - case UNARY_NOT: - return bool_type; - - case UNARY_NEGATE: - return int_type; - - case UNARY_MINUS: - case UNARY_PLUS: - if (t1 != nullptr) { - switch (t1->get_subtype()) { - case CPPDeclaration::ST_array: - // Decay into pointer. - return CPPType::new_type(new CPPPointerType(t1->as_array_type()->_element_type)); - - case CPPDeclaration::ST_enum: - // Convert into integral type. - return t1->as_enum_type()->get_underlying_type(); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = t1->as_simple_type(); - if ((simple_type->_flags & CPPSimpleType::F_short) != 0 || - simple_type->_type == CPPSimpleType::T_bool || - simple_type->_type == CPPSimpleType::T_wchar_t || - simple_type->_type == CPPSimpleType::T_char16_t) { - // Integer promotion. - return int_type; - } - } - // Fall through. - default: - return t1; - } - } - return nullptr; - - case UNARY_STAR: - case '[': // Array element reference - if (t1 != nullptr) { - if (t1->as_pointer_type()) { - return t1->as_pointer_type()->_pointing_at; - } - if (t1->as_array_type()) { - return t1->as_array_type()->_element_type; - } - } - return nullptr; - - case UNARY_REF: - return t1; - - case '*': - case '/': - case '+': - case '-': - if (t1 == nullptr) { - return t2; - } else if (t2 == nullptr) { - return t1; - } else if (t1->as_pointer_type()) { - if (t2->as_pointer_type()) { - return int_type; - } - return t1; - } - return elevate_type(t1, t2); - - case '%': - case '|': - case '&': - case LSHIFT: - case RSHIFT: - return int_type; - - case OROR: - case ANDAND: - case EQCOMPARE: - case NECOMPARE: - case LECOMPARE: - case GECOMPARE: - case '<': - case '>': - case KW_NOEXCEPT: - return bool_type; - - case SPACESHIP: - return nullptr; - - case '?': - return t2; - - case '.': - case POINTSAT: - return nullptr; - - case 'f': // Function evaluation - if (t1 != nullptr) { - // Easy case, function with only a single overload. - CPPFunctionType *ftype = t1->as_function_type(); - if (ftype != nullptr) { - return ftype->_return_type; - } - } else if (_u._op._op1->_type == T_function) { - CPPFunctionGroup *fgroup = _u._op._op1->_u._fgroup; - if (_u._op._op2 == nullptr) { - // If we are passing no args, look for an overload that has takes no - // args. - for (auto it = fgroup->_instances.begin(); it != fgroup->_instances.end(); ++it) { - CPPInstance *inst = *it; - if (inst != nullptr && inst->_type != nullptr) { - CPPFunctionType *type = inst->_type->as_function_type(); - if (type != nullptr && type->accepts_num_parameters(0)) { - return type->_return_type; - } - } - } - } else { - //TODO - } - } - return nullptr; - - case ',': - return t2; - - default: - cerr << "**unexpected operator**\n"; - abort(); - } - - case T_literal: - case T_raw_literal: - if (_u._literal._operator != nullptr) { - CPPType *type = _u._literal._operator->_type; - - CPPFunctionType *ftype = type->as_function_type(); - if (ftype != nullptr) { - return ftype->_return_type; - } - } - return nullptr; - - case T_typeid_type: - case T_typeid_expr: - return _u._typeid._std_type_info; - - case T_type_trait: - return bool_type; - - case T_lambda: - return _u._closure_type; - - default: - cerr << "**invalid operand**\n"; - abort(); - } - - return nullptr; // Compiler kludge; can't get here. -} - -/** - * Returns true if this is an lvalue expression. - */ -bool CPPExpression:: -is_lvalue() const { - switch (_type) { - case T_variable: - case T_function: - case T_unknown_ident: - return true; - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - { - CPPReferenceType *ref_type = _u._typecast._to->as_reference_type(); - return ref_type != nullptr && ref_type->_value_category == CPPReferenceType::VC_lvalue; - } - - case T_unary_operation: - if (_u._op._operator == 'f') { - // A function returning an lvalue reference. - CPPType *return_type = determine_type(); - if (return_type != nullptr) { - CPPReferenceType *ref_type = return_type->as_reference_type(); - return ref_type != nullptr && ref_type->_value_category == CPPReferenceType::VC_lvalue; - } - } - return _u._op._operator == PLUSPLUS - || _u._op._operator == MINUSMINUS - || _u._op._operator == '*'; - - case T_binary_operation: - if (_u._op._operator == ',') { - CPPReferenceType *ref_type = _u._op._op2->as_reference_type(); - return ref_type != nullptr && ref_type->_value_category == CPPReferenceType::VC_lvalue; - } - return (_u._op._operator == POINTSAT || _u._op._operator == ','); - - case T_trinary_operation: - return _u._op._op2->is_lvalue() && _u._op._op3->is_lvalue(); - - case T_literal: - case T_raw_literal: - return true; - - default: - break; - } - - return false; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPExpression:: -is_fully_specified() const { - if (!CPPDeclaration::is_fully_specified()) { - return false; - } - - switch (_type) { - case T_nullptr: - case T_boolean: - case T_integer: - case T_real: - case T_string: - case T_wstring: - case T_u8string: - case T_u16string: - case T_u32string: - return false; - - case T_variable: - return _u._variable->is_fully_specified(); - - case T_function: - return _u._fgroup->is_fully_specified(); - - case T_unknown_ident: - return _u._ident->is_fully_specified(); - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - case T_construct: - case T_aggregate_init: - case T_new: - return (_u._typecast._to->is_fully_specified() && - _u._typecast._op1->is_fully_specified()); - - case T_default_construct: - case T_empty_aggregate_init: - case T_default_new: - case T_sizeof_type: - case T_alignof: - return _u._typecast._to->is_fully_specified(); - - case T_sizeof_expr: - return _u._typecast._op1->is_fully_specified(); - - case T_sizeof_ellipsis: - return _u._ident->is_fully_specified(); - - case T_trinary_operation: - if (!_u._op._op3->is_fully_specified()) { - return false; - } - // Fall through - - case T_binary_operation: - if (!_u._op._op2->is_fully_specified()) { - return false; - } - // Fall through - - case T_unary_operation: - return _u._op._op1->is_fully_specified(); - - case T_literal: - return _u._literal._value->is_fully_specified() && - _u._literal._operator->is_fully_specified(); - - case T_raw_literal: - return _u._literal._value->is_fully_specified(); - - case T_typeid_type: - return _u._typeid._type->is_fully_specified(); - - case T_typeid_expr: - return _u._typeid._expr->is_fully_specified(); - - case T_type_trait: - return _u._type_trait._type->is_fully_specified(); - - case T_lambda: - return _u._closure_type->is_fully_specified(); - - default: - return true; - } -} - -/** - * - */ -CPPDeclaration *CPPExpression:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - CPPDeclaration *top = - CPPDeclaration::substitute_decl(subst, current_scope, global_scope); - if (top != this) { - return top; - } - - CPPExpression *rep = new CPPExpression(*this); - bool any_changed = false; - CPPDeclaration *decl; - - switch (_type) { - case T_variable: - decl = _u._variable->substitute_decl(subst, current_scope, global_scope); - if (decl != rep->_u._variable) { - if (decl->as_instance()) { - // Replacing the variable reference with another variable reference. - rep->_u._variable = decl->as_instance(); - any_changed = true; - - } else if (decl->as_expression()) { - // Replacing the variable reference with an expression. - delete rep; - rep = decl->as_expression(); - any_changed = true; - } - } - break; - - case T_unknown_ident: - rep->_u._ident = _u._ident->substitute_decl(subst, current_scope, global_scope); - any_changed = any_changed || (rep->_u._ident != _u._ident); - - // See if we can define it now. - decl = rep->_u._ident->find_symbol(current_scope, global_scope, subst); - if (decl != nullptr) { - CPPInstance *inst = decl->as_instance(); - if (inst != nullptr) { - rep->_type = T_variable; - rep->_u._variable = inst; - any_changed = true; - - decl = inst->substitute_decl(subst, current_scope, global_scope); - if (decl != inst) { - if (decl->as_instance()) { - // Replacing the variable reference with another variable - // reference. - rep->_u._variable = decl->as_instance(); - - } else if (decl->as_expression()) { - // Replacing the variable reference with an expression. - delete rep; - rep = decl->as_expression(); - } - } - break; - } - CPPFunctionGroup *fgroup = decl->as_function_group(); - if (fgroup != nullptr) { - rep->_type = T_function; - rep->_u._fgroup = fgroup; - any_changed = true; - } - } - - break; - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - case T_construct: - case T_aggregate_init: - case T_new: - rep->_u._typecast._op1 = - _u._typecast._op1->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - any_changed = any_changed || (rep->_u._typecast._op1 != _u._typecast._op1); - // fall through - - case T_default_construct: - case T_empty_aggregate_init: - case T_default_new: - case T_sizeof_type: - case T_alignof: - rep->_u._typecast._to = - _u._typecast._to->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - any_changed = any_changed || (rep->_u._typecast._to != _u._typecast._to); - break; - - case T_sizeof_expr: - rep->_u._typecast._op1 = - _u._typecast._op1->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - any_changed = any_changed || (rep->_u._typecast._op1 != _u._typecast._op1); - break; - - case T_trinary_operation: - rep->_u._op._op3 = - _u._op._op3->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - any_changed = any_changed || (rep->_u._op._op3 != _u._op._op3); - // fall through - - case T_binary_operation: - rep->_u._op._op2 = - _u._op._op2->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - any_changed = any_changed || (rep->_u._op._op2 != _u._op._op2); - // fall through - - case T_unary_operation: - rep->_u._op._op1 = - _u._op._op1->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - any_changed = any_changed || (rep->_u._op._op1 != _u._op._op1); - break; - - case T_typeid_type: - rep->_u._typeid._type = - _u._typeid._type->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - any_changed = any_changed || (rep->_u._typeid._type != _u._typeid._type); - break; - - case T_typeid_expr: - rep->_u._typeid._expr = - _u._typeid._expr->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - any_changed = any_changed || (rep->_u._typeid._expr != _u._typeid._expr); - break; - - case T_type_trait: - rep->_u._type_trait._type = - _u._type_trait._type->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - any_changed = any_changed || (rep->_u._type_trait._type != _u._type_trait._type); - break; - - default: - break; - } - - if (!any_changed) { - delete rep; - rep = this; - } - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - - -/** - * Returns true if any type within the expression list is a CPPTBDType and - * thus isn't fully determined right now. - */ -bool CPPExpression:: -is_tbd() const { - switch (_type) { - case T_variable: - if (_u._variable->_type != nullptr && - _u._variable->_initializer != nullptr) { - if (_u._variable->_storage_class & (CPPInstance::SC_constexpr | CPPInstance::SC_constinit)) { - return false; - } - CPPConstType *const_type = _u._variable->_type->as_const_type(); - if (const_type != nullptr) { - return false; - } - } - - return true; - - case T_unknown_ident: - return true; - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - case T_construct: - case T_aggregate_init: - case T_empty_aggregate_init: - case T_new: - case T_default_construct: - case T_default_new: - case T_sizeof_type: - case T_alignof: - return _u._typecast._to->is_tbd(); - - case T_sizeof_expr: - return _u._typecast._op1->is_tbd(); - - case T_trinary_operation: - if (_u._op._op3->is_tbd()) { - return true; - } - // fall through - - case T_binary_operation: - if (_u._op._op2->is_tbd()) { - return true; - } - // fall through - - case T_unary_operation: - if (_u._op._op1->is_tbd()) { - return true; - } - return false; - - case T_typeid_type: - return _u._typeid._type->is_tbd(); - - case T_typeid_expr: - return _u._typeid._expr->is_tbd(); - - case T_type_trait: - return _u._type_trait._type->is_tbd(); - - case T_lambda: - return _u._closure_type->is_tbd(); - - default: - return false; - } -} - -/** - * - */ -void CPPExpression:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool) const { - switch (_type) { - case T_nullptr: - out << "nullptr"; - break; - - case T_boolean: - out << (_u._boolean ? "true" : "false"); - break; - - case T_integer: - out << _u._integer; - break; - - case T_real: - { - // We use our own dtoa implementation here because it guarantees to - // never format the number as an integer. - char buffer[32]; - pdtoa(_u._real, buffer); - out << buffer; - } - break; - - case T_string: - case T_wstring: - case T_u8string: - case T_u16string: - case T_u32string: - { - switch (_type) { - case T_wstring: - out << 'L'; - break; - case T_u8string: - out << "u8"; - break; - case T_u16string: - out << "u"; - break; - case T_u32string: - out << "U"; - break; - default: - break; - } - // We don't really care about preserving the encoding for now. - out << '"'; - string::const_iterator si; - for (si = _str.begin(); si != _str.end(); ++si) { - switch (*si) { - case '\n': - out << "\\n"; - break; - - case '\t': - out << "\\t"; - break; - - case '\r': - out << "\\r"; - break; - - case '\a': - out << "\\a"; - break; - - case '"': - out << "\\\""; - break; - - case '\\': - out << "\\\\"; - break; - - default: - if (isprint(*si)) { - out << *si; - } else { - out << '\\' << std::oct << std::setw(3) << std::setfill('0') << (int)(*si) - << std::dec << std::setw(0); - } - } - } - } - out << '"'; - break; - - case T_variable: - // We can just refer to the variable by name, except if it's a private - // constant, in which case we have to compute the value, since we may have - // to use it in generated code. - if (_u._variable->_type != nullptr && - _u._variable->_initializer != nullptr && - _u._variable->_vis > V_public) { - // A constexpr or const variable. Fetch its assigned value. - CPPConstType *const_type = _u._variable->_type->as_const_type(); - if ((_u._variable->_storage_class & CPPInstance::SC_constexpr) != 0 || - const_type != nullptr) { - _u._variable->_initializer->output(out, indent_level, scope, false); - break; - } - } - _u._variable->_ident->output(out, scope); - break; - - case T_function: - // Pick any instance; they all have the same name anyway. - if (!_u._fgroup->_instances.empty() && _u._fgroup->_instances[0]->_ident != nullptr) { - _u._fgroup->_instances[0]->_ident->output(out, scope); - } else { - out << _u._fgroup->_name; - } - break; - - case T_unknown_ident: - _u._ident->output(out, scope); - break; - - case T_typecast: - out << "("; - _u._typecast._to->output(out, indent_level, scope, false); - out << ")("; - _u._typecast._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_static_cast: - out << "static_cast<"; - _u._typecast._to->output(out, indent_level, scope, false); - out << ">("; - _u._typecast._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_dynamic_cast: - out << "dynamic_cast<"; - _u._typecast._to->output(out, indent_level, scope, false); - out << ">("; - _u._typecast._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_const_cast: - out << "const_cast<"; - _u._typecast._to->output(out, indent_level, scope, false); - out << ">("; - _u._typecast._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_reinterpret_cast: - out << "reinterpret_cast<"; - _u._typecast._to->output(out, indent_level, scope, false); - out << ">("; - _u._typecast._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_construct: - _u._typecast._to->output(out, indent_level, scope, false); - out << "("; - _u._typecast._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_default_construct: - _u._typecast._to->output(out, indent_level, scope, false); - out << "()"; - break; - - case T_aggregate_init: - _u._typecast._to->output(out, indent_level, scope, false); - out << "{"; - _u._typecast._op1->output(out, indent_level, scope, false); - out << "}"; - break; - - case T_empty_aggregate_init: - _u._typecast._to->output(out, indent_level, scope, false); - out << "{}"; - break; - - case T_new: - out << "(new "; - _u._typecast._to->output(out, indent_level, scope, false); - out << "("; - _u._typecast._op1->output(out, indent_level, scope, false); - out << "))"; - break; - - case T_default_new: - out << "(new "; - _u._typecast._to->output(out, indent_level, scope, false); - out << "())"; - break; - - case T_sizeof_type: - out << "sizeof("; - _u._typecast._to->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_sizeof_expr: - out << "sizeof "; - _u._typecast._op1->output(out, indent_level, scope, false); - break; - - case T_sizeof_ellipsis: - out << "sizeof...("; - _u._ident->output(out, scope); - out << ")"; - break; - - case T_alignof: - out << "alignof("; - _u._typecast._to->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_unary_operation: - switch (_u._op._operator) { - case UNARY_NOT: - out << "(! "; - _u._op._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case UNARY_NEGATE: - out << "(~ "; - _u._op._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case UNARY_MINUS: - out << '-'; - _u._op._op1->output(out, indent_level, scope, false); - break; - - case UNARY_PLUS: - out << '+'; - _u._op._op1->output(out, indent_level, scope, false); - break; - - case UNARY_STAR: - out << "(* "; - _u._op._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case UNARY_REF: - out << "(& "; - _u._op._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - case 'f': // Function evaluation, no parameters. - _u._op._op1->output(out, indent_level, scope, false); - out << "()"; - break; - - case KW_NOEXCEPT: - out << "noexcept("; - _u._op._op1->output(out, indent_level, scope, false); - out << ")"; - break; - - default: - out << "(" << (char)_u._op._operator << " "; - _u._op._op1->output(out, indent_level, scope, false); - out << ")"; - break; - } - break; - - case T_binary_operation: - switch (_u._op._operator) { - case OROR: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " || "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case ANDAND: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " && "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case EQCOMPARE: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " == "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case NECOMPARE: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " != "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case LECOMPARE: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " <= "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case GECOMPARE: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " >= "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case SPACESHIP: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " <=> "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case LSHIFT: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " << "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case RSHIFT: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " >> "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - break; - - case '.': - _u._op._op1->output(out, indent_level, scope, false); - out << "."; - _u._op._op2->output(out, indent_level, scope, false); - break; - - case POINTSAT: - _u._op._op1->output(out, indent_level, scope, false); - out << "->"; - _u._op._op2->output(out, indent_level, scope, false); - break; - - case '[': // Array element reference - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << "["; - _u._op._op2->output(out, indent_level, scope, false); - out << "])"; - break; - - case 'f': // Function evaluation - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << "("; - _u._op._op2->output(out, indent_level, scope, false); - out << "))"; - break; - - case ',': // Comma, no parens are used - _u._op._op1->output(out, indent_level, scope, false); - out << ", "; - _u._op._op2->output(out, indent_level, scope, false); - break; - - default: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " " << (char)_u._op._operator << " "; - _u._op._op2->output(out, indent_level, scope, false); - out << ")"; - } - break; - - case T_trinary_operation: - out << "("; - _u._op._op1->output(out, indent_level, scope, false); - out << " ? "; - _u._op._op2->output(out, indent_level, scope, false); - out << " : "; - _u._op._op3->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_literal: - _u._literal._value->output(out, indent_level, scope, false); - if (_u._literal._operator != nullptr) { - string name = _u._literal._operator->get_simple_name(); - assert(name.substr(0, 12) == "operator \"\" "); - out << name.substr(12); - } - break; - - case T_raw_literal: - out << _str; - if (_u._literal._operator != nullptr) { - string name = _u._literal._operator->get_simple_name(); - assert(name.substr(0, 12) == "operator \"\" "); - out << name.substr(12); - } - break; - - case T_typeid_type: - out << "typeid("; - _u._typeid._type->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_typeid_expr: - out << "typeid("; - _u._typeid._expr->output(out, indent_level, scope, false); - out << ")"; - break; - - case T_default: - out << "default"; - break; - - case T_delete: - out << "delete"; - break; - - case T_type_trait: - switch (_u._type_trait._trait) { - case KW_HAS_VIRTUAL_DESTRUCTOR: - out << "__has_virtual_destructor"; - break; - case KW_IS_ABSTRACT: - out << "__is_abstract"; - break; - case KW_IS_BASE_OF: - out << "__is_base_of"; - break; - case KW_IS_CLASS: - out << "__is_class"; - break; - case KW_IS_CONSTRUCTIBLE: - out << "__is_constructible"; - break; - case KW_IS_CONVERTIBLE_TO: - out << "__is_convertible_to"; - break; - case KW_IS_DESTRUCTIBLE: - out << "__is_destructible"; - break; - case KW_IS_EMPTY: - out << "__is_empty"; - break; - case KW_IS_ENUM: - out << "__is_enum"; - break; - case KW_IS_FINAL: - out << "__is_final"; - break; - case KW_IS_FUNDAMENTAL: - out << "__is_fundamental"; - break; - case KW_IS_POD: - out << "__is_pod"; - break; - case KW_IS_POLYMORPHIC: - out << "__is_polymorphic"; - break; - case KW_IS_STANDARD_LAYOUT: - out << "__is_standard_layout"; - break; - case KW_IS_TRIVIAL: - out << "__is_trivial"; - break; - case KW_IS_TRIVIALLY_COPYABLE: - out << "__is_trivially_copyable"; - break; - case KW_IS_UNION: - out << "__is_union"; - break; - default: - out << (evaluate().as_boolean() ? "true" : "false"); - return; - } - out << '('; - _u._type_trait._type->output(out, indent_level, scope, false); - out << ')'; - break; - - case T_lambda: - _u._closure_type->output(out, indent_level, scope, false); - break; - - default: - out << "(** invalid operand type " << (int)_type << " **)"; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPExpression:: -get_subtype() const { - return ST_expression; -} - -/** - * - */ -CPPExpression *CPPExpression:: -as_expression() { - return this; -} - -/** - * Returns the most general of the two given types. - */ -CPPType *CPPExpression:: -elevate_type(CPPType *t1, CPPType *t2) { - CPPSimpleType *st1 = t1->as_simple_type(); - CPPSimpleType *st2 = t2->as_simple_type(); - - if (st1 == nullptr || st2 == nullptr) { - // Nothing we can do about this. Who knows? - return nullptr; - } - - if (st1->_type == st2->_type) { - // They have the same type, so return the one with the largest flag bits. - if (st1->_flags & CPPSimpleType::F_longlong) { - return st1; - } else if (st2->_flags & CPPSimpleType::F_longlong) { - return st2; - } else if (st1->_flags & CPPSimpleType::F_long) { - return st1; - } else if (st2->_flags & CPPSimpleType::F_long) { - return st2; - } else if (st1->_flags & CPPSimpleType::F_short) { - return st2; - } else if (st2->_flags & CPPSimpleType::F_short) { - return st1; - } - return st1; - } - - // They have different types. - if (st1->_type == CPPSimpleType::T_float || - st1->_type == CPPSimpleType::T_double) { - return st1; - } else if (st2->_type == CPPSimpleType::T_float || - st2->_type == CPPSimpleType::T_double) { - return st2; - } else if (st1->_type == CPPSimpleType::T_int) { - return st1; - } else if (st2->_type == CPPSimpleType::T_int) { - return st2; - } else if (st1->_type == CPPSimpleType::T_bool) { - return st1; - } else if (st2->_type == CPPSimpleType::T_bool) { - return st2; - } - return st1; -} - -/** - * Called by CPPDeclaration to determine whether this expr is equivalent to - * another expr. - */ -bool CPPExpression:: -is_equal(const CPPDeclaration *other) const { - const CPPExpression *ot = ((CPPDeclaration *)other)->as_expression(); - assert(ot != nullptr); - - if (_type != ot->_type) { - return false; - } - - switch (_type) { - case T_nullptr: - return true; - - case T_boolean: - return _u._boolean == ot->_u._boolean; - - case T_integer: - return _u._integer == ot->_u._integer; - - case T_real: - return _u._real == ot->_u._real; - - case T_string: - case T_wstring: - case T_u8string: - case T_u16string: - case T_u32string: - return _str == ot->_str; - - case T_variable: - return _u._variable == ot->_u._variable; - - case T_function: - return _u._fgroup == ot->_u._fgroup; - - case T_unknown_ident: - case T_sizeof_ellipsis: - return *_u._ident == *ot->_u._ident; - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - case T_construct: - case T_aggregate_init: - case T_new: - return _u._typecast._to == ot->_u._typecast._to && - *_u._typecast._op1 == *ot->_u._typecast._op1; - - case T_default_construct: - case T_empty_aggregate_init: - case T_default_new: - case T_sizeof_type: - case T_alignof: - return _u._typecast._to == ot->_u._typecast._to; - - case T_sizeof_expr: - return _u._typecast._op1 == ot->_u._typecast._op1; - - case T_unary_operation: - return *_u._op._op1 == *ot->_u._op._op1; - - case T_binary_operation: - return *_u._op._op1 == *ot->_u._op._op1 && - *_u._op._op2 == *ot->_u._op._op2; - - case T_trinary_operation: - return *_u._op._op1 == *ot->_u._op._op1 && - *_u._op._op2 == *ot->_u._op._op2; - - case T_literal: - return *_u._literal._value == *ot->_u._literal._value && - _u._literal._operator == ot->_u._literal._operator; - - case T_raw_literal: - return _str == ot->_str && - _u._literal._operator == ot->_u._literal._operator; - - case T_typeid_type: - return _u._typeid._type == ot->_u._typeid._type; - - case T_typeid_expr: - return _u._typeid._expr == ot->_u._typeid._expr; - - case T_type_trait: - return _u._type_trait._trait == ot->_u._type_trait._trait && - _u._type_trait._type == ot->_u._type_trait._type; - - case T_lambda: - return _u._closure_type == ot->_u._closure_type; - - default: - cerr << "(** invalid operand type " << (int)_type << " **)"; - } - - return true; -} - -/** - * Called by CPPDeclaration to determine whether this expr should be ordered - * before another expr of the same type, in an arbitrary but fixed ordering. - */ -bool CPPExpression:: -is_less(const CPPDeclaration *other) const { - const CPPExpression *ot = ((CPPDeclaration *)other)->as_expression(); - assert(ot != nullptr); - - if (_type != ot->_type) { - return (int)_type < (int)ot->_type; - } - - switch (_type) { - case T_nullptr: - return false; - - case T_boolean: - return _u._boolean < ot->_u._boolean; - - case T_integer: - return _u._integer < ot->_u._integer; - - case T_real: - return _u._real < ot->_u._real; - - case T_string: - case T_wstring: - case T_u8string: - case T_u16string: - case T_u32string: - return _str < ot->_str; - - case T_variable: - return _u._variable < ot->_u._variable; - - case T_function: - return *_u._fgroup < *ot->_u._fgroup; - - case T_unknown_ident: - case T_sizeof_ellipsis: - return *_u._ident < *ot->_u._ident; - - case T_typecast: - case T_static_cast: - case T_dynamic_cast: - case T_const_cast: - case T_reinterpret_cast: - case T_construct: - case T_aggregate_init: - case T_new: - if (_u._typecast._to != ot->_u._typecast._to) { - return _u._typecast._to < ot->_u._typecast._to; - } - return *_u._typecast._op1 < *ot->_u._typecast._op1; - - case T_default_construct: - case T_empty_aggregate_init: - case T_default_new: - case T_sizeof_type: - case T_alignof: - return _u._typecast._to < ot->_u._typecast._to; - - case T_sizeof_expr: - return _u._typecast._op1 < ot->_u._typecast._op1; - - case T_trinary_operation: - if (*_u._op._op3 != *ot->_u._op._op3) { - return *_u._op._op3 < *ot->_u._op._op3; - } - // Fall through - - case T_binary_operation: - if (*_u._op._op2 != *ot->_u._op._op2) { - return *_u._op._op2 < *ot->_u._op._op2; - } - // Fall through - - case T_unary_operation: - return *_u._op._op1 < *ot->_u._op._op1; - - case T_literal: - if (_u._literal._operator != ot->_u._literal._operator) { - return _u._literal._operator < ot->_u._literal._operator; - } - return *_u._literal._value < *ot->_u._literal._value; - - case T_raw_literal: - if (_u._literal._operator != ot->_u._literal._operator) { - return _u._literal._operator < ot->_u._literal._operator; - } - return _str < ot->_str; - - case T_typeid_type: - return _u._typeid._type < ot->_u._typeid._type; - - case T_typeid_expr: - return *_u._typeid._expr < *ot->_u._typeid._expr; - - case T_type_trait: - if (_u._type_trait._trait != ot->_u._type_trait._trait) { - return _u._type_trait._trait < ot->_u._type_trait._trait; - } - return *_u._type_trait._type < *ot->_u._type_trait._type; - - case T_lambda: - return _u._closure_type < ot->_u._closure_type; - - default: - cerr << "(** invalid operand type " << (int)_type << " **)"; - } - - return false; -} diff --git a/dtool/src/cppparser/cppExpression.h b/dtool/src/cppparser/cppExpression.h deleted file mode 100644 index cd6030f73d4..00000000000 --- a/dtool/src/cppparser/cppExpression.h +++ /dev/null @@ -1,203 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppExpression.h - * @author drose - * @date 1999-10-25 - */ - -#ifndef CPPEXPRESSION_H -#define CPPEXPRESSION_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" - -class CPPIdentifier; -class CPPType; -class CPPPreprocessor; -class CPPFunctionGroup; - -/** - * - */ -class CPPExpression : public CPPDeclaration { -public: - enum Type { - T_nullptr, - T_boolean, - T_integer, - T_real, - T_string, - T_wstring, - T_u8string, - T_u16string, - T_u32string, - T_variable, - T_function, - T_unknown_ident, - T_typecast, - T_static_cast, - T_dynamic_cast, - T_const_cast, - T_reinterpret_cast, - T_construct, - T_default_construct, - T_aggregate_init, - T_empty_aggregate_init, - T_new, - T_default_new, - T_sizeof_type, - T_sizeof_expr, - T_sizeof_ellipsis, - T_alignof, - T_unary_operation, - T_binary_operation, - T_trinary_operation, - T_literal, - T_raw_literal, - T_typeid_type, - T_typeid_expr, - T_type_trait, - T_lambda, - - // These are used when parsing =default and =delete methods. - T_default, - T_delete, - }; - - CPPExpression(bool value); - CPPExpression(unsigned long long value); - CPPExpression(int value); - CPPExpression(const std::string &value); - CPPExpression(long double value); - CPPExpression(CPPIdentifier *ident, CPPScope *current_scope, - CPPScope *global_scope, CPPPreprocessor *error_sink = nullptr); - CPPExpression(int unary_operator, CPPExpression *op1); - CPPExpression(int binary_operator, CPPExpression *op1, CPPExpression *op2); - CPPExpression(int trinary_operator, CPPExpression *op1, CPPExpression *op2, CPPExpression *op3); - - static CPPExpression typecast_op(CPPType *type, CPPExpression *op1, Type cast_type = T_typecast); - static CPPExpression construct_op(CPPType *type, CPPExpression *op1); - static CPPExpression aggregate_init_op(CPPType *type, CPPExpression *op1); - static CPPExpression new_op(CPPType *type, CPPExpression *op1 = nullptr); - static CPPExpression typeid_op(CPPType *type, CPPType *std_type_info); - static CPPExpression typeid_op(CPPExpression *op1, CPPType *std_type_info); - static CPPExpression type_trait(int trait, CPPType *type, CPPType *arg = nullptr); - static CPPExpression sizeof_func(CPPType *type); - static CPPExpression sizeof_func(CPPExpression *op1); - static CPPExpression sizeof_ellipsis_func(CPPIdentifier *ident); - static CPPExpression alignof_func(CPPType *type); - static CPPExpression lambda(CPPClosureType *type); - - static CPPExpression literal(unsigned long long value, CPPInstance *lit_op); - static CPPExpression literal(long double value, CPPInstance *lit_op); - static CPPExpression literal(CPPExpression *value, CPPInstance *lit_op); - static CPPExpression raw_literal(const std::string &raw, CPPInstance *lit_op); - - static const CPPExpression &get_nullptr(); - static const CPPExpression &get_default(); - static const CPPExpression &get_delete(); - - enum ResultType { - RT_integer, - RT_real, - RT_pointer, - RT_error - }; - - class Result { - public: - Result(); - Result(int value); - Result(double value); - Result(void *value); - - int as_integer() const; - double as_real() const; - void *as_pointer() const; - bool as_boolean() const; - void output(std::ostream &out) const; - - ResultType _type; - union { - int _integer; - double _real; - void *_pointer; - } _u; - }; - - - Result evaluate() const; - CPPType *determine_type() const; - bool is_lvalue() const; - bool is_tbd() const; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPExpression *as_expression(); - - Type _type; - std::string _str; - union { - bool _boolean; - unsigned long long _integer; - long double _real; - CPPInstance *_variable; - CPPFunctionGroup *_fgroup; - CPPIdentifier *_ident; - CPPClosureType *_closure_type; - struct { - union { - CPPType *_type; - CPPExpression *_expr; - }; - CPPType *_std_type_info; - } _typeid; - struct { - CPPType *_to; - CPPExpression *_op1; - } _typecast; - struct { - // One of the yytoken values: a character, or something like EQCOMPARE. - int _operator; - CPPExpression *_op1; - CPPExpression *_op2; - CPPExpression *_op3; - } _op; - struct { - CPPInstance *_operator; - CPPExpression *_value; - } _literal; - struct { - int _trait; - CPPType *_type; - CPPType *_arg; - } _type_trait; - } _u; - -protected: - static CPPType *elevate_type(CPPType *t1, CPPType *t2); - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPExpression::Result &result) { - result.output(out); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppExpressionParser.cxx b/dtool/src/cppparser/cppExpressionParser.cxx deleted file mode 100644 index ef5785eb5ac..00000000000 --- a/dtool/src/cppparser/cppExpressionParser.cxx +++ /dev/null @@ -1,77 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppExpressionParser.cxx - * @author drose - * @date 1999-10-25 - */ - -#include "cppExpressionParser.h" -#include "cppExpression.h" - -/** - * - */ -CPPExpressionParser:: -CPPExpressionParser(CPPScope *current_scope, CPPScope *global_scope) : - _current_scope(current_scope), - _global_scope(global_scope) -{ - _expr = nullptr; -} - -/** - * - */ -CPPExpressionParser:: -~CPPExpressionParser() { -} - -/** - * - */ -bool CPPExpressionParser:: -parse_expr(const std::string &expr) { - if (!init_const_expr(expr)) { - std::cerr << "Unable to parse expression\n"; - return false; - } - - _expr = parse_const_expr(this, _current_scope, _global_scope); - - return get_error_count() == 0; -} - -/** - * - */ -bool CPPExpressionParser:: -parse_expr(const std::string &expr, const CPPPreprocessor &filepos) { - if (!init_const_expr(expr)) { - std::cerr << "Unable to parse expression\n"; - return false; - } - - copy_filepos(filepos); - - _expr = parse_const_expr(this, _current_scope, _global_scope); - - return get_error_count() == 0; -} - -/** - * - */ -void CPPExpressionParser:: -output(std::ostream &out) const { - if (_expr == nullptr) { - out << "(null expr)"; - } else { - out << *_expr; - } -} diff --git a/dtool/src/cppparser/cppExpressionParser.h b/dtool/src/cppparser/cppExpressionParser.h deleted file mode 100644 index 9a2cdf67a41..00000000000 --- a/dtool/src/cppparser/cppExpressionParser.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppExpressionParser.h - * @author drose - * @date 1999-10-25 - */ - -#ifndef CPPEXPRESSIONPARSER_H -#define CPPEXPRESSIONPARSER_H - -#include "dtoolbase.h" - -#include "cppPreprocessor.h" - -class CPPExpression; -class CPPScope; - -/** - * - */ -class CPPExpressionParser : public CPPPreprocessor { -public: - CPPExpressionParser(CPPScope *current_scope, CPPScope *global_scope); - ~CPPExpressionParser(); - - bool parse_expr(const std::string &expr); - bool parse_expr(const std::string &expr, const CPPPreprocessor &filepos); - - void output(std::ostream &out) const; - - CPPScope *_current_scope; - CPPScope *_global_scope; - CPPExpression *_expr; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPExpressionParser &ep) { - ep.output(out); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppExtensionType.cxx b/dtool/src/cppparser/cppExtensionType.cxx deleted file mode 100644 index f82735274dc..00000000000 --- a/dtool/src/cppparser/cppExtensionType.cxx +++ /dev/null @@ -1,281 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppExtensionType.cxx - * @author drose - * @date 1999-10-21 - */ - -#include "cppExtensionType.h" -#include "cppTypedefType.h" -#include "cppIdentifier.h" -#include "cppParser.h" -#include "indent.h" - -/** - * - */ -CPPExtensionType:: -CPPExtensionType(CPPExtensionType::Type type, - CPPIdentifier *ident, CPPScope *current_scope, - const CPPFile &file, CPPAttributeList attr) : - CPPType(file), - _type(type), _ident(ident), - _alignment(nullptr) -{ - if (_ident != nullptr) { - _ident->_native_scope = current_scope; - } - _attributes = std::move(attr); -} - -/** - * - */ -std::string CPPExtensionType:: -get_simple_name() const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_simple_name(); -} - -/** - * - */ -std::string CPPExtensionType:: -get_local_name(CPPScope *scope) const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_local_name(scope); -} - -/** - * - */ -std::string CPPExtensionType:: -get_fully_scoped_name() const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_fully_scoped_name(); -} - -/** - * Returns true if the type has not yet been fully specified, false if it has. - */ -bool CPPExtensionType:: -is_incomplete() const { - return true; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPExtensionType:: -is_tbd() const { - if (_ident != nullptr) { - return _ident->is_tbd(); - } - return false; -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPExtensionType:: -is_standard_layout() const { - return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPExtensionType:: -is_trivial() const { - return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPExtensionType:: -is_trivially_copyable() const { - return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); -} - -/** - * Returns true if the type can be constructed using the given argument. - */ -bool CPPExtensionType:: -is_constructible(const CPPType *given_type) const { - if (_type == T_enum || _type == T_enum_class || _type == T_enum_struct) { - const CPPExtensionType *other = ((CPPType *)given_type)->remove_reference()->remove_const()->as_extension_type(); - return other != nullptr && is_equal(other); - } - return false; -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPExtensionType:: -is_default_constructible() const { - return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPExtensionType:: -is_copy_constructible() const { - return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); -} - -/** - * Returns true if the type is copy-assignable. - */ -bool CPPExtensionType:: -is_copy_assignable() const { - return (_type == T_enum || _type == T_enum_class || _type == T_enum_struct); -} - -/** - * - */ -CPPDeclaration *CPPExtensionType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - return (*si).second; - } - - CPPExtensionType *rep = new CPPExtensionType(*this); - if (_ident != nullptr) { - rep->_ident = - _ident->substitute_decl(subst, current_scope, global_scope); - } - - if (rep->_ident == _ident) { - delete rep; - rep = this; - } - rep = CPPType::new_type(rep)->as_extension_type(); - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPExtensionType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - if (_ident == nullptr) { - // We can't resolve anonymous types. But that's OK, since they can't be - // forward declared anyway. - return this; - } - - // Maybe it has been defined by now. - CPPType *type = _ident->find_type(current_scope, global_scope); - if (type != nullptr) { - return type; - } - return this; -} - -/** - * This is a little more forgiving than is_equal(): it returns true if the - * types appear to be referring to the same thing, even if they may have - * different pointers or somewhat different definitions. It's useful for - * parameter matching, etc. - */ -bool CPPExtensionType:: -is_equivalent(const CPPType &other) const { - const CPPExtensionType *ot = ((CPPType *)&other)->as_extension_type(); - if (ot == nullptr) { - return CPPType::is_equivalent(other); - } - - // We consider two different extension types to be equivalent if they have - // the same name. - - return _ident != nullptr && ot->_ident != nullptr && *_ident == *ot->_ident; -} - -/** - * - */ -void CPPExtensionType:: -output(std::ostream &out, int, CPPScope *scope, bool complete) const { - if (_ident != nullptr) { - // If we have a name, use it. - if (complete || cppparser_output_class_keyword) { - out << _type << " "; - } - if (complete && !_attributes.is_empty()) { - out << _attributes << " "; - } - out << _ident->get_local_name(scope); - - } else if (!_typedefs.empty()) { - // If we have a typedef name, use it. - out << _typedefs.front()->get_local_name(scope); - - } else { - out << "(**unknown forward-reference type**)"; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPExtensionType:: -get_subtype() const { - return ST_extension; -} - -/** - * - */ -CPPExtensionType *CPPExtensionType:: -as_extension_type() { - return this; -} - -std::ostream & -operator << (std::ostream &out, CPPExtensionType::Type type) { - switch (type) { - case CPPExtensionType::T_enum: - return out << "enum"; - - case CPPExtensionType::T_class: - return out << "class"; - - case CPPExtensionType::T_struct: - return out << "struct"; - - case CPPExtensionType::T_union: - return out << "union"; - - case CPPExtensionType::T_enum_class: - return out << "enum class"; - - case CPPExtensionType::T_enum_struct: - return out << "enum struct"; - - default: - return out << "***invalid extension type***"; - } -} diff --git a/dtool/src/cppparser/cppExtensionType.h b/dtool/src/cppparser/cppExtensionType.h deleted file mode 100644 index acdef469b9e..00000000000 --- a/dtool/src/cppparser/cppExtensionType.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppExtensionType.h - * @author drose - * @date 1999-10-21 - */ - -#ifndef CPPEXTENSIONTYPE_H -#define CPPEXTENSIONTYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" -#include "cppInstance.h" - -class CPPScope; -class CPPIdentifier; - -/** - * Base class of enum, class, struct, and union types. An instance of the - * base class (instead of one of the specializations) is used for forward - * references. - */ -class CPPExtensionType : public CPPType { -public: - enum Type { - T_enum, - T_class, - T_struct, - T_union, - T_enum_class, - T_enum_struct, - }; - - CPPExtensionType(Type type, CPPIdentifier *ident, CPPScope *current_scope, - const CPPFile &file, CPPAttributeList attr = CPPAttributeList()); - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - - virtual bool is_incomplete() const; - virtual bool is_tbd() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *type) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_copy_assignable() const; - - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_equivalent(const CPPType &other) const; - - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPExtensionType *as_extension_type(); - - Type _type; - CPPIdentifier *_ident; - CPPExpression *_alignment; -}; - -std::ostream &operator << (std::ostream &out, CPPExtensionType::Type type); - -#endif diff --git a/dtool/src/cppparser/cppFile.cxx b/dtool/src/cppparser/cppFile.cxx deleted file mode 100644 index bc3c5aeed01..00000000000 --- a/dtool/src/cppparser/cppFile.cxx +++ /dev/null @@ -1,144 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppFile.cxx - * @author drose - * @date 1999-11-11 - */ - -#include "cppFile.h" - -#include - -using std::string; - -/** - * - */ -CPPFile:: -CPPFile(const Filename &filename, const Filename &filename_as_referenced, - Source source) : - _filename(filename), _filename_as_referenced(filename_as_referenced), - _source(source), - _pragma_once(false) -{ - _filename.set_text(); - _filename_as_referenced.set_text(); -} - -/** - * Returns true if the file appears to be a C or C++ source code file based on - * its extension. That is, returns true if the filename ends in .c, .C, .cc, - * .cpp, or any of a series of likely extensions. - */ -bool CPPFile:: -is_c_or_i_file() const { - return is_c_or_i_file(_filename); -} - -/** - * Returns true if the file appears to be a C or C++ source code file based on - * its extension. That is, returns true if the filename ends in .c, .C, .cc, - * .cpp, or any of a series of likely extensions. - */ -bool CPPFile:: -is_c_or_i_file(const Filename &filename) { - string extension = filename.get_extension(); - // downcase the extension. - for (string::iterator ei = extension.begin(); - ei != extension.end(); - ++ei) { - (*ei) = tolower(*ei); - } - - return (extension == "c" || extension == "cc" || - extension == "cpp" || extension == "c++" || extension == "cxx" || - extension == "i" || extension == "t"); -} - -/** - * Returns true if the file appears to be a C or C++ source code file based on - * its extension. That is, returns true if the filename ends in .c, .C, .cc, - * .cpp, or any of a series of likely extensions. - */ -bool CPPFile:: -is_c_file() const { - return is_c_file(_filename); -} - -/** - * Returns true if the file appears to be a C or C++ source code file based on - * its extension. That is, returns true if the filename ends in .c, .C, .cc, - * .cpp, or any of a series of likely extensions. - */ -bool CPPFile:: -is_c_file(const Filename &filename) { - string extension = filename.get_extension(); - // downcase the extension. - for (string::iterator ei = extension.begin(); - ei != extension.end(); - ++ei) { - (*ei) = tolower(*ei); - } - - return (extension == "c" || extension == "cc" || - extension == "cpp" || extension == "c++" || extension == "cxx"); -} - -/** - * If the other file is "nearer" than this file (in the sense that a file in - * the local directory is nearer than a file in the system directory, etc.), - * replaces this file's information with that of the other. Otherwise, does - * nothing. - */ -void CPPFile:: -replace_nearer(const CPPFile &other) { - if ((int)_source > (int)other._source) { - (*this) = other; - } -} - -/** - * - */ -bool CPPFile:: -operator < (const CPPFile &other) const { - return _filename < other._filename; -} - -/** - * - */ -bool CPPFile:: -operator == (const CPPFile &other) const { - return _filename == other._filename; -} - -/** - * - */ -bool CPPFile:: -operator != (const CPPFile &other) const { - return _filename != other._filename; -} - -/** - * - */ -const char *CPPFile:: -c_str() const { - return _filename.c_str(); -} - -/** - * - */ -bool CPPFile:: -empty() const { - return _filename.empty(); -} diff --git a/dtool/src/cppparser/cppFile.h b/dtool/src/cppparser/cppFile.h deleted file mode 100644 index 5cc26d5e010..00000000000 --- a/dtool/src/cppparser/cppFile.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppFile.h - * @author drose - * @date 1999-11-11 - */ - -#ifndef CPPFILE_H -#define CPPFILE_H - -#include "dtoolbase.h" -#include "filename.h" - -/** - * This defines a source file (typically a C++ header file) that is parsed by - * the CPPParser. Each declaration indicates the source file where it - * appeared. - */ -class CPPFile { -public: - enum Source { - S_local, // File resides in the current directory - S_alternate, // File resides in some other directory - S_system, // File resides in a system directory - S_none, // File is internally generated - }; - - CPPFile(const Filename &filename = "", - const Filename &filename_as_referenced = "", - Source source = S_none); - - bool is_c_or_i_file() const; - static bool is_c_or_i_file(const Filename &filename); - - bool is_c_file() const; - static bool is_c_file(const Filename &filename); - - void replace_nearer(const CPPFile &other); - - bool operator < (const CPPFile &other) const; - bool operator == (const CPPFile &other) const; - bool operator != (const CPPFile &other) const; - - const char *c_str() const; - bool empty() const; - - Filename _filename; - Filename _filename_as_referenced; - mutable Source _source; - mutable bool _pragma_once; -}; - -inline std::ostream &operator << (std::ostream &out, const CPPFile &file) { - return out << file._filename; -} - -#endif diff --git a/dtool/src/cppparser/cppFunctionGroup.cxx b/dtool/src/cppparser/cppFunctionGroup.cxx deleted file mode 100644 index 7904663d082..00000000000 --- a/dtool/src/cppparser/cppFunctionGroup.cxx +++ /dev/null @@ -1,92 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppFunctionGroup.cxx - * @author drose - * @date 1999-11-11 - */ - -#include "cppFunctionGroup.h" -#include "cppFunctionType.h" -#include "cppInstance.h" -#include "indent.h" - -/** - * - */ -CPPFunctionGroup:: -CPPFunctionGroup(const std::string &name) : - CPPDeclaration(CPPFile()), - _name(name) -{ -} - -/** - * - */ -CPPFunctionGroup:: -~CPPFunctionGroup() { -} - -/** - * If all the functions that share this name have the same return type, - * returns that type. Otherwise, if some functions have different return - * types, returns NULL. - */ -CPPType *CPPFunctionGroup:: -get_return_type() const { - CPPType *return_type = nullptr; - - if (!_instances.empty()) { - Instances::const_iterator ii = _instances.begin(); - return_type = (*ii)->_type->as_function_type()->_return_type; - ++ii; - while (ii != _instances.end()) { - if ((*ii)->_type->as_function_type()->_return_type != return_type) { - return nullptr; - } - ++ii; - } - } - - return return_type; -} - -/** - * - */ -void CPPFunctionGroup:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - if (!_instances.empty()) { - Instances::const_iterator ii = _instances.begin(); - (*ii)->output(out, indent_level, scope, complete); - ++ii; - while (ii != _instances.end()) { - out << ";\n"; - indent(out, indent_level); - (*ii)->output(out, indent_level, scope, complete); - ++ii; - } - } -} - -/** - * - */ -CPPDeclaration::SubType CPPFunctionGroup:: -get_subtype() const { - return ST_function_group; -} - -/** - * - */ -CPPFunctionGroup *CPPFunctionGroup:: -as_function_group() { - return this; -} diff --git a/dtool/src/cppparser/cppFunctionGroup.h b/dtool/src/cppparser/cppFunctionGroup.h deleted file mode 100644 index 3fced8f4ab6..00000000000 --- a/dtool/src/cppparser/cppFunctionGroup.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppFunctionGroup.h - * @author drose - * @date 1999-11-11 - */ - -#ifndef CPPFUNCTIONGROUP_H -#define CPPFUNCTIONGROUP_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" - -class CPPInstance; - -/** - * This class is simply a container for one or more CPPInstances for functions - * of the same name. It's handy for storing in the CPPScope, so that - * CPPScope::find_symbol() can return a single pointer to indicate all of the - * functions that may share a given name. - */ -class CPPFunctionGroup : public CPPDeclaration { -public: - CPPFunctionGroup(const std::string &name); - ~CPPFunctionGroup(); - - CPPType *get_return_type() const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPFunctionGroup *as_function_group(); - - typedef std::vector Instances; - Instances _instances; - std::string _name; -}; - -#endif diff --git a/dtool/src/cppparser/cppFunctionType.cxx b/dtool/src/cppparser/cppFunctionType.cxx deleted file mode 100644 index 9eb7c8fdebf..00000000000 --- a/dtool/src/cppparser/cppFunctionType.cxx +++ /dev/null @@ -1,463 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppFunctionType.cxx - * @author drose - * @date 1999-10-21 - */ - -#include "cppFunctionType.h" -#include "cppParameterList.h" -#include "cppSimpleType.h" -#include "cppInstance.h" - -using std::ostream; -using std::ostringstream; -using std::string; - -/** - * - */ -CPPFunctionType:: -CPPFunctionType(CPPType *return_type, CPPParameterList *parameters, - int flags) : - CPPType(CPPFile()), - _return_type(return_type), - _parameters(parameters), - _flags(flags) -{ - _class_owner = nullptr; - - // If the parameter list contains just the token "void", it means no - // parameters. - if (_parameters != nullptr && - _parameters->_parameters.size() == 1 && - _parameters->_parameters.front()->_type->as_simple_type() != nullptr && - _parameters->_parameters.front()->_type->as_simple_type()->_type == - CPPSimpleType::T_void && - _parameters->_parameters.front()->_ident == nullptr) { - _parameters->_parameters.clear(); - } -} - -/** - * - */ -CPPFunctionType:: -CPPFunctionType(const CPPFunctionType ©) : - CPPType(copy), - _return_type(copy._return_type), - _parameters(copy._parameters), - _flags(copy._flags), - _class_owner(copy._class_owner) -{ -} - -/** - * - */ -void CPPFunctionType:: -operator = (const CPPFunctionType ©) { - CPPType::operator = (copy); - _return_type = copy._return_type; - _parameters = copy._parameters; - _flags = copy._flags; - _class_owner = copy._class_owner; -} - -/** - * Returns true if the function accepts the given number of parameters. - */ -bool CPPFunctionType:: -accepts_num_parameters(int num_parameters) { - assert(num_parameters >= 0); - if (_parameters == nullptr) { - return (num_parameters == 0); - } - - size_t actual_num_parameters = _parameters->_parameters.size(); - // If we passed too many parameters, it must have an ellipsis. - if ((size_t)num_parameters > actual_num_parameters) { - return _parameters->_includes_ellipsis; - } - - // Make sure all superfluous parameters have a default value. - for (size_t i = (size_t)num_parameters; i < actual_num_parameters; ++i) { - CPPInstance *param = _parameters->_parameters[i]; - if (param->_initializer == nullptr) { - return false; - } - } - - return true; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPFunctionType:: -is_fully_specified() const { - return CPPType::is_fully_specified() && - _return_type->is_fully_specified() && - _parameters->is_fully_specified(); -} - -/** - * - */ -CPPDeclaration *CPPFunctionType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - return (*si).second; - } - - CPPFunctionType *rep = new CPPFunctionType(*this); - if (_return_type != nullptr) { - rep->_return_type = - _return_type->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - } - - if (_parameters != nullptr) { - rep->_parameters = - _parameters->substitute_decl(subst, current_scope, global_scope); - } - - if (rep->_return_type == _return_type && - rep->_parameters == _parameters) { - delete rep; - rep = this; - } - rep = CPPType::new_type(rep)->as_function_type(); - - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPFunctionType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPType *rtype = _return_type->resolve_type(current_scope, global_scope); - CPPParameterList *params; - if (_parameters == nullptr) { - params = nullptr; - } else { - params = _parameters->resolve_type(current_scope, global_scope); - } - - if (rtype != _return_type || params != _parameters) { - CPPFunctionType *rep = new CPPFunctionType(*this); - rep->_return_type = rtype; - rep->_parameters = params; - return CPPType::new_type(rep); - } - return this; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPFunctionType:: -is_tbd() const { - if (_return_type->is_tbd()) { - return true; - } - return _parameters == nullptr || _parameters->is_tbd(); -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPFunctionType:: -is_trivial() const { - return false; -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPFunctionType:: -is_trivially_copyable() const { - return false; -} - -/** - * - */ -void CPPFunctionType:: -output(ostream &out, int indent_level, CPPScope *scope, bool complete) const { - output(out, indent_level, scope, complete, -1); -} - -/** - * The additional parameter allows us to specify the number of parameters we - * wish to show the default values for. If num_default_parameters is >= 0, it - * indicates the number of default parameter values to show on output. - * Otherwise, all parameter values are shown. - */ -void CPPFunctionType:: -output(ostream &out, int indent_level, CPPScope *scope, bool complete, - int num_default_parameters) const { - - if (_flags & F_trailing_return_type) { - // It was declared using trailing return type, so let's format it that - // way. - out << "auto("; - _parameters->output(out, scope, true, num_default_parameters); - out << ")"; - if (_flags & F_const_method) { - out << " const"; - } - if (_flags & F_noexcept) { - out << " noexcept"; - } - if (_flags & F_final) { - out << " final"; - } - if (_flags & F_override) { - out << " override"; - } - if (!_attributes.is_empty()) { - out << " " << _attributes; - } - out << " -> "; - _return_type->output(out, indent_level, scope, false); - } - else { - _return_type->output(out, indent_level, scope, complete); - out << "("; - _parameters->output(out, scope, true, num_default_parameters); - out << ")"; - if (_flags & F_const_method) { - out << " const"; - } - if (_flags & F_noexcept) { - out << " noexcept"; - } - if (_flags & F_final) { - out << " final"; - } - if (_flags & F_override) { - out << " override"; - } - if (!_attributes.is_empty()) { - out << " " << _attributes; - } - } -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPFunctionType:: -output_instance(ostream &out, int indent_level, CPPScope *scope, - bool complete, const string &prename, - const string &name) const { - output_instance(out, indent_level, scope, complete, prename, name, -1); -} - -/** - * The additional parameter allows us to specify the number of parameters we - * wish to show the default values for. If num_default_parameters is >= 0, it - * indicates the number of default parameter values to show on output. - * Otherwise, all parameter values are shown. - */ -void CPPFunctionType:: -output_instance(ostream &out, int indent_level, CPPScope *scope, - bool complete, const string &prename, - const string &name, int num_default_parameters) const { - ostringstream parm_string; - parm_string << "("; - _parameters->output(parm_string, scope, true, num_default_parameters); - parm_string << ")"; - string str = parm_string.str(); - - if (_flags & (F_constructor | F_destructor)) { - // No return type for constructors and destructors. - out << prename << name << str; - } - else if (_flags & F_trailing_return_type) { - // It was declared using trailing return type, so let's format it that - // way. - out << "auto "; - - if (prename.empty()) { - out << name; - } else { - out << "(" << prename << name << ")"; - } - - out << str; - } - else if (_flags & F_operator_typecast) { - out << "operator "; - _return_type->output_instance(out, indent_level, scope, complete, - "", prename + str); - } - else { - if (prename.empty()) { - _return_type->output_instance(out, indent_level, scope, complete, - "", prename + name + str); - } else { - _return_type->output_instance(out, indent_level, scope, complete, - "", "(" + prename + name + ")" + str); - } - } - - if (_flags & F_const_method) { - out << " const"; - } - if (_flags & F_volatile_method) { - out << " volatile"; - } - if (_flags & F_noexcept) { - out << " noexcept"; - } - if (_flags & F_final) { - out << " final"; - } - if (_flags & F_override) { - out << " override"; - } - - if (!_attributes.is_empty()) { - out << " " << _attributes; - } - - if (_flags & F_trailing_return_type) { - out << " -> "; - _return_type->output(out, indent_level, scope, false); - } -} - -/** - * Returns the number of parameters in the list that may take default values. - */ -int CPPFunctionType:: -get_num_default_parameters() const { - // The trick is just to count, beginning from the end and working towards - // the front, the number of parameters that have some initializer. - - if (_parameters == nullptr) { - return 0; - } - - const CPPParameterList::Parameters ¶ms = _parameters->_parameters; - CPPParameterList::Parameters::const_reverse_iterator pi; - int count = 0; - for (pi = params.rbegin(); - pi != params.rend() && (*pi)->_initializer != nullptr; - ++pi) { - count++; - } - - return count; -} - -/** - * - */ -CPPDeclaration::SubType CPPFunctionType:: -get_subtype() const { - return ST_function; -} - -/** - * - */ -CPPFunctionType *CPPFunctionType:: -as_function_type() { - return this; -} - -/** - * This is similar to is_equal(), except it is more forgiving: it considers - * the functions to be equivalent only if the return type and the types of all - * parameters match. - * - * Note that this isn't symmetric to account for covariant return types. - */ -bool CPPFunctionType:: -match_virtual_override(const CPPFunctionType &other) const { - if (!_return_type->is_equivalent(*other._return_type) && - !_return_type->is_convertible_to(other._return_type)) { - return false; - } - - if (((_flags ^ other._flags) & ~(F_override | F_final)) != 0) { - return false; - } - - if (!_parameters->is_equivalent(*other._parameters)) { - return false; - } - - return true; -} - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPFunctionType:: -is_equal(const CPPDeclaration *other) const { - const CPPFunctionType *ot = ((CPPDeclaration *)other)->as_function_type(); - assert(ot != nullptr); - - if (_return_type != ot->_return_type) { - return false; - } - if (_flags != ot->_flags) { - return false; - } - if (_parameters == ot->_parameters) { - return true; - } - if (_parameters == nullptr || ot->_parameters == nullptr || - *_parameters != *ot->_parameters) { - return false; - } - return true; -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPFunctionType:: -is_less(const CPPDeclaration *other) const { - const CPPFunctionType *ot = ((CPPDeclaration *)other)->as_function_type(); - assert(ot != nullptr); - - if (_return_type != ot->_return_type) { - return _return_type < ot->_return_type; - } - if (_flags != ot->_flags) { - return _flags < ot->_flags; - } - if (_parameters == ot->_parameters) { - return 0; - } - if (_parameters == nullptr || ot->_parameters == nullptr) { - return _parameters < ot->_parameters; - } - return *_parameters < *ot->_parameters; -} diff --git a/dtool/src/cppparser/cppFunctionType.h b/dtool/src/cppparser/cppFunctionType.h deleted file mode 100644 index 3370a079a48..00000000000 --- a/dtool/src/cppparser/cppFunctionType.h +++ /dev/null @@ -1,101 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppFunctionType.h - * @author drose - * @date 1999-10-21 - */ - -#ifndef CPPFUNCTIONTYPE_H -#define CPPFUNCTIONTYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" - -class CPPParameterList; -class CPPIdentifier; - -/** - * - */ -class CPPFunctionType : public CPPType { -public: - enum Flags { - F_const_method = 0x001, - F_operator_typecast = 0x002, - F_constructor = 0x004, - F_destructor = 0x008, - F_method_pointer = 0x010, - F_unary_op = 0x020, - F_operator = 0x040, - F_noexcept = 0x080, - F_copy_constructor = 0x200, - F_move_constructor = 0x400, - F_trailing_return_type = 0x800, - F_final = 0x1000, - F_override = 0x2000, - F_volatile_method = 0x4000, - F_lvalue_method = 0x8000, - F_rvalue_method = 0x10000, - F_copy_assignment_operator = 0x20000, - F_move_assignment_operator = 0x40000, - }; - - CPPFunctionType(CPPType *return_type, CPPParameterList *parameters, - int flags); - CPPFunctionType(const CPPFunctionType ©); - void operator = (const CPPFunctionType ©); - - bool accepts_num_parameters(int num_parameters); - - CPPType *_return_type; - CPPParameterList *_parameters; - int _flags; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_tbd() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, int num_default_parameters) const; - virtual void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const; - void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name, - int num_default_parameters) const; - int get_num_default_parameters() const; - - virtual SubType get_subtype() const; - - virtual CPPFunctionType *as_function_type(); - - bool match_virtual_override(const CPPFunctionType &other) const; - - CPPIdentifier *_class_owner; - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppGlobals.cxx b/dtool/src/cppparser/cppGlobals.cxx deleted file mode 100644 index f537ce8c42c..00000000000 --- a/dtool/src/cppparser/cppGlobals.cxx +++ /dev/null @@ -1,16 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppGlobals.cxx - * @author drose - * @date 2000-05-16 - */ - -#include "cppGlobals.h" - -std::string cpp_longlong_keyword; diff --git a/dtool/src/cppparser/cppGlobals.h b/dtool/src/cppparser/cppGlobals.h deleted file mode 100644 index 39755f18d72..00000000000 --- a/dtool/src/cppparser/cppGlobals.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppGlobals.h - * @author drose - * @date 2000-05-16 - */ - -#ifndef CPPGLOBALS_H -#define CPPGLOBALS_H - -#include "dtoolbase.h" - -// Some compilers (notably VC++) define a special keyword to represent a -// 64-bit integer, but don't recognize "long long int". To parse (and -// generate) code for these compilers, set this string to the 64-bit integer -// typename keyword. -extern std::string cpp_longlong_keyword; - - -#endif diff --git a/dtool/src/cppparser/cppIdentifier.cxx b/dtool/src/cppparser/cppIdentifier.cxx deleted file mode 100644 index 5c7a8d72abc..00000000000 --- a/dtool/src/cppparser/cppIdentifier.cxx +++ /dev/null @@ -1,612 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppIdentifier.cxx - * @author drose - * @date 1999-10-26 - */ - -#include "cppIdentifier.h" -#include "cppScope.h" -#include "cppTemplateScope.h" -#include "cppPreprocessor.h" -#include "cppTemplateParameterList.h" -#include "cppTBDType.h" -#include "cppStructType.h" - -using std::string; - - -/** - * - */ -CPPIdentifier:: -CPPIdentifier(const string &name, const CPPFile &file) { - _names.push_back(CPPNameComponent(name)); - _native_scope = nullptr; - _loc.first_line = 0; - _loc.first_column = 0; - _loc.last_line = 0; - _loc.last_column = 0; - _loc.file = file; -} - -/** - * - */ -CPPIdentifier:: -CPPIdentifier(const CPPNameComponent &name, const CPPFile &file) { - _names.push_back(name); - _native_scope = nullptr; - _loc.first_line = 0; - _loc.first_column = 0; - _loc.last_line = 0; - _loc.last_column = 0; - _loc.file = file; -} - -/** - * - */ -CPPIdentifier:: -CPPIdentifier(const string &name, const cppyyltype &loc) : _loc(loc) { - _names.push_back(CPPNameComponent(name)); - _native_scope = nullptr; -} - -/** - * - */ -CPPIdentifier:: -CPPIdentifier(const CPPNameComponent &name, const cppyyltype &loc) : _loc(loc) { - _names.push_back(name); - _native_scope = nullptr; -} - -/** - * - */ -void CPPIdentifier:: -add_name(const string &name) { - _names.push_back(CPPNameComponent(name)); -} - -/** - * - */ -void CPPIdentifier:: -add_name(const CPPNameComponent &name) { - _names.push_back(name); -} - -/** - * - */ -void CPPIdentifier:: -prepend(CPPIdentifier *ident) { - _names.insert(_names.begin(), ident->_names.begin(), ident->_names.end()); -} - -/** - * - */ -bool CPPIdentifier:: -operator == (const CPPIdentifier &other) const { - if (_names.size() != other._names.size()) { - return false; - } - for (int i = 0; i < (int)_names.size(); ++i) { - if (_names[i] != other._names[i]) { - return false; - } - } - - return true; -} - -/** - * - */ -bool CPPIdentifier:: -operator != (const CPPIdentifier &other) const { - return !(*this == other); -} - -/** - * - */ -bool CPPIdentifier:: -operator < (const CPPIdentifier &other) const { - if (_names.size() != other._names.size()) { - return _names.size() < other._names.size(); - } - for (int i = 0; i < (int)_names.size(); ++i) { - if (_names[i] != other._names[i]) { - return _names[i] < other._names[i]; - } - } - - return false; -} - -/** - * - */ -bool CPPIdentifier:: -is_scoped() const { - return _names.size() > 1; -} - - -/** - * - */ -string CPPIdentifier:: -get_simple_name() const { - return _names.back().get_name(); -} - -/** - * - */ -string CPPIdentifier:: -get_local_name(CPPScope *scope) const { - assert(!_names.empty()); - - string result; - - if (scope == nullptr || (_native_scope == nullptr && _names.size() == 1)) { - result = _names.back().get_name_with_templ(scope); - - } else if (_names.front().empty()) { - result = get_fully_scoped_name(); - - } else { - // Determine the scope of everything up until but not including the last - // name. - CPPScope *my_scope = get_scope(scope, nullptr); - - // Strip off template scopes, since they don't add anything particularly - // meaningful to the local name. - while (my_scope != nullptr && my_scope->as_template_scope() != nullptr) { - my_scope = my_scope->get_parent_scope(); - } - - if (my_scope == nullptr) { - result = get_fully_scoped_name(); - } else if (my_scope == scope) { - return _names.back().get_name_with_templ(scope); - } else { - result = my_scope->get_local_name(scope); - if (!result.empty()) { - result += "::"; - } - result += _names.back().get_name_with_templ(scope); - } - } - return result; -} - -/** - * - */ -string CPPIdentifier:: -get_fully_scoped_name() const { - assert(!_names.empty()); - Names::const_iterator ni = _names.begin(); - string name = (*ni).get_name_with_templ(); - ++ni; - while (ni != _names.end()) { - name += "::" + (*ni).get_name_with_templ(); - ++ni; - } - return name; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPIdentifier:: -is_fully_specified() const { - Names::const_iterator ni; - for (ni = _names.begin(); ni != _names.end(); ++ni) { - if ((*ni).has_templ() && !(*ni).get_templ()->is_fully_specified()) { - return false; - } - } - - return true; -} - -/** - * Returns true if the identifier includes a template parameter list that - * includes some not-yet-defined type. - */ -bool CPPIdentifier:: -is_tbd() const { - Names::const_iterator ni; - for (ni = _names.begin(); ni != _names.end(); ++ni) { - if ((*ni).is_tbd()) { - return true; - } - } - - return false; -} - -/** - * - */ -CPPScope *CPPIdentifier:: -get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - assert(!_names.empty()); - - CPPScope *scope = _native_scope; - if (scope == nullptr) { - scope = current_scope; - } - int i = 0; - - if (_names[i].empty()) { - // This identifier starts with a ::, thus it begins at the global scope. - scope = global_scope; - i++; - } - - while (i + 1 < (int)_names.size() && scope != nullptr) { - // Check for an explicitly specialized scope first. - CPPScope *next_scope = scope->find_scope(_names[i].get_name_with_templ(), global_scope); - if (next_scope == nullptr) { - next_scope = scope->find_scope(_names[i].get_name(), global_scope); - if (next_scope == nullptr) { - if (error_sink != nullptr) { - error_sink->error("Symbol " + _names[i].get_name() + - " is not a known scope in " + - scope->get_fully_scoped_name(), - _loc); - } - return nullptr; - } - if (_names[i].has_templ()) { - next_scope = next_scope->instantiate(_names[i].get_templ(), - current_scope, global_scope); - } - } - scope = next_scope; - i++; - } - - return scope; -} - -/** - * - */ -CPPScope *CPPIdentifier:: -get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPDeclaration::SubstDecl &subst, - CPPPreprocessor *error_sink) const { - assert(!_names.empty()); - - CPPScope *scope = _native_scope; - if (scope == nullptr) { - scope = current_scope; - } - int i = 0; - - if (_names[i].empty()) { - // This identifier starts with a ::, thus it begins at the global scope. - scope = global_scope; - i++; - } - - while (i + 1 < (int)_names.size() && scope != nullptr) { - CPPScope *next_scope = scope->find_scope(_names[i].get_name(), subst, - global_scope); - if (next_scope == nullptr) { - if (error_sink != nullptr) { - error_sink->error("Symbol " + _names[i].get_name() + - " is not a known scope in " + - scope->get_fully_scoped_name(), - _loc); - } - return nullptr; - } - if (_names[i].has_templ()) { - next_scope = next_scope->instantiate(_names[i].get_templ(), - current_scope, global_scope); - } - scope = next_scope; - i++; - } - - return scope; -} - -/** - * Looks up the identifier in the current and/or global scopes, and returns a - * CPPType pointer if it seems to refer to a type, or NULL if it does not. If - * force_instantiate is true, the type will be instantiated as fully as - * possible right now, even if it means instantiating it into an identical - * template type. Otherwise, the instantiation may be delayed for - * optimization reasons, and a CPPTBDType placeholder may be returned instead. - */ -CPPType *CPPIdentifier:: -find_type(CPPScope *current_scope, CPPScope *global_scope, - bool force_instantiate, - CPPPreprocessor *error_sink) const { - CPPScope *scope = get_scope(current_scope, global_scope, error_sink); - if (scope == nullptr) { - return nullptr; - } - - CPPType *type = nullptr; - if (!_names.back().has_templ()) { - type = scope->find_type(get_simple_name()); - - } else { - CPPDeclaration *decl = find_symbol(current_scope, global_scope, error_sink); - type = decl->as_type(); - /* - if (type != NULL) { - if (!type->is_incomplete() || force_instantiate) { - type = type->instantiate(_names.back().get_templ(), - current_scope, global_scope, - error_sink)->as_type(); - - // If we ended up with another template, instantiate later. - if (type->is_template() && !force_instantiate) { - type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); - } - - } else { - // Otherwise, we'll have to instantiate the type later. - type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); - } - // type->_file.replace_nearer(_file); - } - */ - } - return type; -} - -/** - * This flavor of find_type() will instantiate any scope names in the - * identifier. It's useful for fully defining a type while instantiating a - * class. - */ -CPPType *CPPIdentifier:: -find_type(CPPScope *current_scope, CPPScope *global_scope, - CPPDeclaration::SubstDecl &subst, - CPPPreprocessor *error_sink) const { - CPPScope *scope = get_scope(current_scope, global_scope, subst, error_sink); - if (scope == nullptr) { - return nullptr; - } - - CPPType *type = scope->find_type(get_simple_name(), subst, global_scope); - if (type != nullptr && _names.back().has_templ()) { - // This is a template type. - - if (is_fully_specified()) { - // If our identifier fully specifies the instantiation, then apply it. - CPPDeclaration *decl = - type->instantiate(_names.back().get_templ(), - current_scope, global_scope, - error_sink); - assert(decl != nullptr); - CPPType *new_type = decl->as_type(); - assert(new_type != nullptr); - if (new_type == type) { - type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); - } else { - type = new_type; - } - } else { - // Otherwise, we'll have to instantiate the type later. - type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); - } - // type->_file.replace_nearer(_file); - } - return type; -} - - -/** - * - */ -CPPDeclaration *CPPIdentifier:: -find_symbol(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - CPPScope *scope = get_scope(current_scope, global_scope, error_sink); - if (scope == nullptr) { - return nullptr; - } - - CPPDeclaration *sym; - if (!_names.back().has_templ()) { - if (_names.size() > 1 && scope->get_simple_name() == get_simple_name()) { -/** - - */ - sym = scope->get_struct_type()->get_constructor(); - } else { - sym = scope->find_symbol(get_simple_name()); - } - - } else { - sym = scope->find_template(get_simple_name()); - if (sym != nullptr) { - CPPType *type = sym->as_type(); - if (type != nullptr && type->is_incomplete()) { - // We can't instantiate an incomplete type. - sym = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); - } else { - // Instantiate the symbol. - sym = sym->instantiate(_names.back().get_templ(), current_scope, - global_scope, error_sink); - } - } - } - - return sym; -} - -/** - * - */ -CPPDeclaration *CPPIdentifier:: -find_symbol(CPPScope *current_scope, CPPScope *global_scope, - CPPDeclaration::SubstDecl &subst, - CPPPreprocessor *error_sink) const { - CPPScope *scope = get_scope(current_scope, global_scope, subst, error_sink); - if (scope == nullptr) { - return nullptr; - } - - CPPDeclaration *sym; - if (!_names.back().has_templ()) { - if (_names.size() > 1 && scope->get_simple_name() == get_simple_name()) { -/** - - */ - sym = scope->get_struct_type()->get_constructor(); - } else { - sym = scope->find_symbol(get_simple_name()); - } - - } else { - sym = scope->find_template(get_simple_name()); - - if (sym != nullptr) { - CPPType *type = sym->as_type(); - if (type != nullptr && type->is_incomplete()) { - // We can't instantiate an incomplete type. - sym = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); - } else { - // Instantiate the symbol. - sym = sym->instantiate(_names.back().get_templ(), current_scope, - global_scope, error_sink); - } - } - } - - return sym; -} - -/** - * - */ -CPPDeclaration *CPPIdentifier:: -find_template(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - CPPScope *scope = get_scope(current_scope, global_scope, error_sink); - if (scope == nullptr) { - return nullptr; - } - return scope->find_template(get_simple_name()); -} - -/** - * - */ -CPPScope *CPPIdentifier:: -find_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - CPPScope *scope = get_scope(current_scope, global_scope, error_sink); - if (scope == nullptr) { - return nullptr; - } - return scope->find_scope(get_simple_name(), global_scope); -} - - -/** - * - */ -CPPIdentifier *CPPIdentifier:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - CPPIdentifier *rep = new CPPIdentifier(*this); - - bool anything_changed = false; - for (int i = 0; i < (int)rep->_names.size(); ++i) { - if (_names[i].has_templ()) { - rep->_names[i].set_templ - (_names[i].get_templ()->substitute_decl(subst, current_scope, global_scope)); - if (rep->_names[i].get_templ() != _names[i].get_templ()) { - anything_changed = true; - } - } - } - - if (!anything_changed) { - delete rep; - rep = this; - } - - return rep; -} - -/** - * - */ -void CPPIdentifier:: -output(std::ostream &out, CPPScope *scope) const { - if (scope == nullptr) { - output_fully_scoped_name(out); - } else { - output_local_name(out, scope); - } -} - - -/** - * - */ -void CPPIdentifier:: -output_local_name(std::ostream &out, CPPScope *scope) const { - assert(!_names.empty()); - - if (scope == nullptr || (_native_scope == nullptr && _names.size() == 1)) { - out << _names.back(); - } else if (_names.front().empty()) { - output_fully_scoped_name(out); - } else { - // Determine the scope of everything up until but not including the last - // name. - CPPScope *my_scope = get_scope(scope, nullptr); - - if (my_scope == nullptr) { - output_fully_scoped_name(out); - } else { - out << my_scope->get_local_name(scope) << "::" << _names.back(); - } - } -} - -/** - * - */ -void CPPIdentifier:: -output_fully_scoped_name(std::ostream &out) const { - if (_native_scope != nullptr) { - _native_scope->output(out, nullptr); - out << "::"; - } - Names::const_iterator ni = _names.begin(); - out << (*ni); - ++ni; - while (ni != _names.end()) { - out << "::" << (*ni); - ++ni; - } -} diff --git a/dtool/src/cppparser/cppIdentifier.h b/dtool/src/cppparser/cppIdentifier.h deleted file mode 100644 index bd6d3df8627..00000000000 --- a/dtool/src/cppparser/cppIdentifier.h +++ /dev/null @@ -1,106 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppIdentifier.h - * @author drose - * @date 1999-10-26 - */ - -#ifndef CPPIDENTIFIER_H -#define CPPIDENTIFIER_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" -#include "cppNameComponent.h" -#include "cppFile.h" -#include "cppBisonDefs.h" - -#include -#include - -class CPPScope; -class CPPType; -class CPPPreprocessor; -class CPPTemplateParameterList; - -/** - * - */ -class CPPIdentifier { -public: - CPPIdentifier(const std::string &name, const CPPFile &file = CPPFile()); - CPPIdentifier(const CPPNameComponent &name, const CPPFile &file = CPPFile()); - CPPIdentifier(const std::string &name, const cppyyltype &loc); - CPPIdentifier(const CPPNameComponent &name, const cppyyltype &loc); - void add_name(const std::string &name); - void add_name(const CPPNameComponent &name); - - void prepend(CPPIdentifier *ident); - - bool operator == (const CPPIdentifier &other) const; - bool operator != (const CPPIdentifier &other) const; - bool operator < (const CPPIdentifier &other) const; - - bool is_scoped() const; - - std::string get_simple_name() const; - std::string get_local_name(CPPScope *scope = nullptr) const; - std::string get_fully_scoped_name() const; - - bool is_fully_specified() const; - bool is_tbd() const; - - - CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPDeclaration::SubstDecl &subst, - CPPPreprocessor *error_sink = nullptr) const; - - CPPType *find_type(CPPScope *current_scope, CPPScope *global_scope, - bool force_instantiate = false, - CPPPreprocessor *error_sink = nullptr) const; - CPPType *find_type(CPPScope *current_scope, CPPScope *global_scope, - CPPDeclaration::SubstDecl &subst, - CPPPreprocessor *error_sink = nullptr) const; - CPPDeclaration *find_symbol(CPPScope *current_scope, - CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - CPPDeclaration *find_symbol(CPPScope *current_scope, - CPPScope *global_scope, - CPPDeclaration::SubstDecl &subst, - CPPPreprocessor *error_sink = nullptr) const; - CPPDeclaration *find_template(CPPScope *current_scope, - CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - CPPScope *find_scope(CPPScope *current_scope, - CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - CPPIdentifier *substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - void output(std::ostream &out, CPPScope *scope) const; - void output_local_name(std::ostream &out, CPPScope *scope) const; - void output_fully_scoped_name(std::ostream &out) const; - - typedef std::vector Names; - Names _names; - CPPScope *_native_scope; - cppyyltype _loc; -}; - -inline std::ostream &operator << (std::ostream &out, const CPPIdentifier &identifier) { - identifier.output(out, nullptr); - return out; -} - - -#endif diff --git a/dtool/src/cppparser/cppInstance.cxx b/dtool/src/cppparser/cppInstance.cxx deleted file mode 100644 index 7de57987296..00000000000 --- a/dtool/src/cppparser/cppInstance.cxx +++ /dev/null @@ -1,637 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppInstance.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppInstance.h" -#include "cppInstanceIdentifier.h" -#include "cppIdentifier.h" -#include "cppTemplateScope.h" -#include "cppFunctionType.h" -#include "cppSimpleType.h" -#include "cppExpression.h" -#include "cppPreprocessor.h" -#include "cppParameterList.h" -#include "cppReferenceType.h" -#include "cppConstType.h" -#include "indent.h" - -#include - -using std::string; - -/** - * - */ -CPPInstance:: -CPPInstance(CPPType *type, const string &name, int storage_class) : - CPPDeclaration(CPPFile()), - _type(type), - _ident(new CPPIdentifier(name)), - _storage_class(storage_class), - _bit_width(-1) -{ - _initializer = nullptr; -} - -/** - * - */ -CPPInstance:: -CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) : - CPPDeclaration(CPPFile()), - _type(type), - _ident(ident), - _storage_class(storage_class), - _bit_width(-1) -{ - _initializer = nullptr; -} - -/** - * Constructs a new CPPInstance object that defines a variable of the - * indicated type according to the type and the InstanceIdentifier. The - * InstanceIdentifier pointer is deallocated. - */ -CPPInstance:: -CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class, - const CPPFile &file) : - CPPDeclaration(file) -{ - _type = ii->unroll_type(type); - _ident = ii->_ident; - _attributes = ii->_attributes; - ii->_ident = nullptr; - _storage_class = storage_class; - _initializer = nullptr; - - if (ii->_bit_width != nullptr) { - CPPExpression::Result result = ii->_bit_width->evaluate(); - if (result._type != CPPExpression::RT_error) { - _bit_width = ii->_bit_width->evaluate().as_integer(); - } else { - _bit_width = -1; - } - } else { - _bit_width = -1; - } - - CPPParameterList *params = ii->get_initializer(); - if (params != nullptr) { - // In this case, the instance has a parameter-list initializer, e.g.: int - // foo(0); We really should save this initializer in the instance object. - // But we don't for now, since no one really cares about initializers - // anyway. - } - - if (ii->_packed) { - _storage_class |= SC_parameter_pack; - } - - delete ii; -} - -/** - * - */ -CPPInstance:: -CPPInstance(const CPPInstance ©) : - CPPDeclaration(copy), - _type(copy._type), - _ident(copy._ident), - _initializer(copy._initializer), - _storage_class(copy._storage_class), - _bit_width(copy._bit_width) -{ - assert(_type != nullptr); -} - -/** - * - */ -CPPInstance:: -~CPPInstance() { - // Can't delete the identifier. Don't try. -} - - -/** - * Constructs and returns a new CPPInstance object that corresponds to a - * function prototype declaration for a typecast method, whose return type is - * implicit in the identifier type. - */ -CPPInstance *CPPInstance:: -make_typecast_function(CPPInstance *inst, CPPIdentifier *ident, - CPPParameterList *parameters, int function_flags) { - CPPType *type = CPPType::new_type(inst->_type); - delete inst; - - function_flags |= (int)CPPFunctionType::F_operator_typecast; - - CPPType *ft = - CPPType::new_type(new CPPFunctionType(type, parameters, function_flags)); - - return new CPPInstance(ft, ident); -} - -/** - * - */ -bool CPPInstance:: -operator == (const CPPInstance &other) const { - if (_type != other._type) { - return false; - } - if (_storage_class != other._storage_class) { - return false; - } - if (_attributes != other._attributes) { - return false; - } - - // We *do* care about the identifier. We need to differentiate types of - // function variables, among possibly other things, based on the identifier. - if ((_ident == nullptr && other._ident != nullptr) || - (_ident != nullptr && other._ident == nullptr) || - (_ident != nullptr && other._ident != nullptr && *_ident != *other._ident)) - { - return false; - } - - // We similarly care about the initializer. - if ((_initializer == nullptr && other._initializer != nullptr) || - (_initializer != nullptr && other._initializer == nullptr) || - (_initializer != nullptr && other._initializer != nullptr && - *_initializer != *other._initializer)) - { - return false; - } - - return true; -} - -/** - * - */ -bool CPPInstance:: -operator != (const CPPInstance &other) const { - return !operator == (other); -} - -/** - * - */ -bool CPPInstance:: -operator < (const CPPInstance &other) const { - if (_type != other._type) { - return _type < other._type; - } - if (_storage_class != other._storage_class) { - return _storage_class < other._storage_class; - } - if (_attributes != other._attributes) { - return _attributes < other._attributes; - } - - // We *do* care about the identifier. We need to differentiate types of - // function variables, among possibly other things, based on the identifier. - if ((_ident == nullptr && other._ident != nullptr) || - (_ident != nullptr && other._ident == nullptr) || - (_ident != nullptr && other._ident != nullptr && *_ident != *other._ident)) - { - if (_ident == nullptr || other._ident == nullptr) { - return _ident < other._ident; - } - return *_ident < *other._ident; - } - - // We similarly care about the initializer. - if ((_initializer == nullptr && other._initializer != nullptr) || - (_initializer != nullptr && other._initializer == nullptr) || - (_initializer != nullptr && other._initializer != nullptr && - *_initializer != *other._initializer)) - { - if (_initializer == nullptr || other._initializer == nullptr) { - return _initializer < other._initializer; - } - return *_initializer < *other._initializer; - } - - return false; -} - -/** - * Sets the value of the expression that is used to initialize the variable, - * or the default value for a parameter. If a non-null expression is set on a - * function declaration, it implies that the function is pure virtual. - */ -void CPPInstance:: -set_initializer(CPPExpression *initializer) { - if (_type->as_function_type() != nullptr) { - // This is a function declaration. - _storage_class &= ~(SC_pure_virtual | SC_defaulted | SC_deleted); - _initializer = nullptr; - - if (initializer != nullptr) { - if (initializer->_type == CPPExpression::T_integer) { // = 0 - _storage_class |= SC_pure_virtual; - - } else if (initializer->_type == CPPExpression::T_default) { - _storage_class |= SC_defaulted; - - } else if (initializer->_type == CPPExpression::T_delete) { - _storage_class |= SC_deleted; - } - } - } else { - _initializer = initializer; - } -} - -/** - * Sets the number of bytes to align this instance to. - */ -void CPPInstance:: -set_alignment(int align) { - _attributes.add_alignas(align); -} - -/** - * Sets the expression that is used to determine the required alignment for - * the variable. This should be a constant expression, but we don't presently - * verify that it is. - */ -void CPPInstance:: -set_alignment(CPPExpression *const_expr) { - _attributes.add_alignas(const_expr); -} - -/** - * - */ -bool CPPInstance:: -is_scoped() const { - if (_ident == nullptr) { - return false; - } else { - return _ident->is_scoped(); - } -} - -/** - * - */ -CPPScope *CPPInstance:: -get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - if (_ident == nullptr) { - return current_scope; - } else { - return _ident->get_scope(current_scope, global_scope, error_sink); - } -} - -/** - * - */ -string CPPInstance:: -get_simple_name() const { - if (_ident == nullptr) { - return ""; - } else { - return _ident->get_simple_name(); - } -} - -/** - * - */ -string CPPInstance:: -get_local_name(CPPScope *scope) const { - if (_ident == nullptr) { - return ""; - } else { - return _ident->get_local_name(scope); - } -} - -/** - * - */ -string CPPInstance:: -get_fully_scoped_name() const { - if (_ident == nullptr) { - return ""; - } else { - return _ident->get_fully_scoped_name(); - } -} - -/** - * If this is a function type instance, checks whether the function name - * matches the class name (or ~name), and if so, flags it as a constructor, - * destructor or assignment operator - */ -void CPPInstance:: -check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) { - CPPScope *scope = get_scope(current_scope, global_scope); - if (scope == nullptr) { - scope = current_scope; - } - - CPPFunctionType *func = _type->as_function_type(); - if (func != nullptr && scope != nullptr) { - string method_name = get_local_name(scope); - string class_name = scope->get_local_name(); - - if (!method_name.empty() && !class_name.empty()) { - // Check either a constructor or assignment operator. - if (method_name == class_name || method_name == "operator =") { - CPPType *void_type = CPPType::new_type - (new CPPSimpleType(CPPSimpleType::T_void)); - - int flags = func->_flags; - if (method_name == class_name) { - flags |= CPPFunctionType::F_constructor; - } - - CPPParameterList *params = func->_parameters; - if (params->_parameters.size() == 1 && !params->_includes_ellipsis) { - CPPType *param_type = params->_parameters[0]->_type; - CPPReferenceType *ref_type = param_type->as_reference_type(); - - if (ref_type != nullptr) { - param_type = ref_type->_pointing_at->remove_cv(); - - if (class_name == param_type->get_simple_name()) { - if (flags & CPPFunctionType::F_constructor) { - if (ref_type->_value_category == CPPReferenceType::VC_rvalue) { - flags |= CPPFunctionType::F_move_constructor; - } else { - flags |= CPPFunctionType::F_copy_constructor; - } - } else { - if (ref_type->_value_category == CPPReferenceType::VC_rvalue) { - flags |= CPPFunctionType::F_move_assignment_operator; - } else { - flags |= CPPFunctionType::F_copy_assignment_operator; - } - } - } - } - } - - _type = CPPType::new_type - (new CPPFunctionType(void_type, func->_parameters, flags)); - - } else if (method_name == "~" + class_name) { - CPPType *void_type = CPPType::new_type - (new CPPSimpleType(CPPSimpleType::T_void)); - - _type = CPPType::new_type - (new CPPFunctionType(void_type, func->_parameters, - func->_flags | CPPFunctionType::F_destructor)); - } - } - } -} - -/** - * - */ -CPPDeclaration *CPPInstance:: -instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - - if (!is_template()) { - if (error_sink != nullptr) { - error_sink->warning("Ignoring template parameters for instance " + - _ident->get_local_name()); - } - return (CPPInstance *)this; - } - - Instantiations::const_iterator ii; - ii = _instantiations.find(actual_params); - if (ii != _instantiations.end()) { - // We've already instantiated this instance with these parameters. Return - // that. - return (*ii).second; - } - - - CPPTemplateScope *tscope = get_template_scope(); - - CPPDeclaration::SubstDecl subst; - actual_params->build_subst_decl(tscope->_parameters, subst, - current_scope, global_scope); - - CPPInstance *inst = - ((CPPInstance *)this)->substitute_decl(subst, current_scope, global_scope) - ->as_instance(); - if (inst == this) { - // Hmm, nothing to substitute. Make a new instance anyway, so we can - // change the name. - inst = new CPPInstance(*this); - } - assert(inst != nullptr); - inst->_ident = inst->_ident->substitute_decl(subst, current_scope, global_scope); - if (inst->_ident == _ident) { - inst->_ident = new CPPIdentifier(*inst->_ident); - } - inst->_ident->_names.back().set_templ - (new CPPTemplateParameterList(*actual_params)); - - inst->_template_scope = nullptr; - - ((CPPInstance *)this)->_instantiations.insert(Instantiations::value_type(actual_params, inst)); - return inst; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPInstance:: -is_fully_specified() const { - if (_ident != nullptr && !_ident->is_fully_specified()) { - return false; - } - if (_initializer != nullptr && !_initializer->is_fully_specified()) { - return false; - } - return CPPDeclaration::is_fully_specified() && - _type->is_fully_specified(); -} - -/** - * - */ -CPPDeclaration *CPPInstance:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - CPPDeclaration *top = - CPPDeclaration::substitute_decl(subst, current_scope, global_scope); - if (top != this) { - return top; - } - - CPPInstance *rep = new CPPInstance(*this); - CPPDeclaration *new_type = - _type->substitute_decl(subst, current_scope, global_scope); - rep->_type = new_type->as_type(); - - if (rep->_type == nullptr) { - rep->_type = _type; - } - - if (_initializer != nullptr) { - rep->_initializer = - _initializer->substitute_decl(subst, current_scope, global_scope) - ->as_expression(); - } - - if (rep->_type == _type && - rep->_initializer == _initializer) { - delete rep; - rep = this; - } - - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - -/** - * - */ -void CPPInstance:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - output(out, indent_level, scope, complete, -1); -} - -/** - * The extra parameter comes into play only when we happen to be outputting a - * function prototype. See CPPFunctionType::output(). - */ -void CPPInstance:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete, - int num_default_parameters) const { - assert(_type != nullptr); - - if (_type->is_parameter_expr()) { - // In this case, the whole thing is really an expression, and not an - // instance at all. This can only happen if we parsed an instance - // declaration while we thought we were parsing a function prototype. - out << *_initializer; - return; - } - - if (is_template()) { - get_template_scope()->_parameters.write_formal(out, scope); - indent(out, indent_level); - } - - if (!_attributes.is_empty()) { - out << _attributes << " "; - } - - if (_storage_class & SC_static) { - out << "static "; - } - if (_storage_class & SC_extern) { - out << "extern "; - } - if (_storage_class & SC_c_binding) { - out << "\"C\" "; - } - if (_storage_class & SC_virtual) { - out << "virtual "; - } - if (_storage_class & SC_inline) { - out << "inline "; - } - if (_storage_class & SC_explicit) { - out << "explicit "; - } - if (_storage_class & SC_register) { - out << "register "; - } - if (_storage_class & SC_volatile) { - out << "volatile "; - } - if (_storage_class & SC_mutable) { - out << "mutable "; - } - if (_storage_class & SC_consteval) { - out << "consteval "; - } - if (_storage_class & SC_constexpr) { - out << "constexpr "; - } - if (_storage_class & SC_constinit) { - out << "constinit "; - } - if (_storage_class & SC_thread_local) { - out << "thread_local "; - } - - string name; - if (_ident != nullptr) { - name = _ident->get_local_name(scope); - } - if (_storage_class & SC_parameter_pack) { - name = "..." + name; - } - - if (_type->as_function_type()) { - _type->as_function_type()-> - output_instance(out, indent_level, scope, complete, "", name, - num_default_parameters); - } - else { - _type->output_instance(out, indent_level, scope, complete, "", name); - } - - if (_bit_width != -1) { - out << " : " << _bit_width; - } - - if (_storage_class & SC_pure_virtual) { - out << " = 0"; - } - if (_storage_class & SC_defaulted) { - out << " = default"; - } - if (_storage_class & SC_deleted) { - out << " = delete"; - } - if (_initializer != nullptr) { - out << " = " << *_initializer; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPInstance:: -get_subtype() const { - return ST_instance; -} - -/** - * - */ -CPPInstance *CPPInstance:: -as_instance() { - return this; -} diff --git a/dtool/src/cppparser/cppInstance.h b/dtool/src/cppparser/cppInstance.h deleted file mode 100644 index 8e8c427f52c..00000000000 --- a/dtool/src/cppparser/cppInstance.h +++ /dev/null @@ -1,138 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppInstance.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPINSTANCE_H -#define CPPINSTANCE_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" -#include "cppType.h" -#include "cppTemplateParameterList.h" -#include "cppAttributeList.h" - -class CPPInstanceIdentifier; -class CPPIdentifier; -class CPPParameterList; -class CPPScope; -class CPPExpression; - -/** - * - */ -class CPPInstance : public CPPDeclaration { -public: - // Some of these flags clearly only make sense in certain contexts, e.g. - // for a function or method. - enum StorageClass { - SC_static = 0x0001, - SC_extern = 0x0002, - SC_c_binding = 0x0004, - SC_virtual = 0x0008, - SC_inline = 0x0010, - SC_explicit = 0x0020, - SC_register = 0x0040, - SC_pure_virtual = 0x0080, - SC_volatile = 0x0100, - SC_mutable = 0x0200, - SC_consteval = 0x080000, - SC_constexpr = 0x000400, - SC_constinit = 0x100000, - - // This bit is only set by CPPStructType::check_virtual(). - SC_inherited_virtual = 0x0800, - - // This is a special "storage class" for methods tagged with the BLOCKING - // macro (i.e. the special __blocking keyword). These are methods that - // might block and therefore need to release Python threads for their - // duration. - SC_blocking = 0x1000, - - // And this is for methods tagged with __extension, which declares - // extension methods defined separately from the source code. - SC_extension = 0x2000, - - // These are for =default and =delete functions. - SC_defaulted = 0x4000, - SC_deleted = 0x8000, - - SC_thread_local = 0x10000, - - // This isn't really a storage class. It's only used temporarily by the - // parser, to make parsing specifier sequences a bit easier. - SC_const = 0x20000, - - // Used to indicate that this is a parameter pack. - SC_parameter_pack = 0x40000, - }; - - CPPInstance(CPPType *type, const std::string &name, int storage_class = 0); - CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class = 0); - CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, - int storage_class, const CPPFile &file); - CPPInstance(const CPPInstance ©); - ~CPPInstance(); - - static CPPInstance * - make_typecast_function(CPPInstance *inst, CPPIdentifier *ident, - CPPParameterList *parameters, int function_flags); - - bool operator == (const CPPInstance &other) const; - bool operator != (const CPPInstance &other) const; - bool operator < (const CPPInstance &other) const; - - void set_initializer(CPPExpression *initializer); - void set_alignment(int align); - void set_alignment(CPPExpression *const_expr); - - bool is_scoped() const; - CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - std::string get_simple_name() const; - std::string get_local_name(CPPScope *scope = nullptr) const; - std::string get_fully_scoped_name() const; - - void check_for_constructor(CPPScope *current_scope, CPPScope *global_scope); - - virtual CPPDeclaration * - instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, int num_default_parameters) const; - virtual SubType get_subtype() const; - - virtual CPPInstance *as_instance(); - - CPPType *_type; - CPPIdentifier *_ident; - CPPExpression *_initializer; - - int _storage_class; - int _bit_width; - -private: - typedef std::map Instantiations; - Instantiations _instantiations; -}; - -#endif diff --git a/dtool/src/cppparser/cppInstanceIdentifier.cxx b/dtool/src/cppparser/cppInstanceIdentifier.cxx deleted file mode 100644 index cc32ee8a81f..00000000000 --- a/dtool/src/cppparser/cppInstanceIdentifier.cxx +++ /dev/null @@ -1,345 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppInstanceIdentifier.cxx - * @author drose - * @date 1999-10-21 - */ - -#include "cppInstanceIdentifier.h" -#include "cppPointerType.h" -#include "cppReferenceType.h" -#include "cppArrayType.h" -#include "cppConstType.h" -#include "cppFunctionType.h" -#include "cppSimpleType.h" -#include "cppParameterList.h" -#include "cppIdentifier.h" - -/** - * - */ -CPPInstanceIdentifier::Modifier:: -Modifier(CPPInstanceIdentifierType type, CPPAttributeList attr) : - _type(type), - _func_params(nullptr), - _func_flags(0), - _scoping(nullptr), - _expr(nullptr), - _attributes(std::move(attr)) { -} - -/** - * - */ -CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier:: -func_type(CPPParameterList *params, int flags, CPPType *trailing_return_type, - CPPAttributeList attr) { - Modifier mod(IIT_func, std::move(attr)); - mod._func_params = params; - mod._func_flags = flags; - mod._trailing_return_type = trailing_return_type; - return mod; -} - -/** - * - */ -CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier:: -array_type(CPPExpression *expr, CPPAttributeList attr) { - Modifier mod(IIT_array, std::move(attr)); - mod._expr = expr; - return mod; -} - -/** - * - */ -CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier:: -scoped_pointer_type(CPPIdentifier *scoping, CPPAttributeList attr) { - Modifier mod(IIT_scoped_pointer, std::move(attr)); - mod._scoping = scoping; - return mod; -} - -/** - * This is used only for instance declarations that turn out to be have a - * parameter list for an initializer. - */ -CPPInstanceIdentifier::Modifier CPPInstanceIdentifier::Modifier:: -initializer_type(CPPParameterList *params) { - Modifier mod(IIT_initializer); - mod._func_params = params; - return mod; -} - -/** - * - */ -CPPInstanceIdentifier:: -CPPInstanceIdentifier(CPPIdentifier *ident) : - _ident(ident), - _bit_width(nullptr), - _packed(false) { -} - -/** - * - */ -CPPInstanceIdentifier:: -CPPInstanceIdentifier(CPPIdentifier *ident, CPPAttributeList attributes) : - _ident(ident), - _attributes(std::move(attributes)), - _bit_width(nullptr), - _packed(false) { -} - -/** - * Unrolls the list of type punctuation on either side of the identifier to - * determine the actual type represented by the identifier, given the - * indicated starting type (that is, the type name written to the left of the - * identifier). - */ -CPPType *CPPInstanceIdentifier:: -unroll_type(CPPType *start_type) { - CPPType *result = r_unroll_type(start_type, _modifiers.begin()); - return result; -} - - -/** - * - */ -void CPPInstanceIdentifier:: -add_modifier(CPPInstanceIdentifierType type, CPPAttributeList attr) { - _modifiers.push_back(Modifier(type, std::move(attr))); -} - -/** - * - */ -void CPPInstanceIdentifier:: -add_func_modifier(CPPParameterList *params, int flags, - CPPType *trailing_return_type, CPPAttributeList attr) { - // As a special hack, if we added a parameter list to an operator function, - // check if the parameter list is empty. If it is, this is really a unary - // operator, so set the unary_op flag. Operators () and [] are never - // considered unary operators. - if (_ident != nullptr && - _ident->get_simple_name().substr(0, 9) == "operator ") { - - if (_ident->get_simple_name() != std::string("operator ()") && - _ident->get_simple_name() != std::string("operator []")) { - if (params->_parameters.empty()) { - flags |= CPPFunctionType::F_unary_op; - } - } - - flags |= CPPFunctionType::F_operator; - } - - if (trailing_return_type != nullptr) { - // Remember whether trailing return type notation was used. - flags |= CPPFunctionType::F_trailing_return_type; - } - - _modifiers.push_back(Modifier::func_type(params, flags, trailing_return_type, std::move(attr))); -} - -/** - * - */ -void CPPInstanceIdentifier:: -add_scoped_pointer_modifier(CPPIdentifier *scoping, CPPAttributeList attr) { - _modifiers.push_back(Modifier::scoped_pointer_type(scoping, std::move(attr))); -} - -/** - * - */ -void CPPInstanceIdentifier:: -add_array_modifier(CPPExpression *expr, CPPAttributeList attr) { - // Special case for operator new[] and delete[]. We're not really adding an - // array modifier to them, but appending [] to the identifier. This is to - // work around a parser ambiguity. - if (_ident != nullptr && (_ident->get_simple_name() == "operator delete" || - _ident->get_simple_name() == "operator new")) { - - _ident->_names.back().append_name("[]"); - } else { - _modifiers.push_back(Modifier::array_type(expr, std::move(attr))); - } -} - -/** - * - */ -void CPPInstanceIdentifier:: -add_initializer_modifier(CPPParameterList *params) { - _modifiers.push_back(Modifier::initializer_type(params)); -} - -/** - * - */ -void CPPInstanceIdentifier:: -add_trailing_return_type(CPPType *type) { - // This is an awkward hack. Improve in the future. - if (!_modifiers.empty()) { - Modifier &mod = _modifiers.back(); - if (mod._type == IIT_func) { - mod._trailing_return_type = type; - mod._func_flags |= CPPFunctionType::F_trailing_return_type; - return; - } - } - std::cerr << "trailing return type can only be added to a function\n"; -} - -/** - * Add attributes to the instance (not the type). - */ -void CPPInstanceIdentifier:: -add_attributes(const CPPAttributeList &attributes) { - _attributes.add_attributes_from(attributes); -} - -/** - * Returns the initializer parameter list that was set for this particular - * instance, e.g. if the instance were: - * - * int foo(0); - * - * this would return the parameter list (0). Returns NULL if the instance did - * not use a parameter list initializer. - */ -CPPParameterList *CPPInstanceIdentifier:: -get_initializer() const { - Modifiers::const_iterator mi; - for (mi = _modifiers.begin(); mi != _modifiers.end(); ++mi) { - const Modifier &mod = (*mi); - if (mod._type == IIT_initializer) { - return mod._func_params; - } - } - - return nullptr; -} - -/** - * - */ -CPPScope *CPPInstanceIdentifier:: -get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - if (_ident == nullptr) { - return current_scope; - } else { - return _ident->get_scope(current_scope, global_scope, error_sink); - } -} - -/** - * The recursive implementation of unroll_type(). - */ -CPPType *CPPInstanceIdentifier:: -r_unroll_type(CPPType *start_type, - CPPInstanceIdentifier::Modifiers::const_iterator mi) { - assert(start_type != nullptr); - - start_type = CPPType::new_type(start_type); - - if (mi == _modifiers.end()) { - return start_type; - } - - const Modifier &mod = (*mi); - ++mi; - - CPPType *result = nullptr; - - switch (mod._type) { - case IIT_pointer: - result = new CPPPointerType(r_unroll_type(start_type, mi)); - break; - - case IIT_reference: - result = new CPPReferenceType(r_unroll_type(start_type, mi), - CPPReferenceType::VC_lvalue); - break; - - case IIT_rvalue_reference: - result = new CPPReferenceType(r_unroll_type(start_type, mi), - CPPReferenceType::VC_rvalue); - break; - - case IIT_scoped_pointer: - { - CPPType *type = r_unroll_type(start_type, mi); - CPPFunctionType *ftype = type->as_function_type(); - if (ftype != nullptr) { - ftype = new CPPFunctionType(*ftype); - ftype->_class_owner = mod._scoping; - ftype->_flags |= CPPFunctionType::F_method_pointer; - type = ftype; - } - result = new CPPPointerType(type); - } - break; - - case IIT_array: - result = new CPPArrayType(r_unroll_type(start_type, mi), - mod._expr); - break; - - case IIT_const: - result = new CPPConstType(r_unroll_type(start_type, mi)); - break; - - case IIT_volatile: - case IIT_restrict: - // Just pass it through for now. - result = r_unroll_type(start_type, mi); - break; - - case IIT_paren: - result = r_unroll_type(start_type, mi); - break; - - case IIT_func: - { - CPPType *return_type = r_unroll_type(start_type, mi); - if (mod._trailing_return_type != nullptr) { - CPPSimpleType *simple_type = return_type->as_simple_type(); - if (simple_type != nullptr && simple_type->_type == CPPSimpleType::T_auto) { - return_type = mod._trailing_return_type; - } else { - std::cerr << "function with trailing return type needs auto\n"; - } - } - result = new CPPFunctionType(return_type, mod._func_params, - mod._func_flags); - } - break; - - case IIT_initializer: - // In this case, we have parsed an instance declaration with a set of - // initializers as a parameter list. We lose the initializers at this - // point, but the instance will put it back again. - result = start_type; - break; - - default: - std::cerr << "Internal error--invalid CPPInstanceIdentifier\n"; - abort(); - } - - result->_attributes = mod._attributes; - - return CPPType::new_type(result); -} diff --git a/dtool/src/cppparser/cppInstanceIdentifier.h b/dtool/src/cppparser/cppInstanceIdentifier.h deleted file mode 100644 index 21117a8aea8..00000000000 --- a/dtool/src/cppparser/cppInstanceIdentifier.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppInstanceIdentifier.h - * @author drose - * @date 1999-10-21 - */ - -#ifndef CPPINSTANCEIDENTIFIER_H -#define CPPINSTANCEIDENTIFIER_H - -#include "dtoolbase.h" -#include "cppAttributeList.h" - -#include -#include - -class CPPIdentifier; -class CPPParameterList; -class CPPType; -class CPPExpression; -class CPPScope; -class CPPPreprocessor; - -enum CPPInstanceIdentifierType { - IIT_pointer, - IIT_reference, - IIT_rvalue_reference, - IIT_scoped_pointer, - IIT_array, - IIT_const, - IIT_volatile, - IIT_restrict, - IIT_paren, - IIT_func, - IIT_initializer, -}; - -/** - * This class is used in parser.y to build up a variable instance definition. - * An instance is something like 'int *&a'; the InstanceIdentifier stores - * everything to the right of the typename. Later this can be passed to - * make_instance() to construct a CPPInstance. - */ -class CPPInstanceIdentifier { -public: - CPPInstanceIdentifier(CPPIdentifier *ident); - CPPInstanceIdentifier(CPPIdentifier *ident, CPPAttributeList attributes); - - CPPType *unroll_type(CPPType *start_type); - - void add_modifier(CPPInstanceIdentifierType type, - CPPAttributeList attr = CPPAttributeList()); - void add_func_modifier(CPPParameterList *params, int flags, - CPPType *trailing_return_type = nullptr, - CPPAttributeList attr = CPPAttributeList()); - void add_scoped_pointer_modifier(CPPIdentifier *scoping, - CPPAttributeList attr = CPPAttributeList()); - void add_array_modifier(CPPExpression *expr, - CPPAttributeList attr = CPPAttributeList()); - void add_initializer_modifier(CPPParameterList *params); - - void add_trailing_return_type(CPPType *type); - - void add_attributes(const CPPAttributeList &attributes); - - CPPParameterList *get_initializer() const; - - CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - CPPIdentifier *_ident; - - class Modifier { - public: - Modifier(CPPInstanceIdentifierType type, - CPPAttributeList attr = CPPAttributeList()); - static Modifier func_type(CPPParameterList *params, int flags, - CPPType *trailing_return_type, - CPPAttributeList attr); - static Modifier array_type(CPPExpression *expr, CPPAttributeList attr); - static Modifier scoped_pointer_type(CPPIdentifier *scoping, - CPPAttributeList attr); - static Modifier initializer_type(CPPParameterList *params); - - CPPInstanceIdentifierType _type; - CPPParameterList *_func_params; - int _func_flags; - CPPIdentifier *_scoping; - CPPExpression *_expr; - CPPType *_trailing_return_type; - CPPAttributeList _attributes; - }; - typedef std::vector Modifiers; - Modifiers _modifiers; - - CPPAttributeList _attributes; - - // If not null, indicates a bitfield - CPPExpression *_bit_width; - - // Indicates a parameter pack - bool _packed; - -private: - CPPType * - r_unroll_type(CPPType *start_type, Modifiers::const_iterator mi); -}; - -#endif diff --git a/dtool/src/cppparser/cppMakeProperty.cxx b/dtool/src/cppparser/cppMakeProperty.cxx deleted file mode 100644 index 1846092eaaa..00000000000 --- a/dtool/src/cppparser/cppMakeProperty.cxx +++ /dev/null @@ -1,122 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppMakeProperty.cxx - * @author rdb - * @date 2014-09-18 - */ - -#include "cppMakeProperty.h" -#include "cppFunctionGroup.h" - -/** - * - */ -CPPMakeProperty:: -CPPMakeProperty(CPPIdentifier *ident, Type type, - CPPScope *current_scope, const CPPFile &file) : - CPPDeclaration(file), - _ident(ident), - _type(type), - _length_function(nullptr), - _has_function(nullptr), - _get_function(nullptr), - _set_function(nullptr), - _clear_function(nullptr), - _del_function(nullptr), - _insert_function(nullptr), - _get_key_function(nullptr) -{ - _ident->_native_scope = current_scope; -} - -/** - * - */ -std::string CPPMakeProperty:: -get_simple_name() const { - return _ident->get_simple_name(); -} - -/** - * - */ -std::string CPPMakeProperty:: -get_local_name(CPPScope *scope) const { - return _ident->get_local_name(scope); -} - -/** - * - */ -std::string CPPMakeProperty:: -get_fully_scoped_name() const { - return _ident->get_fully_scoped_name(); -} - -/** - * - */ -void CPPMakeProperty:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - if (_length_function != nullptr) { - out << "__make_seq_property"; - } else { - out << "__make_property"; - } - - if (_has_function != nullptr) { - out.put('2'); - } - - out << "(" << _ident->get_local_name(scope); - - if (_length_function != nullptr) { - out << ", " << _length_function->_name; - } - - if (_has_function != nullptr) { - out << ", " << _has_function->_name; - } - - out << ", " << _get_function->_name; - - if (_set_function != nullptr) { - out << ", " << _set_function->_name; - } - - if (_clear_function != nullptr) { - out << ", " << _clear_function->_name; - } - - if (_del_function != nullptr) { - out << ", " << _del_function->_name; - } - - if (_insert_function != nullptr) { - out << ", " << _insert_function->_name; - } - - out << ");"; -} - -/** - * - */ -CPPDeclaration::SubType CPPMakeProperty:: -get_subtype() const { - return ST_make_property; -} - -/** - * - */ -CPPMakeProperty *CPPMakeProperty:: -as_make_property() { - return this; -} diff --git a/dtool/src/cppparser/cppMakeProperty.h b/dtool/src/cppparser/cppMakeProperty.h deleted file mode 100644 index 2967ee3b093..00000000000 --- a/dtool/src/cppparser/cppMakeProperty.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppMakeProperty.h - * @author rdb - * @date 2014-09-18 - */ - -#ifndef CPPMAKEPROPERTY_H -#define CPPMAKEPROPERTY_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" -#include "cppIdentifier.h" - -/** - * This is a MAKE_PROPERTY() declaration appearing within a class body. It - * means to generate a property within Python, replacing (for instance) - * get_something()/set_something() with a synthetic 'something' attribute. - * - * This is an example of a simple property (MAKE_PROPERTY is defined as - * the built-in __make_property): - * @@code - * Thing get_thing() const; - * void set_thing(const Thing &); - * - * MAKE_PROPERTY(thing, get_thing, set_thing); - * @@endcode - * The setter may be omitted to make the property read-only. - * - * There is also a secondary macro that allows the property to be set to a - * cleared state using separate clear functions. In the scripting language, - * this would be represented by a "null" value, or an "optional" construct in - * languages that have no notion of a null value. - * - * @@code - * bool has_thing() const; - * Thing get_thing() const; - * void set_thing(const Thing &); - * void clear_thing(); - * MAKE_PROPERTY2(thing, has_thing, get_thing, set_thing, clear_thing); - * @@endcode - * As with MAKE_PROPERTY, both the setter and clearer can be omitted to create - * a read-only property. - * - * Thirdly, there is a variant called MAKE_SEQ_PROPERTY. It takes a length - * function as argument and the getter and setter take an index as first - * argument: - * @@code - * size_t get_num_things() const; - * Thing &get_thing(size_t i) const; - * void set_thing(size_t i, Thing value) const; - * void remove_thing(size_t i) const; - * - * MAKE_SEQ_PROPERTY(get_num_things, get_thing, set_thing, remove_thing); - * @@endcode - * - * Lastly, there is the possibility to have properties with key/value - * associations, often called a "map" or "dictionary" in scripting languages: - * @@code - * bool has_thing(string key) const; - * Thing &get_thing(string key) const; - * void set_thing(string key, Thing value) const; - * void clear_thing(string key) const; - * - * MAKE_MAP_PROPERTY(things, has_thing, get_thing, set_thing, clear_thing); - * @@endcode - * You may also replace the "has" function with a "find" function that returns - * an index. If the returned index is negative (or in the case of an unsigned - * integer, the maximum value), the item is assumed not to be present in the - * mapping. - * - * It is also possible to use both MAKE_SEQ_PROPERTY and MAKE_MAP_PROPERTY on - * the same property name. This implies that this property has both a - * sequence and mapping interface. - */ -class CPPMakeProperty : public CPPDeclaration { -public: - enum Type { - T_normal = 0x0, - T_sequence = 0x1, - T_mapping = 0x2, - }; - - CPPMakeProperty(CPPIdentifier *ident, Type type, - CPPScope *current_scope, const CPPFile &file); - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - - virtual SubType get_subtype() const; - virtual CPPMakeProperty *as_make_property(); - - CPPIdentifier *_ident; - Type _type; - CPPFunctionGroup *_length_function; - CPPFunctionGroup *_has_function; - CPPFunctionGroup *_get_function; - CPPFunctionGroup *_set_function; - CPPFunctionGroup *_clear_function; - CPPFunctionGroup *_del_function; - CPPFunctionGroup *_insert_function; - CPPFunctionGroup *_get_key_function; -}; - -#endif diff --git a/dtool/src/cppparser/cppMakeSeq.cxx b/dtool/src/cppparser/cppMakeSeq.cxx deleted file mode 100644 index b032d367bbc..00000000000 --- a/dtool/src/cppparser/cppMakeSeq.cxx +++ /dev/null @@ -1,81 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppMakeSeq.cxx - * @author drose - * @date 2008-11-06 - */ - -#include "cppMakeSeq.h" - -/** - * - */ -CPPMakeSeq:: -CPPMakeSeq(CPPIdentifier *ident, - CPPFunctionGroup *length_getter, - CPPFunctionGroup *element_getter, - CPPScope *current_scope, const CPPFile &file) : - CPPDeclaration(file), - _ident(ident), - _length_getter(length_getter), - _element_getter(element_getter) -{ - _ident->_native_scope = current_scope; -} - -/** - * - */ -std::string CPPMakeSeq:: -get_simple_name() const { - return _ident->get_simple_name(); -} - -/** - * - */ -std::string CPPMakeSeq:: -get_local_name(CPPScope *scope) const { - return _ident->get_local_name(scope); -} - -/** - * - */ -std::string CPPMakeSeq:: -get_fully_scoped_name() const { - return _ident->get_fully_scoped_name(); -} - -/** - * - */ -void CPPMakeSeq:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - out << "__make_seq(" << _ident->get_local_name(scope) - << ", " << _length_getter->_name - << ", " << _element_getter->_name - << ");"; -} - -/** - * - */ -CPPDeclaration::SubType CPPMakeSeq:: -get_subtype() const { - return ST_make_seq; -} - -/** - * - */ -CPPMakeSeq *CPPMakeSeq:: -as_make_seq() { - return this; -} diff --git a/dtool/src/cppparser/cppMakeSeq.h b/dtool/src/cppparser/cppMakeSeq.h deleted file mode 100644 index 1db722d9bb7..00000000000 --- a/dtool/src/cppparser/cppMakeSeq.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppMakeSeq.h - * @author drose - * @date 2008-11-06 - */ - -#ifndef CPPMAKESEQ_H -#define CPPMAKESEQ_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" -#include "cppIdentifier.h" -#include "cppFunctionGroup.h" - -/** - * This is a MAKE_SEQ() declaration appearing within a class body. It means - * to generate a sequence method within Python, replacing (for instance) - * get_num_nodes()/get_node(n) with a synthetic get_nodes() method. - */ -class CPPMakeSeq : public CPPDeclaration { -public: - CPPMakeSeq(CPPIdentifier *ident, - CPPFunctionGroup *length_getter, - CPPFunctionGroup *element_getter, - CPPScope *current_scope, const CPPFile &file); - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - - virtual SubType get_subtype() const; - virtual CPPMakeSeq *as_make_seq(); - - CPPIdentifier *_ident; - CPPFunctionGroup *_length_getter; - CPPFunctionGroup *_element_getter; -}; - -#endif diff --git a/dtool/src/cppparser/cppManifest.cxx b/dtool/src/cppparser/cppManifest.cxx deleted file mode 100644 index 4a036f4d7a9..00000000000 --- a/dtool/src/cppparser/cppManifest.cxx +++ /dev/null @@ -1,672 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppManifest.cxx - * @author drose - * @date 1999-10-22 - */ - -#include "cppManifest.h" -#include "cppExpression.h" -#include "cppPreprocessor.h" - -#include - -using std::string; - -/** - * - */ -CPPManifest::ExpansionNode:: -ExpansionNode(int parm_number, bool stringify, bool paste) : - _parm_number(parm_number), - _expand(!stringify && !paste), - _stringify(stringify), - _paste(paste), - _optional(false) -{ -} - -/** - * - */ -CPPManifest::ExpansionNode:: -ExpansionNode(const string &str, bool paste) : - _parm_number(-1), - _expand(!paste), - _stringify(false), - _paste(paste), - _optional(false), - _str(str) -{ -} - -/** - * - */ -CPPManifest::ExpansionNode:: -ExpansionNode(Expansion nested, bool stringify, bool paste, bool optional) : - _parm_number(-1), - _expand(!stringify && !paste), - _stringify(stringify), - _paste(paste), - _optional(optional), - _nested(std::move(nested)) -{ -} - -/** - * - */ -bool CPPManifest::ExpansionNode:: -operator ==(const ExpansionNode &other) const { - return _parm_number == other._parm_number - && _expand == other._expand - && _stringify == other._stringify - && _paste == other._paste - && _optional == other._optional - && _str == other._str - && _nested == other._nested; -} - -/** - * Creates a manifest from a preprocessor definition. - */ -CPPManifest:: -CPPManifest(const CPPPreprocessor &parser, const string &args, const cppyyltype &loc) : - _parser(parser), - _variadic_param(-1), - _loc(loc), - _expr(nullptr), - _vis(V_public) -{ - assert(!args.empty()); - assert(!isspace(args[0])); - - // First, identify the manifest name. - size_t p = 0; - while (p < args.size() && !isspace(args[p]) && args[p] != '(') { - p++; - } - - _name = args.substr(0, p); - - vector_string parameter_names; - - if (args[p] == '(') { - // Hmm, parameters. - _has_parameters = true; - parse_parameters(args, p, parameter_names); - _num_parameters = parameter_names.size(); - - p++; - } else { - _has_parameters = false; - _num_parameters = 0; - } - - // Now identify the expansion. Skip whitespace. - while (p < args.size() && isspace(args[p])) { - p++; - } - - save_expansion(_expansion, args.substr(p), parameter_names); -} - -/** - * Creates a custom manifest definition, for example as specified from a - * command-line -D option. - */ -CPPManifest:: -CPPManifest(const CPPPreprocessor &parser, const string ¯o, const string &definition) : - _parser(parser), - _variadic_param(-1), - _expr(nullptr), - _vis(V_public) -{ - _loc.first_line = 0; - _loc.first_column = 0; - _loc.last_line = 0; - _loc.last_column = 0; - - assert(!macro.empty()); - assert(!isspace(macro[0])); - - // First, identify the manifest name. - size_t p = 0; - while (p < macro.size() && !isspace(macro[p]) && macro[p] != '(') { - p++; - } - - _name = macro.substr(0, p); - - vector_string parameter_names; - - if (macro[p] == '(') { - // Hmm, parameters. - _has_parameters = true; - parse_parameters(macro, p, parameter_names); - _num_parameters = parameter_names.size(); - - p++; - } else { - _has_parameters = false; - _num_parameters = 0; - } - - save_expansion(_expansion, definition, parameter_names); -} - -/** - * - */ -CPPManifest:: -~CPPManifest() { - delete _expr; -} - -/** - * This implements the stringification operator, #. - */ -string CPPManifest:: -stringify(const string &source) { - string result("\""); - - enum { - S_escaped = 0x01, - S_single_quoted = 0x02, - S_double_quoted = 0x04, - S_quoted = 0x06, - }; - int state = 0; - - string::const_iterator it; - for (it = source.begin(); it != source.end(); ++it) { - char c = *it; - - if ((state & S_escaped) == 0) { - switch (c) { - case '\\': - if (state & S_quoted) { - state |= S_escaped; - result += '\\'; - } - break; - - case '\'': - state ^= S_single_quoted; - break; - - case '"': - state ^= S_double_quoted; - result += '\\'; - break; - } - } else { - if (c == '\\' || c == '"') { - result += '\\'; - } - state &= ~S_escaped; - } - - result += c; - } - - result += '"'; - return result; -} - -/** - * - */ -void CPPManifest:: -extract_args(vector_string &args, const string &expr, size_t &p) const { - // Skip whitespace till paren. - while (p < expr.size() && isspace(expr[p])) { - p++; - } - if (p >= expr.size() || expr[p] != '(') { - // No paren, so we have only one arg. - size_t q = p; - while (p < expr.size() && (isalnum(expr[p]) || expr[p] == '_')) { - p++; - } - args.push_back(expr.substr(q, p - q)); - } - else if (expr[p] == '"' || expr[p] == '\'') { - // Quoted string or character. - int quote_mark = expr[p]; - p++; - while (p < expr.size() && expr[p] != quote_mark && expr[p] != '\n') { - if (expr[p] == '\\') { - p++; - } - if (p < expr.size()) { - p++; - } - } - p++; - } - else { - // Skip paren. - p++; - int paren_level = 1; - size_t q = p; - while (p < expr.size()) { - if (expr[p] == ',' && paren_level == 1) { - // Back up to strip any trailing whitespace. - size_t r = p; - while (r > q && isspace(expr[r - 1])) { - --r; - } - args.push_back(expr.substr(q, r - q)); - q = p+1; - } - else if (expr[p] == '"' || expr[p] == '\'') { - // Quoted string or character. - int quote_mark = expr[p]; - p++; - while (p < expr.size() && expr[p] != quote_mark && expr[p] != '\n') { - if (expr[p] == '\\') { - p++; - } - if (p < expr.size()) { - p++; - } - } - } - else if (expr[p] == '(') { - ++paren_level; - } - else if (expr[p] == ')') { - --paren_level; - if (paren_level == 0) { - break; - } - } - else if (isspace(expr[p])) { - // Skip whitespace at the beginning. - if (q == p) { - q++; - } - } - p++; - } - { - // Back up to strip any trailing whitespace. - size_t r = p; - while (r > q && isspace(expr[r - 1])) { - --r; - } - if (!args.empty() || r > q) { - args.push_back(expr.substr(q, r - q)); - } - } - - if (p < expr.size() && expr[p] == ')') { - p++; - } - } - - if ((int)args.size() < _num_parameters) { - _parser.warning("Not enough arguments for manifest " + _name); - } - else if (_variadic_param < 0 && (int)args.size() > _num_parameters) { - _parser.warning("Too many arguments for manifest " + _name); - } -} - -/** - * - */ -string CPPManifest:: -expand(const vector_string &args, bool expand_undefined, const Ignores &ignores) const { - return r_expand(_expansion, args, expand_undefined, ignores); -} - -/** - * Returns the type of the manifest, if it is known, or NULL if the type - * cannot be determined. - */ -CPPType *CPPManifest:: -determine_type() const { - if (_expr != nullptr) { - return _expr->determine_type(); - } - return nullptr; -} - -/** - * Returns true if the macro definitions are equal. - */ -bool CPPManifest:: -is_equal(const CPPManifest *other) const { - if (this == other) { - return true; - } - if (_name != other->_name) { - return false; - } - if (_has_parameters != other->_has_parameters) { - return false; - } - if (_num_parameters != other->_num_parameters) { - return false; - } - if (_variadic_param != other->_variadic_param) { - return false; - } - if (_expansion != other->_expansion) { - return false; - } - return true; -} - -/** - * - */ -void CPPManifest:: -output(std::ostream &out) const { - out << _name; - - if (_has_parameters) { - out << "("; - if (_num_parameters > 0) { - if (_variadic_param == 0) { - out << "..."; - } else { - out << "$1"; - } - - for (size_t i = 1; i < _num_parameters; ++i) { - if (_variadic_param == (int)i) { - out << ", ..."; - } else { - out << ", $" << i + 1; - } - } - } - out << ")"; - } - - Expansion::const_iterator ei; - for (ei = _expansion.begin(); ei != _expansion.end(); ++ei) { - if ((*ei)._paste) { - out << " ## "; - } else { - out << " "; - } - - if ((*ei)._stringify) { - out << "#"; - } - if ((*ei)._parm_number >= 0) { - if ((*ei)._parm_number == _variadic_param) { - out << "__VA_ARGS__"; - } else { - out << "$" << (*ei)._parm_number + 1; - } - } - if ((*ei)._optional) { - out << "__VA_OPT__("; - } - if (!(*ei)._str.empty()) { - out << (*ei)._str; - } - if ((*ei)._optional) { - out << ")"; - } - } -} - -/** - * - */ -void CPPManifest:: -parse_parameters(const string &args, size_t &p, - vector_string ¶meter_names) { - assert(p < args.size()); - assert(args[p] == '('); - - p++; - while (p < args.size() && isspace(args[p])) { - p++; - } - - while (p < args.size() && args[p] != ')') { - // Here's the beginning of a parm. - size_t q = p; - while (p < args.size() && !isspace(args[p]) && - args[p] != ')' && args[p] != ',') { - p++; - } - - // Check if it's a variadic parameter by checking if it ends with "...". - // This picks up both C99-style variadic macros and GCC-style variadic - // macros. - if (p - q >= 3 && args.compare(p - 3, 3, "...") == 0) { - _variadic_param = parameter_names.size(); - parameter_names.push_back(args.substr(q, p - q - 3)); - } else { - parameter_names.push_back(args.substr(q, p - q)); - } - - // Skip whitespace after the parameter name. - while (p < args.size() && isspace(args[p])) { - p++; - } - - if (p < args.size() && args[p] == ',') { - p++; - // Skip whitespace after a comma. - while (p < args.size() && isspace(args[p])) { - p++; - } - } - } -} - -/** - * - */ -void CPPManifest:: -save_expansion(Expansion &expansion, const string &exp, const vector_string ¶meter_names) { - // Walk through the expansion string. For each substring that is an - // identifier, check it against parameter_names. - size_t p = 0; - size_t last = 0; - bool stringify = false; - bool paste = false; - while (p < exp.size()) { - if (isalpha(exp[p]) || exp[p] == '_') { - // Here's the start of an identifier. Find the end of it. - size_t q = p; - p++; - while (p < exp.size() && (isalnum(exp[p]) || exp[p] == '_')) { - p++; - } - - string ident = exp.substr(q, p - q); - - // Is this identifier one of our parameters? - int pnum = -1; - - if (ident == "__VA_ARGS__") { - // C99-style variadics, ie. #define macro(...) __VA_ARGS__ - pnum = _variadic_param; - - } else if (ident == "__VA_OPT__") { - // Optional expansion, only expands if __VA_ARGS__ is non-empty - while (p < exp.size() && isspace(exp[p])) { - ++p; - } - if (p < exp.size() && exp[p] == '(') { - int start = ++p; - int nesting = 1; - while (p < exp.size() && nesting > 0) { - if (exp[p] == '(') { - ++nesting; - } - else if (exp[p] == ')') { - --nesting; - } - ++p; - } - - if (last != q) { - expansion.push_back(ExpansionNode(exp.substr(last, q - last), paste)); - paste = false; - } - - // Store this as a nested expansion, because the whole thing may be - // stringified as a whole. - Expansion nested; - save_expansion(nested, exp.substr(start, p - 1 - start), parameter_names); - expansion.push_back(ExpansionNode(std::move(nested), stringify, paste, true)); - stringify = false; - paste = false; - last = p; - continue; - } - - } else { - for (int i = 0; pnum == -1 && i < (int)parameter_names.size(); ++i) { - const string &pname = parameter_names[i]; - if (pname == ident) { - pnum = i; - } - } - } - - if (pnum != -1) { - // Yep! - if (last != q) { - expansion.push_back(ExpansionNode(exp.substr(last, q - last), paste)); - paste = false; - } - expansion.push_back(ExpansionNode(pnum, stringify, paste)); - stringify = false; - paste = false; - last = p; - } - } else if (exp[p] == '#') { - // This may be a stringification operator. - if (last != p) { - expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste)); - paste = false; - } - - ++p; - - if (p < exp.size() && exp[p] == '#') { - // Woah, this is a token-pasting operator. - paste = true; - if (!expansion.empty()) { - // The previous expansion shouldn't be expanded. - expansion.back()._expand = false; - } - ++p; - } else { - // Mark that the next argument should be stringified. - stringify = true; - } - last = p; - - } else if (isspace(exp[p])) { - if (last != p) { - expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste)); - paste = false; - } - - ++p; - last = p; - - } else { - ++p; - } - } - - if (last != p) { - expansion.push_back(ExpansionNode(exp.substr(last, p - last), paste)); - } -} - -/** - * - */ -string CPPManifest:: -r_expand(const Expansion &expansion, const vector_string &args, - bool expand_undefined, const Ignores &ignores) const { - std::string result; - - for (const ExpansionNode &node : expansion) { - if (node._parm_number >= 0) { - int i = node._parm_number; - - string subst; - if (i < (int)args.size()) { - subst = args[i]; - - if (i == _variadic_param) { - for (++i; i < (int)args.size(); ++i) { - subst += ", " + args[i]; - } - } - if (node._stringify) { - subst = stringify(subst); - } - } - else if (i == _variadic_param && node._paste) { - // Special case GCC behavior: if __VA_ARGS__ is pasted to a comma and - // no arguments are passed, the comma is removed. MSVC does this - // automatically. Not sure if we should allow MSVC behavior as well. - if (!result.empty() && *result.rbegin() == ',') { - result.resize(result.size() - 1); - } - } - - if (node._expand) { - _parser.expand_manifests(subst, expand_undefined, ignores); - } - - if (!subst.empty()) { - if (result.empty() || node._paste || result.back() == '(') { - result += subst; - } else { - result += ' '; - result += subst; - } - } - } - if (!node._str.empty()) { - if (result.empty() || node._paste || node._str[0] == ',' || node._str[0] == ')') { - result += node._str; - } else { - result += ' '; - result += node._str; - } - } - if (!node._nested.empty()) { - string nested_result; - if (node._optional && args.size() >= _num_parameters) { - nested_result = r_expand(node._nested, args, expand_undefined, ignores); - } - if (node._stringify) { - nested_result = stringify(nested_result); - } - if (result.empty() || node._paste) { - result += nested_result; - } else { - result += ' '; - result += nested_result; - } - } - } - - return result; -} diff --git a/dtool/src/cppparser/cppManifest.h b/dtool/src/cppparser/cppManifest.h deleted file mode 100644 index f1e4902ab11..00000000000 --- a/dtool/src/cppparser/cppManifest.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppManifest.h - * @author drose - * @date 1999-10-22 - */ - -#ifndef CPPMANIFEST_H -#define CPPMANIFEST_H - -#include "dtoolbase.h" - -#include "cppFile.h" -#include "cppVisibility.h" -#include "cppBisonDefs.h" - -#include "vector_string.h" -#include - -class CPPExpression; -class CPPType; - -/** - * - */ -class CPPManifest { -public: - typedef std::unordered_set Ignores; - - CPPManifest(const CPPPreprocessor &parser, const std::string &args, const cppyyltype &loc); - CPPManifest(const CPPPreprocessor &parser, const std::string ¯o, const std::string &definition); - ~CPPManifest(); - - static std::string stringify(const std::string &source); - void extract_args(vector_string &args, const std::string &expr, size_t &p) const; - std::string expand(const vector_string &args = vector_string(), - bool expand_undefined = false, - const Ignores &ignores = Ignores()) const; - - - CPPType *determine_type() const; - - bool is_equal(const CPPManifest *other) const; - void output(std::ostream &out) const; - - const CPPPreprocessor &_parser; - std::string _name; - bool _has_parameters; - size_t _num_parameters; - int _variadic_param; - cppyyltype _loc; - CPPExpression *_expr; - - // Manifests don't have a visibility in the normal sense. Normally this - // will be V_public. But a manifest that is defined between __begin_publish - // and __end_publish will have a visibility of V_published. - CPPVisibility _vis; - -private: - class ExpansionNode { - public: - ExpansionNode(int parm_number, bool stringify, bool paste); - ExpansionNode(const std::string &str, bool paste = false); - ExpansionNode(std::vector nested, bool stringify = false, bool paste = false, bool optional = false); - - bool operator ==(const ExpansionNode &other) const; - - int _parm_number; - bool _expand; - bool _stringify; - bool _paste; - bool _optional; - std::string _str; - std::vector _nested; - }; - typedef std::vector Expansion; - - void parse_parameters(const std::string &args, size_t &p, - vector_string ¶meter_names); - void save_expansion(Expansion &expansion, const std::string &exp, - const vector_string ¶meter_names); - - std::string r_expand(const Expansion &expansion, const vector_string &args, - bool expand_undefined, const Ignores &ignores) const; - - Expansion _expansion; -}; - -inline std::ostream &operator << (std::ostream &out, const CPPManifest &manifest) { - manifest.output(out); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppNameComponent.cxx b/dtool/src/cppparser/cppNameComponent.cxx deleted file mode 100644 index 1c8e4df88b1..00000000000 --- a/dtool/src/cppparser/cppNameComponent.cxx +++ /dev/null @@ -1,167 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppNameComponent.cxx - * @author drose - * @date 1999-11-12 - */ - -#include "cppNameComponent.h" -#include "cppTemplateParameterList.h" - -using std::string; - -/** - * - */ -CPPNameComponent:: -CPPNameComponent(const string &name) : - _name(name) -{ - _templ = nullptr; -} - -/** - * - */ -bool CPPNameComponent:: -operator == (const CPPNameComponent &other) const { - if (_name != other._name) { - return false; - } - if (_templ == nullptr && other._templ == nullptr) { - return true; - } - if (_templ == nullptr || other._templ == nullptr) { - return false; - } - if (*_templ != *other._templ) { - return false; - } - - return true; -} - -/** - * - */ -bool CPPNameComponent:: -operator != (const CPPNameComponent &other) const { - return !(*this == other); -} - -/** - * - */ -bool CPPNameComponent:: -operator < (const CPPNameComponent &other) const { - if (_name != other._name) { - return _name < other._name; - } - if (_templ == nullptr && other._templ == nullptr) { - return false; - } - if (_templ == nullptr || other._templ == nullptr) { - return _templ < other._templ; - } - return (*_templ) < (*other._templ); -} - -/** - * - */ -string CPPNameComponent:: -get_name() const { - return _name; -} - -/** - * - */ -string CPPNameComponent:: -get_name_with_templ(CPPScope *scope) const { - std::ostringstream strm; - strm << _name; - if (_templ != nullptr) { - strm << "< "; - _templ->output(strm, scope); - strm << " >"; - } - return strm.str(); -} - -/** - * - */ -CPPTemplateParameterList *CPPNameComponent:: -get_templ() const { - return _templ; -} - -/** - * - */ -bool CPPNameComponent:: -empty() const { - return _name.empty(); -} - -/** - * - */ -bool CPPNameComponent:: -has_templ() const { - return _templ != nullptr; -} - -/** - * Returns true if the name component includes a template parameter list that - * includes some not-yet-defined type. - */ -bool CPPNameComponent:: -is_tbd() const { - if (_templ != nullptr) { - return _templ->is_tbd(); - } - return false; -} - -/** - * - */ -void CPPNameComponent:: -set_name(const string &name) { - _name = name; -} - -/** - * - */ -void CPPNameComponent:: -append_name(const string &name) { - _name += name; -} - -/** - * - */ -void CPPNameComponent:: -set_templ(CPPTemplateParameterList *templ) { - _templ = templ; -} - -/** - * - */ -void CPPNameComponent:: -output(std::ostream &out) const { - out << _name; - if (_templ != nullptr) { - out << "< " << *_templ << " >"; - } -} diff --git a/dtool/src/cppparser/cppNameComponent.h b/dtool/src/cppparser/cppNameComponent.h deleted file mode 100644 index a33de22a394..00000000000 --- a/dtool/src/cppparser/cppNameComponent.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppNameComponent.h - * @author drose - * @date 1999-11-12 - */ - -#ifndef CPPNAMECOMPONENT_H -#define CPPNAMECOMPONENT_H - -#include "dtoolbase.h" -#include "cppBisonDefs.h" - -#include - -class CPPTemplateParameterList; -class CPPScope; - -class CPPNameComponent { -public: - CPPNameComponent(const std::string &name); - bool operator == (const CPPNameComponent &other) const; - bool operator != (const CPPNameComponent &other) const; - bool operator < (const CPPNameComponent &other) const; - - std::string get_name() const; - std::string get_name_with_templ(CPPScope *scope = nullptr) const; - CPPTemplateParameterList *get_templ() const; - bool empty() const; - bool has_templ() const; - - bool is_tbd() const; - - void set_name(const std::string &name); - void append_name(const std::string &name); - void set_templ(CPPTemplateParameterList *templ); - - void output(std::ostream &out) const; - -private: - std::string _name; - CPPTemplateParameterList *_templ; -}; - -inline std::ostream &operator << (std::ostream &out, const CPPNameComponent &name) { - name.output(out); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppNamespace.cxx b/dtool/src/cppparser/cppNamespace.cxx deleted file mode 100644 index ae37bced70b..00000000000 --- a/dtool/src/cppparser/cppNamespace.cxx +++ /dev/null @@ -1,116 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppNamespace.cxx - * @author drose - * @date 1999-11-16 - */ - -#include "cppNamespace.h" -#include "cppIdentifier.h" -#include "cppScope.h" -#include "indent.h" - -/** - * - */ -CPPNamespace:: -CPPNamespace(CPPIdentifier *ident, CPPScope *scope, const CPPFile &file, - CPPAttributeList attr) : - CPPDeclaration(file, std::move(attr)), - _is_inline(false), - _ident(ident), - _scope(scope) -{ -} - -/** - * - */ -std::string CPPNamespace:: -get_simple_name() const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_simple_name(); -} - -/** - * - */ -std::string CPPNamespace:: -get_local_name(CPPScope *scope) const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_local_name(scope); -} - -/** - * - */ -std::string CPPNamespace:: -get_fully_scoped_name() const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_fully_scoped_name(); -} - -/** - * - */ -CPPScope *CPPNamespace:: -get_scope() const { - return _scope; -} - -/** - * - */ -void CPPNamespace:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - if (_is_inline) { - out << "inline "; - } - out << "namespace "; - - if (!complete && _ident != nullptr) { - // If we have a name, use it. - out << "namespace " << _ident->get_local_name(scope); - } - else { - if (!_attributes.is_empty()) { - out << _attributes << " "; - } - if (_ident != nullptr) { - out << _ident->get_local_name(scope) << " {\n"; - } else { - out << "{\n"; - } - - _scope->write(out, indent_level + 2, _scope); - indent(out, indent_level) << "}"; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPNamespace:: -get_subtype() const { - return ST_namespace; -} - -/** - * - */ -CPPNamespace *CPPNamespace:: -as_namespace() { - return this; -} diff --git a/dtool/src/cppparser/cppNamespace.h b/dtool/src/cppparser/cppNamespace.h deleted file mode 100644 index d8b3e7bd214..00000000000 --- a/dtool/src/cppparser/cppNamespace.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppNamespace.h - * @author drose - * @date 1999-11-16 - */ - -#ifndef CPPNAMESPACE_H -#define CPPNAMESPACE_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" - -class CPPIdentifier; -class CPPScope; - -/** - * - */ -class CPPNamespace : public CPPDeclaration { -public: - CPPNamespace(CPPIdentifier *ident, CPPScope *scope, - const CPPFile &file, CPPAttributeList attr = CPPAttributeList()); - - std::string get_simple_name() const; - std::string get_local_name(CPPScope *scope = nullptr) const; - std::string get_fully_scoped_name() const; - CPPScope *get_scope() const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPNamespace *as_namespace(); - - // We can't call this _inline since that would clash with an MSVC built-in - // keyword declaration. - bool _is_inline; - -private: - CPPIdentifier *_ident; - CPPScope *_scope; -}; - -#endif diff --git a/dtool/src/cppparser/cppParameterList.cxx b/dtool/src/cppparser/cppParameterList.cxx deleted file mode 100644 index 4fc5198b6ec..00000000000 --- a/dtool/src/cppparser/cppParameterList.cxx +++ /dev/null @@ -1,239 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppParameterList.cxx - * @author drose - * @date 1999-10-21 - */ - -#include "cppParameterList.h" -#include "cppInstance.h" - -/** - * - */ -CPPParameterList:: -CPPParameterList() { - _includes_ellipsis = false; -} - -/** - * This is similar to operator == except it is more forgiving: it is true if - * only the length and order of types is the same, never minding the instance - * names or initial values. - */ -bool CPPParameterList:: -is_equivalent(const CPPParameterList &other) const { - if (_includes_ellipsis != other._includes_ellipsis) { - return false; - } - if (_parameters.size() != other._parameters.size()) { - return false; - } - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (!_parameters[i]->_type->is_equivalent(*other._parameters[i]->_type)) { - return false; - } - } - return true; -} - -/** - * - */ -bool CPPParameterList:: -operator == (const CPPParameterList &other) const { - if (_includes_ellipsis != other._includes_ellipsis) { - return false; - } - if (_parameters.size() != other._parameters.size()) { - return false; - } - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (*_parameters[i] != *other._parameters[i]) { - return false; - } - } - return true; -} - -/** - * - */ -bool CPPParameterList:: -operator != (const CPPParameterList &other) const { - return !(*this == other); -} - -/** - * - */ -bool CPPParameterList:: -operator < (const CPPParameterList &other) const { - if (_includes_ellipsis != other._includes_ellipsis) { - return _includes_ellipsis < other._includes_ellipsis; - } - if (_parameters.size() != other._parameters.size()) { - return _parameters.size() < other._parameters.size(); - } - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (*_parameters[i] != *other._parameters[i]) { - return *_parameters[i] < *other._parameters[i]; - } - } - return false; -} - -/** - * Returns true if any of the types in the parameter list are base on - * CPPTBDType. - */ -bool CPPParameterList:: -is_tbd() const { - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (_parameters[i]->_type->is_tbd()) { - return true; - } - } - return false; -} - -/** - * Returns true if any of the types in the parameter list turns out to be a - * constant expression, which is a clue that this parameter list is actually - * intended to be an instance declaration. - */ -bool CPPParameterList:: -is_parameter_expr() const { - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (_parameters[i]->_type->is_parameter_expr()) { - return true; - } - } - return false; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPParameterList:: -is_fully_specified() const { - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (!_parameters[i]->is_fully_specified()) { - return false; - } - } - - return true; -} - -/** - * - */ -CPPParameterList *CPPParameterList:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - CPPParameterList *rep = new CPPParameterList; - bool any_changed = false; - for (int i = 0; i < (int)_parameters.size(); ++i) { - CPPInstance *inst = - _parameters[i]->substitute_decl(subst, current_scope, global_scope) - ->as_instance(); - if (inst != _parameters[i]) { - any_changed = true; - } - rep->_parameters.push_back(inst); - } - - if (!any_changed) { - delete rep; - rep = this; - } - return rep; -} - - -/** - * Returns an equivalent CPPParameterList, in which all of the individual - * types have been resolved. - */ -CPPParameterList *CPPParameterList:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPParameterList *rep = new CPPParameterList; - bool any_changed = false; - for (int i = 0; i < (int)_parameters.size(); ++i) { - CPPInstance *inst = _parameters[i]; - CPPType *new_type = inst->_type; - if (new_type->is_tbd()) { - new_type = new_type->resolve_type(current_scope, global_scope); - } - - if (new_type != inst->_type) { - any_changed = true; - CPPInstance *new_inst = new CPPInstance(*inst); - new_inst->_type = new_type; - rep->_parameters.push_back(new_inst); - } else { - rep->_parameters.push_back(inst); - } - } - - if (!any_changed) { - delete rep; - rep = this; - } - return rep; -} - -/** - * If num_default_parameters is >= 0, it indicates the number of default - * parameter values to show on output. Otherwise, all parameter values are - * shown. - */ -void CPPParameterList:: -output(std::ostream &out, CPPScope *scope, bool parameter_names, - int num_default_parameters) const { - if (!_parameters.empty()) { - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (i != 0) { - out << ", "; - } - - // Save the default value expression; we might be about to temporarily - // clear it. - CPPExpression *expr = _parameters[i]->_initializer; - - if (num_default_parameters >= 0 && - i < (int)_parameters.size() - num_default_parameters) { - // Don't show the default value for this parameter. - _parameters[i]->_initializer = nullptr; - } - - if (parameter_names) { - _parameters[i]->output(out, 0, scope, false); - } else { - _parameters[i]->_type->output(out, 0, scope, false); - } - - // Restore the default value expression. - _parameters[i]->_initializer = expr; - } - if (_includes_ellipsis) { - out << ", ..."; - } - - } else if (_includes_ellipsis) { - out << "..."; - - } else { - // No parameters. - out << "void"; - } -} diff --git a/dtool/src/cppparser/cppParameterList.h b/dtool/src/cppparser/cppParameterList.h deleted file mode 100644 index a5e5d327e97..00000000000 --- a/dtool/src/cppparser/cppParameterList.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppParameterList.h - * @author drose - * @date 1999-10-21 - */ - -#ifndef CPPPARAMETERLIST_H -#define CPPPARAMETERLIST_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" - -#include - -class CPPInstance; -class CPPScope; - -/** - * A list of formal parameters for a function declaration. - */ -class CPPParameterList { -public: - CPPParameterList(); - - bool is_equivalent(const CPPParameterList &other) const; - - bool operator == (const CPPParameterList &other) const; - bool operator != (const CPPParameterList &other) const; - bool operator < (const CPPParameterList &other) const; - - bool is_tbd() const; - bool is_parameter_expr() const; - - bool is_fully_specified() const; - CPPParameterList *substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - CPPParameterList *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - // This vector contains a list of formal parameters, in order. A parameter - // may have an empty identifer name. - typedef std::vector Parameters; - Parameters _parameters; - bool _includes_ellipsis; - - void output(std::ostream &out, CPPScope *scope, bool parameter_names, - int num_default_parameters = -1) const; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPParameterList &plist) { - plist.output(out, nullptr, true); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppParser.cxx b/dtool/src/cppparser/cppParser.cxx deleted file mode 100644 index f236a238c99..00000000000 --- a/dtool/src/cppparser/cppParser.cxx +++ /dev/null @@ -1,93 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppParser.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppParser.h" -#include "cppFile.h" -#include "cppTypeParser.h" -#include "cppBisonDefs.h" - -#include -#include - -bool cppparser_output_class_keyword = false; - -/** - * - */ -CPPParser:: -CPPParser() : CPPScope(nullptr, CPPNameComponent(""), V_public) { -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPParser:: -is_fully_specified() const { - // The global scope is always considered to be "fully specified", even if it - // contains some template declarations. - return true; -} - -/** - * - */ -bool CPPParser:: -parse_file(const Filename &filename) { - Filename canonical(filename); - canonical.make_canonical(); - - CPPFile file(canonical, filename, CPPFile::S_local); - - // Don't read it if we included it before and it had #pragma once. - ParsedFiles::iterator it = _parsed_files.find(file); - if (it != _parsed_files.end() && it->_pragma_once) { - // But mark it as local. - it->_source = CPPFile::S_local; - return true; - } - - if (!init_cpp(file)) { - std::cerr << "Unable to read " << filename << "\n"; - return false; - } - parse_cpp(this); - - return get_error_count() == 0; -} - -/** - * Given a string, expand all manifests within the string and evaluate it as - * an expression. Returns NULL if the string is not a valid expression. - */ -CPPExpression *CPPParser:: -parse_expr(const std::string &expr) { - YYLTYPE loc = {}; - return CPPPreprocessor::parse_expr(expr, this, this, loc); -} - -/** - * Given a string, interpret it as a type name and return the corresponding - * CPPType. Returns NULL if the string is not a valid type. - */ -CPPType *CPPParser:: -parse_type(const std::string &type) { - CPPTypeParser ep(this, this); - ep._verbose = 0; - if (ep.parse_type(type, *this)) { - return ep._type; - } else { - return nullptr; - } -} diff --git a/dtool/src/cppparser/cppParser.h b/dtool/src/cppparser/cppParser.h deleted file mode 100644 index 82ac2abd08c..00000000000 --- a/dtool/src/cppparser/cppParser.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppParser.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPPARSER_H -#define CPPPARSER_H - -#include "dtoolbase.h" - -#include "cppScope.h" -#include "cppPreprocessor.h" -#include "filename.h" - -#include - -/** - * - */ -class CPPParser : public CPPScope, public CPPPreprocessor { -public: - CPPParser(); - - virtual bool is_fully_specified() const; - - bool parse_file(const Filename &filename); - - CPPExpression *parse_expr(const std::string &expr); - CPPType *parse_type(const std::string &type); -}; - -/* - * Normally, this variable should be left true, especially while parsing. - * However, after parsing has finished, and you want to output the results of - * parsing in a way that can be successfully compiled by VC++, you may need to - * set this variable to false. It controls the way typenames are written. - * When true, class names are written 'class X', which is the way the parser - * expects things to come, and which compiles successfully under every - * compiler except VC++. When false, class names are written simply 'X', - * which is the only way they'll compile under VC++. - */ -extern bool cppparser_output_class_keyword; - -#endif diff --git a/dtool/src/cppparser/cppPointerType.cxx b/dtool/src/cppparser/cppPointerType.cxx deleted file mode 100644 index 768bd43841d..00000000000 --- a/dtool/src/cppparser/cppPointerType.cxx +++ /dev/null @@ -1,308 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppPointerType.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppPointerType.h" -#include "cppFunctionType.h" -#include "cppIdentifier.h" -#include "cppArrayType.h" -#include "cppStructType.h" -#include "cppSimpleType.h" - -/** - * - */ -CPPPointerType:: -CPPPointerType(CPPType *pointing_at) : - CPPType(CPPFile()), - _pointing_at(pointing_at) -{ -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPPointerType:: -is_fully_specified() const { - return CPPType::is_fully_specified() && - _pointing_at->is_fully_specified(); -} - -/** - * - */ -CPPDeclaration *CPPPointerType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - return (*si).second; - } - - CPPPointerType *rep = new CPPPointerType(*this); - rep->_pointing_at = - _pointing_at->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - - if (rep->_pointing_at == _pointing_at) { - delete rep; - rep = this; - } - rep = CPPType::new_type(rep)->as_pointer_type(); - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPPointerType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPType *ptype = _pointing_at->resolve_type(current_scope, global_scope); - - if (ptype != _pointing_at) { - CPPPointerType *rep = new CPPPointerType(*this); - rep->_pointing_at = ptype; - return CPPType::new_type(rep); - } - return this; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPPointerType:: -is_tbd() const { - return _pointing_at->is_tbd(); -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPPointerType:: -is_standard_layout() const { - return true; -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPPointerType:: -is_trivial() const { - return true; -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPPointerType:: -is_trivially_copyable() const { - return true; -} - -/** - * Returns true if the type can be constructed using the given argument. - */ -bool CPPPointerType:: -is_constructible(const CPPType *given_type) const { - given_type = ((CPPType *)given_type)->remove_reference()->remove_cv(); - - // Can convert from compatible pointer or array type. - CPPType *other_target; - switch (given_type->get_subtype()) { - case ST_array: - other_target = given_type->as_array_type()->_element_type; - break; - - case ST_pointer: - other_target = given_type->as_pointer_type()->_pointing_at; - break; - - case ST_simple: - // Can initialize from nullptr. - return given_type->as_simple_type()->_type == CPPSimpleType::T_nullptr; - - default: - return false; - } - - // Can't convert const to non-const pointer. - if (other_target->is_const() && !_pointing_at->is_const()) { - return false; - } - - // Are we pointing to the same type? That's always OK. - const CPPType *a = _pointing_at->remove_cv(); - const CPPType *b = other_target->remove_cv(); - if (a == b || *a == *b) { - return true; - } - - // Can initialize void pointer with any pointer. - const CPPSimpleType *simple_type = a->as_simple_type(); - if (simple_type != nullptr) { - return simple_type->_type == CPPSimpleType::T_void; - } - - // Can initialize from derived class pointer. - const CPPStructType *a_struct = a->as_struct_type(); - const CPPStructType *b_struct = b->as_struct_type(); - if (a_struct != nullptr && b_struct != nullptr) { - return a_struct->is_base_of(b_struct); - } - - return false; -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPPointerType:: -is_default_constructible() const { - return true; -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPPointerType:: -is_copy_constructible() const { - return true; -} - -/** - * Returns true if the type is copy-assignable. - */ -bool CPPPointerType:: -is_copy_assignable() const { - return true; -} - -/** - * This is a little more forgiving than is_equal(): it returns true if the - * types appear to be referring to the same thing, even if they may have - * different pointers or somewhat different definitions. It's useful for - * parameter matching, etc. - */ -bool CPPPointerType:: -is_equivalent(const CPPType &other) const { - const CPPPointerType *ot = ((CPPType *)&other)->as_pointer_type(); - if (ot == nullptr) { - return CPPType::is_equivalent(other); - } - - return _pointing_at->is_equivalent(*ot->_pointing_at); -} - -/** - * - */ -void CPPPointerType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - /* - CPPFunctionType *ftype = _pointing_at->as_function_type(); - if (ftype != (CPPFunctionType *)NULL) { - // Pointers to functions are a bit of a special case; we have to be a - // little more careful about where the '*' goes. - - string star = "*"; - if ((ftype->_flags & CPPFunctionType::F_method_pointer) != 0) { - // We have to output pointers-to-method with a scoping before the '*'. - star = ftype->_class_owner->get_fully_scoped_name() + "::*"; - } - - _pointing_at->output_instance(out, indent_level, scope, complete, - star, ""); - - } else { - _pointing_at->output(out, indent_level, scope, complete); - out << " *"; - } - */ - output_instance(out, indent_level, scope, complete, "", ""); -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPPointerType:: -output_instance(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const { - std::string star = "*"; - - CPPFunctionType *ftype = _pointing_at->as_function_type(); - if (ftype != nullptr && - ((ftype->_flags & CPPFunctionType::F_method_pointer) != 0)) { - // We have to output pointers-to-method with a scoping before the '*'. - star = ftype->_class_owner->get_fully_scoped_name() + "::*"; - } - - if (!_attributes.is_empty()) { - std::ostringstream strm; - strm << star << _attributes << " "; - star = strm.str(); - } - - _pointing_at->output_instance(out, indent_level, scope, complete, - star + prename, name); -} - -/** - * - */ -CPPDeclaration::SubType CPPPointerType:: -get_subtype() const { - return ST_pointer; -} - -/** - * - */ -CPPPointerType *CPPPointerType:: -as_pointer_type() { - return this; -} - - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPPointerType:: -is_equal(const CPPDeclaration *other) const { - const CPPPointerType *ot = ((CPPDeclaration *)other)->as_pointer_type(); - assert(ot != nullptr); - - return _pointing_at == ot->_pointing_at; -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPPointerType:: -is_less(const CPPDeclaration *other) const { - const CPPPointerType *ot = ((CPPDeclaration *)other)->as_pointer_type(); - assert(ot != nullptr); - - return _pointing_at < ot->_pointing_at; -} diff --git a/dtool/src/cppparser/cppPointerType.h b/dtool/src/cppparser/cppPointerType.h deleted file mode 100644 index 683398be733..00000000000 --- a/dtool/src/cppparser/cppPointerType.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppPointerType.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPPOINTERTYPE_H -#define CPPPOINTERTYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" - -/** - * - */ -class CPPPointerType : public CPPType { -public: - CPPPointerType(CPPType *pointing_at); - - CPPType *_pointing_at; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_tbd() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *other) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_copy_assignable() const; - virtual bool is_equivalent(const CPPType &other) const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const; - - virtual SubType get_subtype() const; - - virtual CPPPointerType *as_pointer_type(); - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppPreprocessor.cxx b/dtool/src/cppparser/cppPreprocessor.cxx deleted file mode 100644 index 74d2803e5c8..00000000000 --- a/dtool/src/cppparser/cppPreprocessor.cxx +++ /dev/null @@ -1,3305 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppPreprocessor.cxx - * @author drose - * @date 1999-10-22 - */ - -#include "cppPreprocessor.h" -#include "cppExpressionParser.h" -#include "cppExpression.h" -#include "cppScope.h" -#include "cppIdentifier.h" -#include "cppTemplateScope.h" -#include "cppTemplateParameterList.h" -#include "cppClassTemplateParameter.h" -#include "cppConstType.h" -#include "cppFunctionGroup.h" -#include "cppFunctionType.h" -#include "cppPointerType.h" -#include "cppParameterList.h" -#include "cppSimpleType.h" -#include "cppGlobals.h" -#include "cppCommentBlock.h" -#include "cppBison.h" -#include "indent.h" -#include "pstrtod.h" -#include "string_utils.h" - -#include -#include -#include - -using std::cerr; -using std::string; - -// We manage our own visibility counter, in addition to that managed by -// cppBison.y. We do this just so we can define manifests with the correct -// visibility when they are declared. (Asking the parser for the current -// visibility is prone to error, since the parser might be several tokens -// behind the preprocessor.) -static CPPVisibility preprocessor_vis = V_public; - -// Don't forget to update CPPToken::output() when adding entries. -static const std::unordered_map keywords = { - {"alignas", KW_ALIGNAS}, - {"alignof", KW_ALIGNOF}, - {"__alignof", KW_ALIGNOF}, - {"__alignof__", KW_ALIGNOF}, - {"auto", KW_AUTO}, - {"__begin_publish", KW_BEGIN_PUBLISH}, - {"__blocking", KW_BLOCKING}, - {"bool", KW_BOOL}, - {"__builtin_va_list", KW_BUILTIN_VA_LIST}, - {"catch", KW_CATCH}, - {"char", KW_CHAR}, - {"char8_t", KW_CHAR8_T}, - {"char16_t", KW_CHAR16_T}, - {"char32_t", KW_CHAR32_T}, - {"class", KW_CLASS}, - {"const", KW_CONST}, - {"__const", KW_CONST}, - {"__const__", KW_CONST}, - {"consteval", KW_CONSTEVAL}, - {"constexpr", KW_CONSTEXPR}, - {"constinit", KW_CONSTINIT}, - {"const_cast", KW_CONST_CAST}, - {"decltype", KW_DECLTYPE}, - {"default", KW_DEFAULT}, - {"delete", KW_DELETE}, - {"double", KW_DOUBLE}, - {"dynamic_cast", KW_DYNAMIC_CAST}, - {"else", KW_ELSE}, - {"__end_publish", KW_END_PUBLISH}, - {"enum", KW_ENUM}, - {"extern", KW_EXTERN}, - {"__extension", KW_EXTENSION}, - {"explicit", KW_EXPLICIT}, - {"__published", KW_PUBLISHED}, - {"false", KW_FALSE}, - {"final", KW_FINAL}, - {"float", KW_FLOAT}, - {"friend", KW_FRIEND}, - {"for", KW_FOR}, - {"goto", KW_GOTO}, - {"__has_virtual_destructor", KW_HAS_VIRTUAL_DESTRUCTOR}, - {"if", KW_IF}, - {"inline", KW_INLINE}, - {"__inline", KW_INLINE}, - {"__inline__", KW_INLINE}, - {"int", KW_INT}, - {"__is_abstract", KW_IS_ABSTRACT}, - {"__is_base_of", KW_IS_BASE_OF}, - {"__is_class", KW_IS_CLASS}, - {"__is_constructible", KW_IS_CONSTRUCTIBLE}, - {"__is_convertible_to", KW_IS_CONVERTIBLE_TO}, - {"__is_destructible", KW_IS_DESTRUCTIBLE}, - {"__is_empty", KW_IS_EMPTY}, - {"__is_enum", KW_IS_ENUM}, - {"__is_final", KW_IS_FINAL}, - {"__is_fundamental", KW_IS_FUNDAMENTAL}, - {"__is_pod", KW_IS_POD}, - {"__is_polymorphic", KW_IS_POLYMORPHIC}, - {"__is_standard_layout", KW_IS_STANDARD_LAYOUT}, - {"__is_trivial", KW_IS_TRIVIAL}, - {"__is_trivially_copyable", KW_IS_TRIVIALLY_COPYABLE}, - {"__is_union", KW_IS_UNION}, - {"long", KW_LONG}, - {"__make_map_keys_seq", KW_MAKE_MAP_KEYS_SEQ}, - {"__make_map_property", KW_MAKE_MAP_PROPERTY}, - {"__make_property", KW_MAKE_PROPERTY}, - {"__make_property2", KW_MAKE_PROPERTY2}, - {"__make_seq", KW_MAKE_SEQ}, - {"__make_seq_property", KW_MAKE_SEQ_PROPERTY}, - {"mutable", KW_MUTABLE}, - {"namespace", KW_NAMESPACE}, - {"noexcept", KW_NOEXCEPT}, - {"nullptr", KW_NULLPTR}, - {"new", KW_NEW}, - {"operator", KW_OPERATOR}, - {"override", KW_OVERRIDE}, - {"private", KW_PRIVATE}, - {"protected", KW_PROTECTED}, - {"public", KW_PUBLIC}, - {"register", KW_REGISTER}, - {"reinterpret_cast", KW_REINTERPRET_CAST}, - //{"restrict", KW_RESTRICT}, - {"__restrict", KW_RESTRICT}, - {"__restrict__", KW_RESTRICT}, - {"return", KW_RETURN}, - {"short", KW_SHORT}, - {"signed", KW_SIGNED}, - {"sizeof", KW_SIZEOF}, - {"static", KW_STATIC}, - {"static_assert", KW_STATIC_ASSERT}, - {"static_cast", KW_STATIC_CAST}, - {"struct", KW_STRUCT}, - {"template", KW_TEMPLATE}, - {"thread_local", KW_THREAD_LOCAL}, - {"throw", KW_THROW}, - {"true", KW_TRUE}, - {"try", KW_TRY}, - {"typedef", KW_TYPEDEF}, - {"typeid", KW_TYPEID}, - {"typename", KW_TYPENAME}, - {"__underlying_type", KW_UNDERLYING_TYPE}, - {"union", KW_UNION}, - {"unsigned", KW_UNSIGNED}, - {"using", KW_USING}, - {"virtual", KW_VIRTUAL}, - {"void", KW_VOID}, - {"volatile", KW_VOLATILE}, - {"wchar_t", KW_WCHAR_T}, - {"while", KW_WHILE}, - - // These are alternative ways to refer to built-in operators. - {"and", ANDAND}, - {"and_eq", ANDEQUAL}, - {"bitand", '&'}, - {"bitor", '|'}, - {"compl", '~'}, - {"not", '!'}, - {"not_eq", NECOMPARE}, - {"or", OROR}, - {"or_eq", OREQUAL}, - {"xor", '^'}, - {"xor_eq", XOREQUAL}, -}; - -static int -hex_val(int c) { - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return (c - '0'); - - default: - return (tolower(c) - 'a' + 10); - } -} - -static string -trim_blanks(const string &str) { - size_t first, last; - - if(str.empty()) - return str; - - first = 0; - while (first < str.length() && isspace(str[first])) { - first++; - } - - last = str.length() - 1; - while (last > first && isspace(str[last])) { - last--; - } - - return str.substr(first, last - first + 1); -} - -/** - * - */ -CPPPreprocessor::InputFile:: -InputFile() { - _in = nullptr; - _manifest = nullptr; - _line_number = 0; - _col_number = 0; - _next_line_number = 1; - _next_col_number = 1; - _lock_position = false; - _ignore_manifest = false; -} - -/** - * - */ -CPPPreprocessor::InputFile:: -~InputFile() { - if (_in != nullptr) { - // For some reason--compiler bug in gcc 3.2?--explicitly deleting the - // stream pointer does not call the appropriate global delete function; - // instead apparently calling the system delete function. So we call the - // delete function by hand instead. -#if !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW) - _in->~istream(); - (*global_operator_delete)(_in); -#else - delete _in; -#endif - } -} - -/** - * - */ -bool CPPPreprocessor::InputFile:: -open(const CPPFile &file) { - assert(_in == nullptr); - - _file = file; - pifstream *in = new pifstream; - _in = in; - - return _file._filename.open_read(*in); -} - -/** - * - */ -bool CPPPreprocessor::InputFile:: -connect_input(const string &input) { - assert(_in == nullptr); - - _input = input; - _in = new std::istringstream(_input); - return !_in->fail(); -} - -/** - * Fetches a single character from the source file. - */ -int CPPPreprocessor::InputFile:: -get() { - assert(_in != nullptr); - - if (!_lock_position) { - _line_number = _next_line_number; - _col_number = _next_col_number; - } - - int c = _in->get(); - - // Quietly skip over embedded carriage-return characters. We shouldn't see - // any of these unless there was some DOS-to-Unix file conversion problem. - while (c == '\r') { - c = _in->get(); - } - - switch (c) { - case EOF: - break; - - case '\n': - if (!_lock_position) { - ++_next_line_number; - _next_col_number = 1; - } - break; - - default: - if (!_lock_position) { - ++_next_col_number; - } - } - - return c; -} - -/** - * Like get(), but does not advance the file pointer. - */ -int CPPPreprocessor::InputFile:: -peek() { - assert(_in != nullptr); - - int c = _in->peek(); - - // Quietly skip over embedded carriage-return characters. We shouldn't see - // any of these unless there was some DOS-to-Unix file conversion problem. - while (c == '\r') { - _in->get(); - c = _in->peek(); - } - - return c; -} - -/** - * - */ -CPPPreprocessor:: -CPPPreprocessor() { - _noangles = false; - _state = S_eof; - _paren_nesting = 0; - _parsing_template_params = false; - _parsing_attribute = false; - _unget = '\0'; - _last_c = '\0'; - _start_of_line = true; - _last_cpp_comment = false; - _save_comments = true; - - _resolve_identifiers = true; - - _warning_count = 0; - _error_count = 0; - _error_abort = false; -#ifdef CPP_VERBOSE_LEX - _token_index = 0; -#endif - _verbose = 1; -} - -/** - * - */ -bool CPPPreprocessor:: -preprocess_file(const Filename &filename) { - Filename canonical(filename); - canonical.make_canonical(); - - CPPFile file(canonical, filename, CPPFile::S_local); - - // Don't read it if we included it before and it had #pragma once. - ParsedFiles::iterator it = _parsed_files.find(file); - if (it != _parsed_files.end() && it->_pragma_once) { - // But mark it as local. - it->_source = CPPFile::S_local; - return true; - } - - if (!init_cpp(file)) { - std::cerr << "Unable to read " << filename << "\n"; - return false; - } - - int line_number = 1; - int nesting = 0; - bool next_space = false; - CPPToken token = get_next_token(); - while (!token.is_eof()) { - if (token._token == '}') { - nesting -= 1; - } - if (token._lloc.first_line > line_number) { - // Token is on a different line, so insert a newline. - std::cout << "\n"; - line_number = token._lloc.first_line; - indent(std::cout, nesting * 2); - } - else if (next_space && token._token != ';' && token._token != ':' && token._token != ',' && token._token != ')') { - // The above tokens never need a preceding space - std::cout << " "; - } - if (token._token == '{') { - nesting += 1; - } - next_space = (token._token != '(' && token._token != '~'); - token.output_code(std::cout); - - CPPToken next_token = get_next_token(); - if (next_token._lloc.file != token._lloc.file) { - // Switched to a new file, reset the line number. - line_number = 0; - } - token = std::move(next_token); - } - std::cout << "\n"; - - return get_error_count() == 0; -} - -/** - * Sets the verbosity level of the parser. At 0, no warnings will be - * reported; at 1 or higher, expect to get spammed. - */ -void CPPPreprocessor:: -set_verbose(int verbose) { - _verbose = verbose; -} - -/** - * Returns the verbosity level of the parser. - */ -int CPPPreprocessor:: -get_verbose() const { - return _verbose; -} - -/** - * - */ -void CPPPreprocessor:: -copy_filepos(const CPPPreprocessor &other) { - InputFile *infile = _infile; - assert(infile != nullptr); - infile->_file = other.get_file(); - infile->_line_number = other.get_line_number(); - infile->_col_number = other.get_col_number(); -} - -/** - * - */ -CPPFile CPPPreprocessor:: -get_file() const { - InputFile *infile = _infile; - if (infile != nullptr) { - return infile->_file; - } else { - return CPPFile(""); - } -} - -/** - * Returns the line number of the last character returned by get(). - */ -int CPPPreprocessor:: -get_line_number() const { - InputFile *infile = _infile; - if (infile != nullptr) { - return infile->_line_number; - } else { - return 0; - } -} - -/** - * Returns the column number of the last character returned by get(). - */ -int CPPPreprocessor:: -get_col_number() const { - InputFile *infile = _infile; - if (infile != nullptr) { - return infile->_col_number; - } else { - return 0; - } -} - -/** - * - */ -CPPToken CPPPreprocessor:: -get_next_token() { - -#ifdef CPP_VERBOSE_LEX - CPPToken tok = get_next_token0(); - indent(cerr, get_file_depth() * 2) - << _token_index++ << ". " << tok << "\n"; - return tok; -} - -CPPToken CPPPreprocessor:: -get_next_token0() { -#endif - - // We make a nested call to internal_get_next_token(), so we can combine - // sequences of identifiers and scoping symbols into a single identifier, - // for yacc's convenience. - - CPPToken token(0); - if (!_saved_tokens.empty()) { - token = std::move(_saved_tokens.back()); - _saved_tokens.pop_back(); - } else { - token = internal_get_next_token(); - } - - YYLTYPE loc = token._lloc; - - if (_resolve_identifiers && - (token._token == SIMPLE_IDENTIFIER || token._token == SCOPE)) { - // We will be returning a scoped identifier, or a scoping. Keep pulling - // off tokens until we reach the end of the scopeidentifier sequence. - - string name; - - // If we started the ball with an identifier, use it and get the next - // token. Otherwise, we started with :: (global scope), and we indicate - // this with an empty string at the beginning of the scoping sequence. - if (token._token == SIMPLE_IDENTIFIER) { - name = token._lval.str; - token = internal_get_next_token(); - } - - CPPIdentifier *ident = new CPPIdentifier(name, loc); - YYSTYPE result; - result.u.identifier = ident; - - if (token._token == '<') { - // If the next token is an angle bracket and the current identifier - // wants template instantiation, assume the angle bracket begins the - // instantiation and call yacc recursively to parse the template - // parameters. - CPPDeclaration *decl = ident->find_template(current_scope, global_scope); - if (decl != nullptr) { - ident->_names.back().set_templ - (nested_parse_template_instantiation(decl->get_template_scope())); - token = internal_get_next_token(); - //} else { - // error(string("unknown template '") + ident->get_fully_scoped_name() + "'", loc); - } - } - - while (token._token == SCOPE) { - loc.last_line = token._lloc.last_line; - loc.last_column = token._lloc.last_column; - - name += "::"; - token = internal_get_next_token(); - string token_prefix; - - if (token._token == '~') { - // A scoping operator followed by a tilde can only be the start of a - // scoped destructor name. Make the tilde be part of the name. - name += "~"; - token_prefix = "~"; - token = internal_get_next_token(); - } - - if (token._token != SIMPLE_IDENTIFIER) { - // The last useful token was a SCOPE, thus this is a scoping token. - - if (token._token == KW_OPERATOR) { - // Unless the last token we came across was the "operator" keyword. - // We make a special case for this, because it's occasionally scoped - // in normal use. - token._lval = result; - _last_token_loc = token._lloc; - return token; - } - _saved_tokens.push_back(token); - _last_token_loc = loc; - return CPPToken(SCOPING, loc, name, result); - } - - name += token._lval.str; - ident->_names.push_back(token_prefix + token._lval.str); - - loc.last_line = token._lloc.last_line; - loc.last_column = token._lloc.last_column; - ident->_loc.last_line = loc.last_line; - ident->_loc.last_column = loc.last_column; - - token = internal_get_next_token(); - - if (token._token == '<') { - // If the next token is an angle bracket and the current indentifier - // wants template instantiation, assume the angle bracket begins the - // instantiation and call yacc recursively to parse the template - // parameters. - CPPDeclaration *decl = - ident->find_template(current_scope, global_scope); - if (decl != nullptr) { - ident->_names.back().set_templ - (nested_parse_template_instantiation(decl->get_template_scope())); - token = internal_get_next_token(); - } else { - error(string("unknown template '") + ident->get_fully_scoped_name() + "'", loc); - } - } - } - // The last useful token was a SIMPLE_IDENTIFIER, thus this is a normal - // scoped identifier. - _saved_tokens.push_back(token); - - int token_type = IDENTIFIER; - CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope); - if (decl != nullptr && decl->as_type() != nullptr) { - // We need to see type pack template parameters as a different type of - // identifier to resolve a parser ambiguity. - CPPClassTemplateParameter *ctp = decl->as_class_template_parameter(); - if (ctp && ctp->_packed) { - token_type = TYPEPACK_IDENTIFIER; - } else { - token_type = TYPENAME_IDENTIFIER; - } - } - - _last_token_loc = loc; - return CPPToken(token_type, loc, name, result); - } - - // This is the normal case: just pass through whatever token we got. - _last_token_loc = loc; - return token; -} - -/** - * - */ -CPPToken CPPPreprocessor:: -peek_next_token() { - CPPToken token(0); - if (!_saved_tokens.empty()) { - token = _saved_tokens.back(); - } else { - token = internal_get_next_token(); - _saved_tokens.push_back(token); - } - return token; -} - -/** - * - */ -void CPPPreprocessor:: -warning(const string &message) const { - if (_verbose < 2) { - return; - } - int line = get_line_number(); - int col = get_col_number(); - YYLTYPE loc; - loc.first_line = line; - loc.first_column = col; - loc.last_line = line; - loc.last_column = col; - loc.file = get_file(); - warning(message, loc); -} - -/** - * - */ -void CPPPreprocessor:: -warning(const string &message, const YYLTYPE &loc) const { - if (_verbose >= 2) { - if (_verbose >= 3) { - indent(cerr, get_file_depth() * 2); - } - - if (!loc.file.empty()) { - cerr << loc.file << ':'; - } - if (loc.first_line) { - cerr << loc.first_line << ':'; - - if (loc.first_column) { - cerr << loc.first_column << ':'; - } - } - - cerr << " warning: " << message << "\n"; - show_line(loc); - } - _warning_count++; -} - -/** - * - */ -void CPPPreprocessor:: -error(const string &message) const { - int line = get_line_number(); - int col = get_col_number(); - YYLTYPE loc; - loc.first_line = line; - loc.first_column = col; - loc.last_line = line; - loc.last_column = col; - loc.file = get_file(); - error(message, loc); -} - -/** - * - */ -void CPPPreprocessor:: -error(const string &message, const YYLTYPE &loc) const { - if (_state == S_nested || _state == S_end_nested) { - // Don't report or log errors in the nested state. These will be reported - // when the nesting level collapses. - return; - } - - if (_verbose >= 1) { - if (_verbose >= 3) { - indent(cerr, get_file_depth() * 2); - } - - if (!loc.file.empty()) { - cerr << loc.file << ':'; - } - if (loc.first_line) { - cerr << loc.first_line << ':'; - - if (loc.first_column) { - cerr << loc.first_column << ':'; - } - } - - cerr << " error: " << message << "\n"; - show_line(loc); - - InputFile *infile = _infile; - if (infile != nullptr && !loc.file.empty()) { - // Add all the expansions to a vector for easy reverse iteration. - std::vector infiles; - while (infile != nullptr && infile->_file == loc.file && infile->_manifest != nullptr) { - infiles.push_back(infile); - infile = infile->_parent; - } - if (!infiles.empty()) { - auto rit = infiles.rbegin(); - if (_verbose >= 3) { - cerr << "Expansion of " << (*rit)->_manifest->_name << ":\n"; - while (rit != infiles.rend()) { - cerr << " -> " << trim_blanks((*rit)->_input) << "\n"; - ++rit; - } - } - else { - cerr << "with " << (*rit)->_manifest->_name; - if ((*rit)->_manifest->_has_parameters) { - cerr << "()"; - } - cerr << " expanded to: " << trim_blanks(_infile->_input) << "\n"; - } - cerr << std::endl; - } - } - - if (_error_abort) { - cerr << "Aborting.\n"; - abort(); - } - } - _error_count++; -} - -/** - * Shows the indicated line, useful for error messages. - */ -void CPPPreprocessor:: -show_line(const YYLTYPE &loc) const { - if (loc.file._filename.empty()) { - return; - } - - int indent_level = 0; - if (_verbose >= 3) { - indent_level = get_file_depth() * 2; - } - - // Seek to the offending line in the file. - std::ifstream stream; - if (loc.file._filename.open_read(stream)) { - int l = 0; - string linestr; - while (l < loc.first_line) { - std::getline(stream, linestr); - ++l; - } - - // Strip off trailing whitespace. - size_t last = linestr.length(); - while (isspace(linestr[--last])) { - linestr = linestr.substr(0, last); - } - - indent(cerr, indent_level) << linestr << "\n"; - - // Point the user at the offending column. - if (loc.first_column) { - int last_column; - if (loc.first_line == loc.last_line && loc.last_column) { - last_column = loc.last_column; - } else { - last_column = linestr.length(); - } - - indent(cerr, indent_level); - int i = 0; - for (; i < loc.first_column - 1; ++i) { - cerr.put(' '); - } - cerr.put('^'); - while (++i < last_column) { - cerr.put('~'); - } - cerr << "\n"; - } - } -} - -/** - * - */ -int CPPPreprocessor:: -get_warning_count() const { - return _warning_count; -} - -/** - * - */ -int CPPPreprocessor:: -get_error_count() const { - return _error_count; -} - -/** - * Returns the CPPCommentBlock immediately preceding the indicated line, if - * any. If there is no such comment, returns NULL. - */ -CPPCommentBlock *CPPPreprocessor:: -get_comment_before(int line, CPPFile file) { - CPPComments::reverse_iterator ci; - ci = _comments.rbegin(); - - int wrong_file_count = 0; - while (ci != _comments.rend()) { - CPPCommentBlock *comment = (*ci); - if (comment->_file == file) { - wrong_file_count = 0; - if (comment->_last_line == line || comment->_last_line == line - 1) { - return comment; - } - - if (comment->_last_line < line) { - return nullptr; - } - } else { - wrong_file_count++; - if (wrong_file_count > 10) { - return nullptr; - } - } - - ++ci; - } - - return nullptr; -} - -/** - * Returns the CPPCommentBlock that starts on the indicated line, if any. If - * there is no such comment, returns NULL. - */ -CPPCommentBlock *CPPPreprocessor:: -get_comment_on(int line, CPPFile file) { - CPPComments::reverse_iterator ci; - ci = _comments.rbegin(); - - while (ci != _comments.rend()) { - CPPCommentBlock *comment = (*ci); - if (comment->_file == file) { - if (comment->_line_number == line) { - return comment; - } else if (comment->_line_number < line) { - return nullptr; - } - } - - ++ci; - } - - return nullptr; -} - -/** - * - */ -bool CPPPreprocessor:: -init_cpp(const CPPFile &file) { - _state = S_normal; - _saved_tokens.push_back(CPPToken(START_CPP)); - _last_c = '\0'; - - return push_file(file); -} - -/** - * - */ -bool CPPPreprocessor:: -init_const_expr(const string &expr) { - _state = S_normal; - _saved_tokens.push_back(CPPToken(START_CONST_EXPR)); - - return push_string(expr); -} - -/** - * - */ -bool CPPPreprocessor:: -init_type(const string &type) { - _state = S_normal; - _saved_tokens.push_back(CPPToken(START_TYPE)); - - return push_string(type); -} - -/** - * - */ -bool CPPPreprocessor:: -push_file(const CPPFile &file) { - if (_verbose >= 3) { - indent(cerr, get_file_depth() * 2) - << "Reading " << file << "\n"; - } - assert(_last_c == 0); - - InputFile *infile = new InputFile; - if (infile->open(file)) { - infile->_parent = _infile; - _infile = infile; - - // Record the fact that we opened the file for the benefit of user code. - _parsed_files.insert(file); - - infile->_prev_last_c = _last_c; - _last_c = '\0'; - _start_of_line = true; - return true; - } - - delete infile; - return false; -} - -/** - * - */ -bool CPPPreprocessor:: -push_string(const string &input) { -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Pushing to string \"" << input - << "\"\n"; -#endif - - InputFile *infile = new InputFile; - if (infile->connect_input(input)) { - infile->_prev_last_c = _last_c; - infile->_parent = _infile; - _infile = infile; - _last_c = '\0'; - return true; - } - -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Unable to read string\n"; -#endif - - delete infile; - return false; -} - -/** - * - */ -bool CPPPreprocessor:: -push_expansion(const string &input, const CPPManifest *manifest, const YYLTYPE &loc) { -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Pushing to expansion \"" << input - << "\"\n"; -#endif - - InputFile *infile = new InputFile; - if (infile->connect_input(input)) { - infile->_manifest = manifest; - infile->_file = loc.file; - infile->_line_number = loc.first_line; - infile->_col_number = loc.first_column; - infile->_lock_position = true; - - if (!manifest->_has_parameters) { - // If the manifest does not use arguments, then disallow recursive - // expansion. - infile->_ignore_manifest = true; - } - - infile->_prev_last_c = _last_c; - infile->_parent = _infile; - _infile = infile; - _last_c = '\0'; - return true; - } - -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Unable to read expansion\n"; -#endif - - delete infile; - return false; -} - -/** - * Given a string, expand all manifests within the string. - */ -void CPPPreprocessor:: -expand_manifests(string &expr, bool expand_undefined, - const CPPManifest::Ignores &ignores) const { - size_t p = 0; - while (p < expr.size()) { - if (isalpha(expr[p]) || expr[p] == '_') { - size_t q = p; - while (p < expr.size() && (isalnum(expr[p]) || expr[p] == '_')) { - p++; - } - string ident = expr.substr(q, p - q); - - // Here's an identifier. Is it "defined"? - if (ident == "defined") { - expand_defined_function(expr, q, p); - } - else if (expand_undefined && ident == "__has_include") { - expand_has_include_function(expr, q, p); - } - else if (ident == "L" && p < expr.size() && (expr[p] == '\'' || expr[p] == '\"')) { - // Special exception for the wide string literal suffix, which is - // never expanded. - } - else { - // Is it a manifest? - Manifests::const_iterator mi = _manifests.find(ident); - if (mi != _manifests.end() && ignores.count((*mi).second) == 0) { - const CPPManifest *manifest = (*mi).second; - vector_string args; - if (manifest->_has_parameters) { - // If it's not followed by a parenthesis, don't expand it. - while (p < expr.size() && isspace(expr[p])) { - p++; - } - if (p >= expr.size() || expr[p] != '(') { - continue; - } - - manifest->extract_args(args, expr, p); - } - - // Don't consider this manifest when expanding the arguments or - // result, to prevent recursion. - CPPManifest::Ignores nested_ignores(ignores); - nested_ignores.insert(manifest); - - string result = manifest->expand(args, expand_undefined, nested_ignores); - expand_manifests(result, expand_undefined, nested_ignores); - - expr = expr.substr(0, q) + result + expr.substr(p); - p = q + result.size(); - } - else if (ident == "__FILE__") { - // Special case: this is a dynamic definition. - CPPFile file = get_file(); - string result = string("\"") + file._filename_as_referenced.get_fullpath() + "\""; - expr = expr.substr(0, q) + result + expr.substr(p); - p = q + result.size(); - - } - else if (ident == "__LINE__") { - // So is this. - string line = format_string(get_line_number()); - expr = expr.substr(0, q) + line + expr.substr(p); - p = q + line.size(); - } - else if (expand_undefined && ident != "true" && ident != "false") { - // It is not found. Expand it to 0, but only if we are currently - // parsing an #if expression. - expr = expr.substr(0, q) + "0" + expr.substr(p); - p = q + 1; - } - } - } - else if (expr[p] == '\'' || expr[p] == '"') { - // Skip the next part until we find a closing quotation mark. - char quote = expr[p]; - p++; - while (p < expr.size() && expr[p] != quote) { - if (expr[p] == '\\') { - // This might be an escaped quote. Skip an extra char. - p++; - } - p++; - } - if (p >= expr.size()) { - // Unclosed string. - warning("missing terminating " + string(1, quote) + " character"); - } - p++; - } - else { - p++; - } - } -} - -/** - * Given a string, expand all manifests within the string and evaluate it as - * an expression. Returns NULL if the string is not a valid expression. - * - * This is an internal support function for CPPPreprocessor; however, there is - * a public variant of this function defined for CPPParser. - */ -CPPExpression *CPPPreprocessor:: -parse_expr(const string &input_expr, CPPScope *current_scope, - CPPScope *global_scope, const YYLTYPE &loc) { - string expr = input_expr; - expand_manifests(expr, false); - - CPPExpressionParser ep(current_scope, global_scope); - ep._verbose = 0; - if (ep.parse_expr(expr, *this)) { - return ep._expr; - } else { - return nullptr; - } -} - -/** - * - */ -CPPToken CPPPreprocessor:: -internal_get_next_token() { - if (_state == S_eof || _state == S_end_nested) { - return CPPToken::eof(); - } - - int c = _last_c; - _last_c = '\0'; - if (c == '\0' || c == EOF) { - c = get(); - } - - // Skip any whitespace, comments, and preprocessor directives before the - // token. - c = skip_whitespace(c); - while (c == '#' && _start_of_line && !should_ignore_preprocessor()) { - c = skip_whitespace(process_directive(c)); - } - - if (c == '\'') { - return get_quoted_char(c); - } else if (c == '"') { - return get_quoted_string(c); - } else if (isalpha(c) || c == '_') { - return get_identifier(c); - } else if (isdigit(c)) { - return get_number(c); - } - - if (c == EOF) { - _state = S_eof; - return CPPToken::eof(); - } - - // Check for a number beginning with a decimal point. - int next_c = peek(); - if (c == '.' && isdigit(next_c)) { - return get_number(c); - } - - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - loc.last_line = loc.first_line; - loc.last_column = loc.first_column; - - // Check for two- or three-character tokens. - int di = check_digraph(c); - if (di != 0) { - c = di; - ++loc.last_column; - get(); - - int tri = check_trigraph(di); - if (tri != 0) { - ++loc.last_column; - get(); - return CPPToken(tri, loc); - } - return CPPToken(di, loc); - } - - if (_state == S_nested) { - // If we're running a nested lexer, keep track of the paren levels. When - // we encounter a comma or closing angle bracket at the bottom level, we - // stop. - - switch (c) { - case '(': - case '[': - _paren_nesting++; - break; - - case ')': - case ']': - _paren_nesting--; - break; - - case ',': - if (_paren_nesting <= 0) { - _state = S_end_nested; - return CPPToken(0, loc); - } - break; - - case '>': - if (_paren_nesting <= 0) { - _parsing_template_params = false; - _state = S_end_nested; - return CPPToken(0, loc); - } - } - } else if (_parsing_attribute) { - // If we're parsing an attribute, also keep track of the paren nesting. - if (c == '[' || c == '(') { - ++_paren_nesting; - } else if (c == ']' || c == ')') { - --_paren_nesting; - } - } - - // Look for an end-of-line comment, and parse it before we finish this - // token. This is not strictly necessary, but it allows us to pick up - // docstrings from comments after enum values. - while (next_c != EOF && isspace(next_c)) { - get(); - next_c = peek(); - } - if (next_c == '/') { - _last_c = skip_whitespace(get()); - } - - return CPPToken(c, loc); -} - -/** - * Checks the next character in the stream to see if this might be a two- - * character token. Returns 0 if it is only a single-character token. - */ -int CPPPreprocessor:: -check_digraph(int c) { - int next_c = peek(); - switch (c) { - case '+': - if (next_c == '+') return PLUSPLUS; - if (next_c == '=') return PLUSEQUAL; - break; - - case '-': - if (next_c == '-') return MINUSMINUS; - if (next_c == '=') return MINUSEQUAL; - if (next_c == '>') return POINTSAT; - break; - - case '<': - if (next_c == '<') return LSHIFT; - if (next_c == '=') return LECOMPARE; - if (next_c == ':') return '['; - if (next_c == '%') return '{'; - break; - - case '>': - if (_parsing_template_params && _paren_nesting <= 0) { - // Don't parse >> as right-shift when parsing a template list, as per - // C++11, to allow a syntax like A>. However, nested >> must be - // preserved, such as in A<(2>>1)> - break; - } - if (next_c == '>') return RSHIFT; - if (next_c == '=') return GECOMPARE; - break; - - case '|': - if (next_c == '|') return OROR; - if (next_c == '=') return OREQUAL; - break; - - case '&': - if (next_c == '&') return ANDAND; - if (next_c == '=') return ANDEQUAL; - break; - - case '^': - if (next_c == '=') return XOREQUAL; - break; - - case '=': - if (next_c == '=') return EQCOMPARE; - break; - - case '!': - if (next_c == '=') return NECOMPARE; - break; - - case '.': - if (next_c == '*') return DOT_STAR; - if (next_c == '.') { - get(); - if (peek() == '.') { - return ELLIPSIS; - } else { - unget('.'); - } - } - break; - - case ':': - if (next_c == ':') return SCOPE; - if (next_c == '>') return ']'; - break; - - case '*': - if (next_c == '=') return TIMESEQUAL; - break; - - case '/': - if (next_c == '=') return DIVIDEEQUAL; - break; - - case '%': - if (next_c == '=') return MODEQUAL; - if (next_c == '>') return '}'; - break; - - case '[': - if (next_c == '[' && !_parsing_attribute) { - _parsing_attribute = true; - return ATTR_LEFT; - } - break; - - case ']': - if (next_c == ']' && _parsing_attribute && _paren_nesting == 0) { - _parsing_attribute = false; - return ATTR_RIGHT; - } - break; - } - - return 0; -} - -/** - * Checks the next character in the stream to see if this might be a three- - * character token; usually called in conjunction with check_digraph. Returns - * 0 if it is not a three-character token. - */ -int CPPPreprocessor:: -check_trigraph(int c) { - int next_c = peek(); - switch (c) { - case POINTSAT: - if (next_c == '*') return POINTSAT_STAR; - break; - - case LSHIFT: - if (next_c == '=') return LSHIFTEQUAL; - break; - - case RSHIFT: - if (next_c == '=') return RSHIFTEQUAL; - break; - - case LECOMPARE: - if (next_c == '>') return SPACESHIP; - break; - } - - return 0; -} - -/** - * - */ -int CPPPreprocessor:: -skip_whitespace(int c) { - while (c != EOF) { - c = skip_comment(c); - - if (c == '\\') { - // This does not usually occur in the middle of unquoted C++ code, - // except before a newline character. - if (peek() != '\n') { - return '\\'; - } - c = get(); - } - - if (!isspace(c)) { - return c; - } - c = get(); - } - return c; -} - -/** - * - */ -int CPPPreprocessor:: -skip_comment(int c) { - while (c == '/') { - int next_c = peek(); - if (next_c == '*') { - get(); - _last_cpp_comment = false; - c = skip_c_comment(get()); - } else if (next_c == '/') { - get(); - c = skip_cpp_comment(get()); - break; - } else { - _last_cpp_comment = false; - return c; - } - } - if (!isspace(c)) { - _last_cpp_comment = false; - } - return c; -} - -/** - * - */ -int CPPPreprocessor:: -skip_c_comment(int c) { - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number() - 2; - loc.last_line = 0; - loc.last_column = 0; - - if (_save_comments) { - CPPCommentBlock *comment = new CPPCommentBlock; - _comments.push_back(comment); - - comment->_file = loc.file; - comment->_line_number = loc.first_line; - comment->_last_line = loc.last_line; - comment->_col_number = loc.first_column; - comment->_c_style = true; - comment->_comment = "/*"; - - while (c != EOF) { - if (c == '*') { - comment->_comment += c; - c = get(); - if (c == '/') { - comment->_comment += c; - comment->_last_line = get_line_number(); - return get(); - } - } else { - comment->_comment += c; - c = get(); - } - } - - loc.last_line = get_line_number(); - comment->_last_line = loc.last_line; - - warning("Comment is unterminated", loc); - - } else { - CPPFile first_file = get_file(); - - while (c != EOF) { - if (c == '*') { - c = get(); - if (c == '/') { - return get(); - } - } else { - c = get(); - } - } - - loc.last_line = get_line_number(); - - warning("Comment is unterminated", loc); - } - - return c; -} - -/** - * - */ -int CPPPreprocessor:: -skip_cpp_comment(int c) { - if (_save_comments) { - CPPCommentBlock *comment; - - int line_number = get_line_number(); - if (c == '\n') { - // We have to subtract one from the line number as we just fetched a - // newline. - --line_number; - } - - if (_last_cpp_comment && !_comments.empty() && - _comments.back()->_last_line >= line_number - 1) { - // If the last non-whitespace character read was also part of a C++ - // comment, then this is just a continuation of that comment block. - // However, if there was a line without comment in between, it starts a - // new block anyway. - comment = _comments.back(); - assert(!comment->_c_style); - comment->_comment += "//"; - - } else { - // Otherwise, this begins a new comment block. - comment = new CPPCommentBlock; - - comment->_file = get_file(); - comment->_line_number = line_number; - comment->_last_line = line_number; - comment->_col_number = get_col_number() - 2; - comment->_c_style = false; - comment->_comment = "//"; - - _comments.push_back(comment); - } - - while (c != EOF && c != '\n') { - comment->_comment += c; - c = get(); - } - - comment->_comment += '\n'; - comment->_last_line = line_number; - - _last_cpp_comment = true; - - } else { - while (c != EOF && c != '\n') { - c = get(); - } - } - - return c; -} - -/** - * Skips a C++14 digit separator that has just been found through peek(). - */ -int CPPPreprocessor:: -skip_digit_separator(int c) { - if (c != '\'') { - return c; - } - - get(); - c = peek(); - - if (isdigit(c)) { - return c; - } - - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - loc.last_line = loc.first_line; - loc.last_column = loc.first_column; - - if (c != '\'') { - // This assumes that this isn't a character constant directly follows a - // digit sequence, like 123'a' -- I can't think of a situation where - // that's legal anyway, though. - error("digit separator cannot occur at end of digit sequence", loc); - return c; - } - - while (c == '\'') { - get(); - ++loc.last_column; - c = peek(); - } - error("adjacent digit separators", loc); - - return c; -} - -/** - * - */ -int CPPPreprocessor:: -process_directive(int c) { - assert(c == '#'); - c = skip_whitespace(get()); - - int begin_line = get_line_number(); - int begin_column = get_col_number(); - - string command, args; - c = get_preprocessor_command(c, command); - - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - - c = get_preprocessor_args(c, args); - - loc.last_line = get_line_number(); - loc.last_column = 0; - -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "#" << command << " " << args << "\n"; -#endif - - if (command == "define") { - handle_define_directive(args, loc); - } else if (command == "undef") { - handle_undef_directive(args, loc); - } else if (command == "ifdef") { - handle_ifdef_directive(args, loc); - } else if (command == "ifndef") { - handle_ifndef_directive(args, loc); - } else if (command == "if") { - handle_if_directive(args, loc); - } else if (command == "else" || command == "elif") { - // Presumably this follows some #if or #ifdef. We don't bother to check - // this, however. - skip_false_if_block(false); - } else if (command == "endif") { - // Presumably this follows some #if or #ifdef. We don't bother to check - // this, however. - } else if (command == "include") { - handle_include_directive(args, loc); - } else if (command == "pragma") { - handle_pragma_directive(args, loc); - } else if (command == "ident") { - // Quietly ignore idents. - } else if (command == "error") { - handle_error_directive(args, loc); - } else { - loc.first_line = begin_line; - loc.first_column = begin_column; - loc.last_line = begin_line; - loc.last_column = begin_column + command.size() - 1; - warning("Ignoring unknown directive #" + command, loc); - } - - _start_of_line = true; - return '\n'; -} - -/** - * - */ -int CPPPreprocessor:: -get_preprocessor_command(int c, string &command) { - // The next sequence of characters is the command. - while (c != EOF && (isalnum(c) || c == '_')) { - command += c; - c = get(); - } - - while (c != EOF && c != '\n' && isspace(c)) { - c = get(); - } - - return c; -} - -/** - * - */ -int CPPPreprocessor:: -get_preprocessor_args(int c, string &args) { - // Following the command, the rest of the line, as well as any text on - // successive lines, is part of the arguments to the command. - - // Check for comments first. - c = skip_comment(c); - - while (c != EOF && c != '\n') { - if (c == '\\') { - int next_c = get(); - if (next_c == '\n') { - // Here we have an escaped newline: a continuation. - args += '\n'; - } else { - // Just a backslash followed by some non-backslash, keep both. - args += c; - if (next_c != EOF) { - args += next_c; - } - } - } else { - args += c; - } - c = skip_comment(get()); - } - - // Remove any leading and trailing whitespace from the args. - args = trim_blanks(args); - - return c; -} - -/** - * - */ -void CPPPreprocessor:: -handle_define_directive(const string &args, const YYLTYPE &loc) { - if (args.empty()) { - warning("Ignoring empty #define directive", loc); - } else { - CPPManifest *manifest = new CPPManifest(*this, args, loc); - manifest->_vis = preprocessor_vis; - if (!manifest->_has_parameters) { - string expr_string = manifest->expand(); - if (!expr_string.empty()) { - manifest->_expr = parse_expr(expr_string, global_scope, global_scope, loc); - } - } - - std::pair result = - _manifests.insert(Manifests::value_type(manifest->_name, manifest)); - - if (!result.second) { - // There was already a macro with this name. Delete the old. - CPPManifest *other = result.first->second; - if (!manifest->is_equal(other)) { - warning("redefinition of macro '" + manifest->_name + "'", loc); - warning("previous definition is here", other->_loc); - } - result.first->second = manifest; - } - } -} - -/** - * - */ -void CPPPreprocessor:: -handle_undef_directive(const string &args, const YYLTYPE &loc) { - if (args.empty()) { - warning("Ignoring empty #undef directive", loc); - } else { - Manifests::iterator mi = _manifests.find(args); - if (mi != _manifests.end()) { - _manifests.erase(mi); - } - } -} - -/** - * - */ -void CPPPreprocessor:: -handle_ifdef_directive(const string &args, const YYLTYPE &loc) { - if (!is_manifest_defined(args)) { - // The macro is undefined. Skip stuff. - skip_false_if_block(true); - } -} - -/** - * - */ -void CPPPreprocessor:: -handle_ifndef_directive(const string &args, const YYLTYPE &loc) { - if (is_manifest_defined(args)) { - // The macro is defined. Skip stuff. - skip_false_if_block(true); - } -} - -/** - * - */ -void CPPPreprocessor:: -handle_if_directive(const string &args, const YYLTYPE &loc) { - // When expanding manifests, we should replace unknown macros with 0. - string expr = args; - expand_manifests(expr, true); - - int expression_result = 0; - CPPExpressionParser ep(current_scope, global_scope); - ep._verbose = 0; - if (ep.parse_expr(expr, *this)) { - CPPExpression::Result result = ep._expr->evaluate(); - if (result._type == CPPExpression::RT_error) { - std::ostringstream strm; - strm << *ep._expr; - warning("Ignoring invalid expression " + strm.str(), loc); - } else { - expression_result = result.as_integer(); - } - } else { - warning("Ignoring invalid expression " + args, loc); - } - - if (expression_result) { - // The expression result is true. We continue. - return; - } - - // The expression result is false. Skip stuff. - skip_false_if_block(true); -} - -/** - * - */ -void CPPPreprocessor:: -handle_include_directive(const string &args, const YYLTYPE &loc) { - Filename filename; - Filename filename_as_referenced; - bool angle_quotes = false; - - string expr = args; - - // The filename to include might actually be hidden within a manifest - // definition. Wow. FreeType depends on this. - - // Just to play things safe, since our manifest-expansion logic might not - // filter out quotes and angle brackets properly, we'll only expand - // manifests if we don't begin with a quote or bracket. - if (!expr.empty() && (expr[0] != '"' && expr[0] != '<')) { - expand_manifests(expr, false); - } - - if (!expr.empty()) { - if (expr[0] == '"' && expr[expr.size() - 1] == '"') { - filename = expr.substr(1, expr.size() - 2); - - if (_infile->_parent == nullptr) { - // If we're currently processing a top-level file, record the include - // directive. We don't need to record includes from included files. - _quote_includes.insert(filename); - } - } else if (expr[0] == '<' && expr[expr.size() - 1] == '>') { - filename = expr.substr(1, expr.size() - 2); - if (!_noangles) { - // If _noangles is true, we don't make a distinction between angle - // brackets and quote marks--all #include statements are treated the - // same, as if they used quote marks. - angle_quotes = true; - } - - if (_infile->_parent == nullptr) { - // If we're currently processing a top-level file, record the include - // directive. We don't need to record includes from included files. - _angle_includes.insert(filename); - } - } - } else { - warning("Ignoring invalid #include directive", loc); - } - - filename.set_text(); - filename_as_referenced = filename; - - // Now look for the filename. If we didn't use angle quotes, look first in - // the current directory. - CPPFile::Source source = CPPFile::S_none; - - if (find_include(filename, angle_quotes, source)) { - _last_c = '\0'; - - // If it was explicitly named on the command-line, mark it S_local. - filename.make_canonical(); - if (_explicit_files.count(filename)) { - source = CPPFile::S_local; - } - - CPPFile file(filename, filename_as_referenced, source); - - // Don't include it if we included it before and it had #pragma once. - ParsedFiles::const_iterator it = _parsed_files.find(file); - if (it != _parsed_files.end() && it->_pragma_once) { - return; - } - - if (!push_file(file)) { - warning("Unable to read " + filename.get_fullpath(), loc); - } - } else { - warning("Cannot find " + filename.get_fullpath(), loc); - } -} - -/** - * - */ -void CPPPreprocessor:: -handle_pragma_directive(const string &args, const YYLTYPE &loc) { - if (args == "once") { - ParsedFiles::iterator it = _parsed_files.find(loc.file); - assert(it != _parsed_files.end()); - it->_pragma_once = true; - } - - char macro[64]; - if (sscanf(args.c_str(), "push_macro ( \"%63[^\"]\" )", macro) == 1) { - // We just mark it as pushed for now, so that the next time someone tries - // to override it, we save the old value. - Manifests::iterator mi = _manifests.find(macro); - if (mi != _manifests.end()) { - _manifest_stack[macro].push_back(mi->second); - } else { - _manifest_stack[macro].push_back(nullptr); - } - - } else if (sscanf(args.c_str(), "pop_macro ( \"%63[^\"]\" )", macro) == 1) { - ManifestStack &stack = _manifest_stack[macro]; - if (stack.size() > 0) { - CPPManifest *manifest = stack.back(); - stack.pop_back(); - Manifests::iterator mi = _manifests.find(macro); - if (manifest == nullptr) { - // It was undefined when it was pushed, so make it undefined again. - if (mi != _manifests.end()) { - _manifests.erase(mi); - } - } else if (mi != _manifests.end()) { - mi->second = manifest; - } else { - _manifests.insert(Manifests::value_type(macro, manifest)); - } - } else { - warning("pop_macro without matching push_macro", loc); - } - } -} - -/** - * - */ -void CPPPreprocessor:: -handle_error_directive(const string &args, const YYLTYPE &loc) { - error(args, loc); -} - -/** - * We come here when we fail an #if or an #ifdef test, or when we reach the - * #else clause to something we didn't fail. This function skips all text up - * until the matching #endif. - */ -void CPPPreprocessor:: -skip_false_if_block(bool consider_elifs) { - int level = 0; - _save_comments = false; - - int c = skip_comment(get()); - while (c != EOF) { - if (c == '#' && _start_of_line) { - c = skip_whitespace(get()); - - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - loc.last_line = loc.first_line; - loc.last_column = loc.first_column; - - // Is this it? - string command, args; - c = get_preprocessor_command(c, command); - c = get_preprocessor_args(c, args); - if (command == "if" || command == "ifdef" || command == "ifndef") { - // Hmm, a nested if block. Even more to skip. - level++; - } else if (command == "else") { - if (level == 0 && consider_elifs) { - // This will do! - _save_comments = true; - return; - } - } else if (command == "elif") { - if (level == 0 && consider_elifs) { - // If we pass this test, we're in. - _save_comments = true; - handle_if_directive(args, loc); - return; - } - } else if (command == "endif") { - // Skip any args. - if (level == 0) { - // Here's the end! - _save_comments = true; - return; - } - level--; - } - } else { - c = skip_comment(get()); - } - } - - _save_comments = true; -} - -/** - * Returns true if the given manifest is defined. - */ -bool CPPPreprocessor:: -is_manifest_defined(const string &manifest_name) const { - Manifests::const_iterator mi = _manifests.find(manifest_name); - if (mi != _manifests.end()) { - return true; - } - - if (manifest_name == "__has_include" || - manifest_name == "__FILE__" || - manifest_name == "__LINE__") { - // Special built-in directives that are considered "defined". - return true; - } - - return false; -} - -/** - * Locates the given filename. Changes the first argument to the full path. - */ -bool CPPPreprocessor:: -find_include(Filename &filename, bool angle_quotes, CPPFile::Source &source) const { - // Now look for the filename. If we didn't use angle quotes, look first in - // the current directory. - if (!angle_quotes && filename.exists()) { - source = CPPFile::S_local; - return true; - } - - // Search the same directory as the includer. - if (!angle_quotes) { - Filename match(get_file()._filename.get_dirname(), filename); - if (match.exists()) { - filename = match; - source = CPPFile::S_alternate; - return true; - } - } - - // Now search the angle-include-path - if (angle_quotes && filename.resolve_filename(_angle_include_path)) { - source = CPPFile::S_system; - return true; - } - - // Now search the quote-include-path - if (!angle_quotes) { - for (size_t dir = 0; dir < _quote_include_path.get_num_directories(); ++dir) { - Filename match(_quote_include_path.get_directory(dir), filename); - if (match.exists()) { - filename = match; - source = _quote_include_kind[dir]; - return true; - } - } - } - - return false; -} - -/** - * - */ -CPPToken CPPPreprocessor:: -get_quoted_char(int c) { - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - - string str = scan_quoted(c); - YYSTYPE result; - if (!str.empty()) { - result.u.integer = (int)str[0]; - } else { - result.u.integer = 0; - } - - return get_literal(CHAR_TOK, loc, str, result); -} - -/** - * - */ -CPPToken CPPPreprocessor:: -get_quoted_string(int c) { - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - - string str = scan_quoted(c); - - return get_literal(SIMPLE_STRING, loc, str); -} - -/** - * - */ -CPPToken CPPPreprocessor:: -get_identifier(int c) { - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - loc.last_line = loc.first_line; - loc.last_column = loc.first_column; - - string name(1, (char)c); - - c = peek(); - while (c != EOF && (isalnum(c) || c == '_')) { - name += get(); - c = peek(); - } - - loc.last_line = get_line_number(); - loc.last_column = get_col_number(); - - if ((c == '\'' || c == '"') && - (name == "L" || name == "u8" || name == "u" || name == "U" || - name == "R" || name == "LR" || name == "u8R" || name == "uR" || name == "UR")) { - // This is actually a wide-character or wide-string literal or some such. - get(); - string str; - if (name[name.size() - 1] == 'R') { - name.resize(name.size() - 1); - str = scan_raw(c); - } else { - str = scan_quoted(c); - } - - // Figure out the correct character type to use. - CPPExpression::Type type; - if (name == "L") { - type = CPPExpression::T_wstring; - } else if (name == "u8") { - type = CPPExpression::T_u8string; - } else if (name == "u") { - type = CPPExpression::T_u16string; - } else if (name == "U") { - type = CPPExpression::T_u32string; - } else { - type = CPPExpression::T_string; - } - - loc.last_line = get_line_number(); - loc.last_column = get_col_number(); - - YYSTYPE result; - if (c == '\'') { - // We don't really care about the type for now. - if (!str.empty()) { - result.u.integer = (int)str[0]; - } else { - result.u.integer = 0; - } - return get_literal(CHAR_TOK, loc, str, result); - } else { - result.u.expr = new CPPExpression(str); - result.u.expr->_type = type; - return get_literal(STRING_LITERAL, loc, str, result); - } - } - - _last_c = 0; - - // Is it a manifest? - Manifests::const_iterator mi = _manifests.find(name); - if (mi != _manifests.end() && !should_ignore_manifest((*mi).second)) { - // If the manifest is expecting arguments, we don't expand it unless the - // the next token is an open-parenthesis. - CPPManifest *manifest = (*mi).second; - if (manifest->_has_parameters) { - while (c != EOF && isspace(c)) { - get(); - c = peek(); - } - if (c == '(') { - // It is followed by a parenthesis, so we can expand this. - return expand_manifest(manifest, loc); - } - } else { - // Non-function-like macros are always expanded. - return expand_manifest(manifest, loc); - } - } - if (name == "__FILE__") { - return get_literal(SIMPLE_STRING, loc, loc.file._filename_as_referenced); - } - if (name == "__LINE__") { - YYSTYPE result; - result.u.integer = loc.first_line; - return CPPToken(INTEGER, loc, "", result); - } - - // Check for keywords. - auto kwit = keywords.find(name); - int kw = (kwit != keywords.end()) ? (*kwit).second : 0; - - // Update our internal visibility flag. - switch (kw) { - case KW_BEGIN_PUBLISH: - preprocessor_vis = V_published; - break; - - case KW_END_PUBLISH: - preprocessor_vis = V_public; - break; - } - - if (kw != 0) { - if (kw == KW_EXPLICIT || kw == KW_NOEXCEPT) { - // These can be followed by a left-paren. Doing this helps to avoid - // shift/reduce conflicts in the parser. - while (c != EOF && isspace(c)) { - get(); - c = peek(); - } - if (c == '(') { - if (kw == KW_EXPLICIT) { - kw = KW_EXPLICIT_LPAREN; - } - else if (kw == KW_NOEXCEPT) { - kw = KW_NOEXCEPT_LPAREN; - } - get(); - } - } - - YYSTYPE result; - result.u.identifier = nullptr; - return CPPToken(kw, loc, name, result); - } - - return CPPToken(SIMPLE_IDENTIFIER, loc, name); -} - -/** - * Under the assumption that we've just parsed a string or real constant, - * parse a following custom literal, and returns a token for it. - */ -CPPToken CPPPreprocessor:: -get_literal(int token, YYLTYPE loc, const string &str, const YYSTYPE &value) { - string suffix; - - int c = peek(); - if (isalpha(c) || c == '_') { - // A literal seems to be following directly. - while (c != EOF && (isalnum(c) || c == '_')) { - suffix += get(); - c = peek(); - } - } - loc.last_line = get_line_number(); - loc.last_column = get_col_number(); - - if (suffix.empty()) { - // There is no suffix. - return CPPToken(token, loc, str, value); - } - - // Handle built-in literal suffixes. - if (token == INTEGER) { - if (cmp_nocase(suffix, "u") == 0 || - cmp_nocase(suffix, "l") == 0 || - cmp_nocase(suffix, "ul") == 0 || cmp_nocase(suffix, "lu") == 0 || - cmp_nocase(suffix, "ll") == 0 || - cmp_nocase(suffix, "ull") == 0 || cmp_nocase(suffix, "llu") == 0) { - // These are built-in integer suffixes. Right now, we don't try to - // distinguish between them. - return CPPToken(INTEGER, loc, str, value); - } - } else if (token == REAL) { - if (suffix == "f" || suffix == "F" || - suffix == "l" || suffix == "L") { - return CPPToken(REAL, loc, str, value); - } - } - - // Find the literal operator for this literal. - CPPIdentifier *ident = new CPPIdentifier("operator \"\" " + suffix); - CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope, this); - - if (decl == nullptr) { - // Special case to handle C code, which allows a macro to directly follow - // a string, like "str"SUFFIX. In this case, it becomes a separate token. - Manifests::const_iterator mi = _manifests.find(suffix); - if (mi != _manifests.end() && !should_ignore_manifest((*mi).second)) { - CPPManifest *manifest = (*mi).second; - _saved_tokens.push_back(expand_manifest(manifest, loc)); - return CPPToken(token, loc, str, value); - } - } - - if (decl == nullptr || decl->get_subtype() != CPPDeclaration::ST_function_group) { - error("unknown literal suffix " + suffix, loc); - return CPPToken(token, loc, str, value); - } - - // Find the overload with the appropriate signature. - CPPExpression *expr = nullptr; - CPPInstance *instance = nullptr; - CPPInstance *raw_instance = nullptr; - CPPFunctionGroup *fgroup = decl->as_function_group(); - CPPFunctionGroup::Instances::iterator it; - for (it = fgroup->_instances.begin(); it != fgroup->_instances.end(); ++it) { - if ((*it)->_type == nullptr) { - continue; - } - - CPPFunctionType *ftype = (*it)->_type->as_function_type(); - if (ftype == nullptr || ftype->_parameters == nullptr) { - continue; - } - - CPPParameterList::Parameters ¶ms = ftype->_parameters->_parameters; - if (token == STRING_LITERAL || token == SIMPLE_STRING) { - // A custom string literal must take a second size_t argument. - if (params.size() != 2) continue; - } else { - if (params.size() != 1) continue; - } - - CPPInstance *param = params[0]; - if (param == nullptr || param->_type == nullptr) { - continue; - } - - CPPType *type = param->_type; - while (type->get_subtype() == CPPDeclaration::ST_const) { - type = type->as_const_type()->_wrapped_around; - } - if (type->get_subtype() == CPPDeclaration::ST_simple) { - // It's a primitive type. Check that it matches the appropriate token. - CPPSimpleType::Type simple = type->as_simple_type()->_type; - - if (token == INTEGER && simple == CPPSimpleType::T_int) { - expr = new CPPExpression(value.u.integer); - instance = (*it); - break; - } else if (token == REAL && simple == CPPSimpleType::T_double) { - expr = new CPPExpression(value.u.real); - instance = (*it); - break; - } else if (token == CHAR_TOK && (simple == CPPSimpleType::T_char || - simple == CPPSimpleType::T_wchar_t || - simple == CPPSimpleType::T_char8_t || - simple == CPPSimpleType::T_char16_t || - simple == CPPSimpleType::T_char32_t)) { - // We currently don't have the means to check the exact character - // type. - expr = new CPPExpression(value.u.integer); - instance = (*it); - break; - } - - } else if (type->get_subtype() == CPPDeclaration::ST_pointer) { - // Must be a const pointer. Unwrap it. - type = type->as_pointer_type()->_pointing_at; - if (type == nullptr || type->get_subtype() != CPPDeclaration::ST_const) { - continue; - } - type = type->as_const_type()->_wrapped_around; - if (type == nullptr || type->get_subtype() != CPPDeclaration::ST_simple) { - continue; - } - - CPPSimpleType::Type simple = type->as_simple_type()->_type; - if (simple == CPPSimpleType::T_char && params.size() == 1) { - // This is the raw literal operator. Store it, but don't break; a - // non-raw version of the operator might follow, which we'd prefer. - raw_instance = (*it); - - } else if (token == SIMPLE_STRING && simple == CPPSimpleType::T_char) { - expr = new CPPExpression(str); - instance = (*it); - break; - - } else if (token == STRING_LITERAL) { - // Verify that the character type of the string literal matches the - // character type of the parameter. - CPPExpression::Type str_type = value.u.expr->_type; - if ((str_type == CPPExpression::T_string && simple == CPPSimpleType::T_char) || - (str_type == CPPExpression::T_wstring && simple == CPPSimpleType::T_wchar_t) || - (str_type == CPPExpression::T_u8string && (simple == CPPSimpleType::T_char || simple == CPPSimpleType::T_char8_t)) || - (str_type == CPPExpression::T_u16string && simple == CPPSimpleType::T_char16_t) || - (str_type == CPPExpression::T_u32string && simple == CPPSimpleType::T_char32_t)) { - expr = value.u.expr; - instance = (*it); - break; - } - } - } - } - - YYSTYPE result; - if (instance != nullptr) { - result.u.expr = new CPPExpression(CPPExpression::literal(expr, instance)); - return CPPToken(CUSTOM_LITERAL, loc, str, result); - } - - if ((token == REAL || token == INTEGER) && raw_instance != nullptr) { - // For numeric constants, we can fall back to a raw literal operator. - result.u.expr = new CPPExpression(CPPExpression::raw_literal(str, instance)); - return CPPToken(CUSTOM_LITERAL, loc, str, result); - } - - error(fgroup->_name + " has no suitable overload for literal of this type", loc); - result.u.expr = nullptr; - return CPPToken(CUSTOM_LITERAL, loc, str, result); -} - -/** - * - */ -CPPToken CPPPreprocessor:: -expand_manifest(const CPPManifest *manifest, const YYLTYPE &loc) { - vector_string args; - - if (manifest->_has_parameters) { - // Hmm, we're expecting arguments. - extract_manifest_args(manifest->_name, manifest->_num_parameters, - manifest->_variadic_param, args); - } - - // Keep track of the manifests we're supposed to ignore. - CPPManifest::Ignores ignores; - ignores.insert(manifest); - - InputFile *infile = _infile; - while (infile != nullptr) { - if (infile->_ignore_manifest) { - ignores.insert(infile->_manifest); - } - infile = infile->_parent; - } - - string expanded = " " + manifest->expand(args, false, ignores) + " "; - push_expansion(expanded, manifest, loc); - -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Expanding " << manifest->_name << " to " << expanded << "\n"; -#endif - - return internal_get_next_token(); -} - -/** - * - */ -void CPPPreprocessor:: -extract_manifest_args(const string &name, int num_args, int va_arg, - vector_string &args) { - CPPFile first_file = get_file(); - int first_line = get_line_number(); - int first_col = get_col_number(); - - // Skip whitespace till paren. - int c = _last_c; - _last_c = '\0'; - if (c == 0) { - c = get(); - } - while (c != EOF && isspace(c)) { - c = get(); - } - - if (c != '(') { - // No paren, so we have only one arg. - string arg; - while (c != EOF && (isalnum(c) || c == '_')) { - arg += c; - c = get(); - } - args.push_back(arg); - - } else { - // Skip paren. - c = skip_whitespace(get()); - int paren_level = 1; - string arg; - while (c != EOF) { - if (c == ',' && paren_level == 1) { - args.push_back(trim_blanks(arg)); - arg = ""; - c = get(); - - } else if (c == '"' || c == '\'') { - // Quoted string or character. - int quote_mark = c; - arg += c; - c = get(); - while (c != EOF && c != quote_mark && c != '\n') { - if (c == '\\') { - arg += c; - c = get(); - } - if (c != EOF) { - arg += c; - c = get(); - } - } - arg += c; - c = get(); - - } else if (c == '(') { - arg += '('; - ++paren_level; - c = get(); - - } else if (c == ')') { - --paren_level; - if (paren_level == 0) { - break; - } - arg += ')'; - c = get(); - - } else if (isspace(c)) { - // Skip extra whitespace. - c = skip_whitespace(c); - if (!arg.empty()) { - arg += ' '; - } - - } else if (c == '\\') { - // It could be a slash before a newline. If so, that's whitespace as - // well. - c = get(); - if (c != '\n') { - arg += '\\'; - } else if (!arg.empty()) { - arg += ' '; - c = skip_whitespace(get()); - } - - } else { - arg += c; - c = get(); - } - } - if (num_args != 0 || !arg.empty()) { - args.push_back(trim_blanks(arg)); - } - } - - YYLTYPE loc; - loc.first_line = first_line; - loc.first_column = first_col; - loc.last_line = first_line; - loc.last_column = first_col; - loc.file = first_file; - - if ((int)args.size() < num_args - (va_arg >= 0)) { - warning("Not enough arguments for manifest " + name, loc); - - } else if (va_arg < 0 && (int)args.size() > num_args) { - warning("Too many arguments for manifest " + name, loc); - } -} - -/** - * Expands the defined(manifest) function to either 1 or 0, depending on - * whether the manifest exists. - */ -void CPPPreprocessor:: -expand_defined_function(string &expr, size_t q, size_t &p) const { - while (p < expr.size() && isspace(expr[p])) { - p++; - } - - bool has_paren = false; - if (expr[p] == '(') { - has_paren = true; - p++; - } - - size_t r = p; - while (p < expr.size() && (isalnum(expr[p]) || expr[p] == '_')) { - p++; - } - string name = expr.substr(r, p - r); - - if (has_paren) { - if (expr[p] == ')') { - p++; - } else { - error("missing ')' after 'defined'"); - } - } - - char result = is_manifest_defined(name) ? '1' : '0'; - expr = expr.substr(0, q) + result + expr.substr(p); - p = q + 1; -} - -/** - * Expands the __has_include(manifest) function to either 1 or 0, depending on - * whether the include file exists. - */ -void CPPPreprocessor:: -expand_has_include_function(string &expr, size_t q, size_t &p) const { - bool found_file = false; - - // Skip whitespace till paren. - while (p < expr.size() && isspace(expr[p])) { - p++; - } - - if (expr[p] != '(') { - error("expected '(' after '__has_include'"); - return; - } - p++; - while (p < expr.size() && isspace(expr[p])) { - p++; - } - - int paren_level = 1; - bool needs_expansion = false; - size_t r = p; - while (p < expr.size()) { - if (expr[p] == '"' || expr[p] == '\'' || expr[p] == '<') { - // Quoted string or angle bracket. - int quote_mark = expr[p]; - if (quote_mark == '<') { - quote_mark = '>'; - } - p++; - while (p < expr.size() && expr[p] != quote_mark && expr[p] != '\n') { - if (expr[p] == '\\') { - p++; - } - if (p < expr.size()) { - p++; - } - } - } - else if (expr[p] == '(') { - ++paren_level; - } - else if (expr[p] == ')') { - --paren_level; - if (paren_level == 0) { - break; - } - } - else if (isalnum(expr[p]) || expr[p] == '_') { - needs_expansion = true; - } - p++; - } - - if (p >= expr.size() || expr[p] != ')') { - error("missing ')' after '__has_include'"); - return; - } - - // Back up to strip trailing whitespace. - size_t t = p; - while (t > r && isspace(expr[t - 1])) { - --t; - } - string inc = expr.substr(r, t - r); - p++; - - // Only expand if we've encountered unquoted identifier-valid characters, - // to be on the safe side. - if (needs_expansion) { - expand_manifests(inc, false); - } - - Filename filename; - bool angle_quotes = false; - - if (!inc.empty() && inc[0] == '"' && inc[inc.size() - 1] == '"') { - filename = inc.substr(1, inc.size() - 2); - } - else if (!inc.empty() && inc[0] == '<' && inc[inc.size() - 1] == '>') { - filename = inc.substr(1, inc.size() - 2); - if (!_noangles) { - // If _noangles is true, we don't make a distinction between angle - // brackets and quote marks--all #inc statements are treated the - // same, as if they used quote marks. - angle_quotes = true; - } - } - else { - warning("invalid argument for __has_include() directive: " + inc); - expr = expr.substr(0, q) + "0" + expr.substr(p); - p = q + 1; - return; - } - - filename.set_text(); - - CPPFile::Source source = CPPFile::S_none; - found_file = find_include(filename, angle_quotes, source); - - string result = found_file ? "1" : "0"; - expr = expr.substr(0, q) + result + expr.substr(p); - p = q + result.size(); -} - -/** - * Assuming that we've just read a digit or a period indicating the start of a - * number, read the rest. - */ -CPPToken CPPPreprocessor:: -get_number(int c) { - YYLTYPE loc; - loc.file = get_file(); - loc.first_line = get_line_number(); - loc.first_column = get_col_number(); - loc.last_line = loc.first_line; - loc.last_column = loc.first_column; - - string num(1, (char)c); - bool leading_zero = (c == '0'); - bool decimal_point = (c == '.'); - - c = skip_digit_separator(peek()); - - if (leading_zero && (c == 'x' || c == 'X')) { - // Here we have a hex number. - num += get(); - c = peek(); - - while (c != EOF && (isdigit(c) || (tolower(c) >= 'a' && tolower(c) <= 'f'))) { - num += get(); - c = skip_digit_separator(peek()); - } - - loc.last_line = get_line_number(); - loc.last_column = get_col_number(); - - YYSTYPE result; - result.u.integer = strtol(num.c_str(), nullptr, 16); - - return get_literal(INTEGER, loc, num, result); - - } else if (leading_zero && (c == 'b' || c == 'B')) { - // A C++14-style binary number. - get(); - c = peek(); - string bin(1, (char)c); - - while (c != EOF && (c == '0' || c == '1')) { - bin += get(); - c = skip_digit_separator(peek()); - } - - loc.last_line = get_line_number(); - loc.last_column = get_col_number(); - - YYSTYPE result; - result.u.integer = strtol(bin.c_str(), nullptr, 2); - - return get_literal(INTEGER, loc, bin, result); - } - - while (c != EOF && isdigit(c)) { - num += get(); - c = skip_digit_separator(peek()); - } - - if (c == '.' && !decimal_point) { - // Now we have a floating-point number. - decimal_point = true; - num += get(); - c = peek(); - - while (c != EOF && isdigit(c)) { - num += get(); - c = peek(); - } - } - - if (decimal_point || c == 'e' || c == 'E') { - if (tolower(c) == 'e') { - // An exponent is allowed. - num += get(); - c = peek(); - if (c == '-' || c == '+') { - num += get(); - c = peek(); - } - while (c != EOF && isdigit(c)) { - num += get(); - c = skip_digit_separator(peek()); - } - } - - loc.last_line = get_line_number(); - loc.last_column = get_col_number(); - - YYSTYPE result; - result.u.real = (long double)pstrtod(num.c_str(), nullptr); - - return get_literal(REAL, loc, num, result); - } - - // This is a decimal or octal integer number. - - loc.last_line = get_line_number(); - loc.last_column = get_col_number(); - - YYSTYPE result; - - if (leading_zero) { - // A leading zero implies an octal number. strtol() is supposed to be - // able to make this distinction by itself, but we'll do it explicitly - // just to be sure. - result.u.integer = strtol(num.c_str(), nullptr, 8); - - } else { - // A decimal (base 10) integer. - result.u.integer = strtol(num.c_str(), nullptr, 10); - } - - return get_literal(INTEGER, loc, num, result); -} - -/** - * - */ -int CPPPreprocessor:: -scan_escape_sequence(int c) { - if (c != '\\') { - return c; - } - - c = get(); - switch (c) { - case 'a': - return '\a'; - - case 'b': - return '\b'; - - case 'f': - return '\f'; - - case 'n': - return '\n'; - - case 'r': - return '\r'; - - case 't': - return '\t'; - - case 'v': - return '\v'; - - case 'e': - // \e is non-standard, but GCC supports it. - return '\x1B'; - - case 'x': - // hex character. - c = get(); - if (isxdigit(c)) { - int val = hex_val(c); - if (isxdigit(peek())) { - val = (val << 4) | hex_val(get()); - } - return val; - } - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - // Octal character. - { - int val = (c - '0'); - c = peek(); - if (c >= '0' && c <= '7') { - val = (val << 3) | (get() - '0'); - c = peek(); - if (c >= '0' && c <= '7') { - val = (val << 3) | (get() - '0'); - } - } - return val; - } - } - - // Simply output the following character. - return c; -} - -/** - * - */ -string CPPPreprocessor:: -scan_quoted(int c) { - int quote_mark = c; - - string str; - c = get(); - while (c != EOF && c != '\n' && c != quote_mark) { - if (c == '\\') { - // Backslash means a special character follows. - c = scan_escape_sequence(c); - } - - str += c; - c = get(); - } - - if (c != quote_mark) { - warning("Unclosed string"); - } - return str; -} - -/** - * Parses a C++11 raw string. - */ -string CPPPreprocessor:: -scan_raw(int c) { - int quote_mark = c; - - string delimiter = ")"; - - string str; - c = get(); - while (c != EOF && c != '(') { - delimiter += c; - c = get(); - } - - // OK, now start parsing the string, until we see the delimiter again. - c = get(); - while (c != EOF) { - if (c == quote_mark) { - // We encountered a quote mark - did the last part of the string end - // with the given delimiter? If so, we've reached the end. - if (str.compare(str.size() - delimiter.size(), delimiter.size(), delimiter) == 0) { - str.resize(str.size() - delimiter.size()); - break; - } - } - str += c; - c = get(); - } - - if (c != quote_mark) { - warning("Unclosed string"); - } - return str; -} - -/** - * Returns true if the manifest is one that is being ignored right now - * (presumably because we are presently expanding it). - */ -bool CPPPreprocessor:: -should_ignore_manifest(const CPPManifest *manifest) const { - InputFile *infile = _infile; - while (infile != nullptr) { - if (infile->_ignore_manifest && infile->_manifest == manifest) { - return true; - } - infile = infile->_parent; - } - - return false; -} - -/** - * Returns true if we should ignore any preprocessor directives (e.g. we're - * presently expanding a manifest). - */ -bool CPPPreprocessor:: -should_ignore_preprocessor() const { - InputFile *infile = _infile; - while (infile != nullptr) { - if (infile->_ignore_manifest) { - return true; - } - infile = infile->_parent; - } - - return false; -} - -/** - * - */ -int CPPPreprocessor:: -get() { - if (_unget != '\0') { - int c = _unget; - _unget = '\0'; - return c; - } - - if (UNLIKELY(_infile == nullptr)) { - return EOF; - } - - int c = _infile->get(); - - while (UNLIKELY(c == EOF && _infile != nullptr)) { -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "End of input stream, restoring to previous input\n"; -#endif - // Pop the last file off the end. - InputFile *infile = _infile; - _infile = infile->_parent; - delete infile; - - // Synthesize a newline, just in case the file doesn't already end with - // one. - c = '\n'; - } - - if (c == '\n') { - _start_of_line = true; - } else if (!isspace(c) && c != '#') { - _start_of_line = false; - } - - return c; -} - -/** - * Like get(), but does not alter the current state. - */ -int CPPPreprocessor:: -peek() { - if (_unget != '\0') { - return _unget; - } - - InputFile *infile = _infile; - if (UNLIKELY(infile == nullptr)) { - return EOF; - } - - int c = infile->peek(); - - while (UNLIKELY(c == EOF && infile != nullptr)) { - int last_c = infile->_prev_last_c; - infile = infile->_parent; - - if (last_c != '\0') { - c = last_c; - } else if (infile != nullptr) { - c = infile->peek(); - } - } - - return c; -} - -/** - * Undoes the effects of a previous get(). Not recommended, use peek() - * instead where possible, as it doesn't cause the column index to be off. - */ -void CPPPreprocessor:: -unget(int c) { - assert(_unget == '\0'); - _unget = c; -} - -/** - * Recursively invokes yacc to parse the stuff within angle brackets that's - * the template instantiation part of an identifier. This involves setting - * and restoring some state flags so we can return EOF when we reach the - * closing bracket. - */ -CPPTemplateParameterList *CPPPreprocessor:: -nested_parse_template_instantiation(CPPTemplateScope *scope) { -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Beginning nested parse\n"; -#endif - assert(scope != nullptr); - - State old_state = _state; - int old_nesting = _paren_nesting; - bool old_parsing_params = _parsing_template_params; - - const CPPTemplateParameterList &formal_params = scope->_parameters; - CPPTemplateParameterList::Parameters::const_iterator pi; - - _state = S_nested; - _paren_nesting = 0; - _parsing_template_params = true; - - CPPToken token = internal_get_next_token(); - if (token._token == '>' || token._token == 0) { - _parsing_template_params = false; - } else { - _saved_tokens.push_back(token); - } - - CPPTemplateParameterList *actual_params = new CPPTemplateParameterList; - - for (pi = formal_params._parameters.begin(); - pi != formal_params._parameters.end() && _parsing_template_params;) { - CPPToken token = peek_next_token(); - YYLTYPE loc = token._lloc; - - CPPDeclaration *decl = (*pi); - CPPClassTemplateParameter *param = decl->as_class_template_parameter(); - CPPInstance *inst = decl->as_instance(); - if (param) { - // Parse a typename template parameter. - _saved_tokens.push_back(CPPToken(START_TYPE)); - CPPType *type = ::parse_type(this, current_scope, global_scope); - if (type == nullptr) { - loc.last_line = get_line_number(); - loc.last_column = get_col_number() - 1; - warning("invalid type", loc); - skip_to_end_nested(); - type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown)); - } - actual_params->_parameters.push_back(type); - - // If this is a variadic template, keep reading using this parameter. - if (!param->_packed) { - ++pi; - } - } else if (inst) { - // Parse a constant expression template parameter. - _saved_tokens.push_back(CPPToken(START_CONST_EXPR)); - CPPExpression *expr = parse_const_expr(this, current_scope, global_scope); - if (expr == nullptr) { - loc.last_line = get_line_number(); - loc.last_column = get_col_number() - 1; - warning("invalid expression", loc); - skip_to_end_nested(); - expr = new CPPExpression(0); - } - actual_params->_parameters.push_back(expr); - - // If this is a variadic template, keep reading using this parameter. - if ((inst->_storage_class & CPPInstance::SC_parameter_pack) == 0) { - ++pi; - } - } else { - loc.last_line = get_line_number(); - loc.last_column = get_col_number() - 1; - warning("invalid template parameter", loc); - skip_to_end_nested(); - ++pi; - } - - _state = S_nested; - _paren_nesting = 0; - } - - if (_parsing_template_params) { - warning("Ignoring extra parameters in template instantiation"); - skip_to_angle_bracket(); - } - - _state = old_state; - _paren_nesting = old_nesting; - _parsing_template_params = old_parsing_params; - -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Ending nested parse\n"; -#endif - return actual_params; -} - - -/** - * This is an error-recovery function, called after returning from a nested - * parse. If the state is not S_end_nested, there was an error in parsing the - * nested tokens, and not all of the nested tokens may have been consumed. - * This function will consume the rest of the nested tokens. - */ -void CPPPreprocessor:: -skip_to_end_nested() { -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Skipping tokens:\n"; -#endif - - // Eat any eof tokens on the pushback stack. - while (!_saved_tokens.empty() && _saved_tokens.back().is_eof()) { - _saved_tokens.pop_back(); - } - - while (_state != S_end_nested && _state != S_eof) { - get_next_token(); - } - -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Done skipping tokens.\n"; -#endif -} - -/** - * This is an error-recovery function, called after returning from a nested - * parse. If we haven't yet consumed the closing angle bracket on the - * template instantiation, keep consuming tokens until we do. - */ -void CPPPreprocessor:: -skip_to_angle_bracket() { -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Skipping tokens:\n"; -#endif - - while (_parsing_template_params && _state != S_eof) { - _state = S_nested; - while (_state != S_end_nested && _state != S_eof) { - get_next_token(); - } - } - - // Eat any eof tokens on the pushback stack. - while (!_saved_tokens.empty() && _saved_tokens.back().is_eof()) { - _saved_tokens.pop_back(); - } - -#ifdef CPP_VERBOSE_LEX - indent(cerr, get_file_depth() * 2) - << "Done skipping tokens.\n"; -#endif -} - -/** - * Returns the number of files on the _infile list. - */ -int CPPPreprocessor:: -get_file_depth() const{ - int depth = 0; - InputFile *infile = _infile; - while (infile != nullptr) { - ++depth; - infile = infile->_parent; - } - return depth; -} diff --git a/dtool/src/cppparser/cppPreprocessor.h b/dtool/src/cppparser/cppPreprocessor.h deleted file mode 100644 index a241fc617d6..00000000000 --- a/dtool/src/cppparser/cppPreprocessor.h +++ /dev/null @@ -1,235 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppPreprocessor.h - * @author drose - * @date 1999-10-22 - */ - -#ifndef CPPPREPROCESSOR_H -#define CPPPREPROCESSOR_H - -#include "dtoolbase.h" - -#include "cppManifest.h" -#include "cppToken.h" -#include "cppFile.h" -#include "cppCommentBlock.h" - -#include "dSearchPath.h" -#include "vector_string.h" - -#include -#include -#include - -class CPPScope; -class CPPTemplateParameterList; -class CPPExpression; - -// #define CPP_VERBOSE_LEX - -/** - * - */ -class CPPPreprocessor { -public: - CPPPreprocessor(); - - bool preprocess_file(const Filename &filename); - - void set_verbose(int verbose); - int get_verbose() const; - - void copy_filepos(const CPPPreprocessor &other); - - CPPFile get_file() const; - int get_line_number() const; - int get_col_number() const; - - CPPToken get_next_token(); - CPPToken peek_next_token(); -#ifdef CPP_VERBOSE_LEX - CPPToken get_next_token0(); - int _token_index; -#endif - - void warning(const std::string &message) const; - void warning(const std::string &message, const YYLTYPE &loc) const; - void error(const std::string &message) const; - void error(const std::string &message, const YYLTYPE &loc) const; - void show_line(const YYLTYPE &loc) const; - - CPPCommentBlock *get_comment_before(int line, CPPFile file); - CPPCommentBlock *get_comment_on(int line, CPPFile file); - - int get_warning_count() const; - int get_error_count() const; - - typedef std::unordered_map Manifests; - Manifests _manifests; - - typedef std::vector ManifestStack; - std::map _manifest_stack; - - std::vector _quote_include_kind; - DSearchPath _quote_include_path; - DSearchPath _angle_include_path; - bool _noangles; - - CPPComments _comments; - - typedef std::set ParsedFiles; - ParsedFiles _parsed_files; - - typedef std::set Includes; - Includes _quote_includes; - Includes _angle_includes; - - std::set _explicit_files; - - // This is normally true, to indicate that the preprocessor should decode - // identifiers like foo::bar into a single IDENTIFIER, - // TYPENAME_IDENTIFIER, or SCOPING token for yacc's convenience. When - // false, it leaves them alone and returns a sequence of SIMPLE_IDENTIFIER - // and SCOPE tokens instead. - bool _resolve_identifiers; - - // The default _verbose level is 1, which will output normal error and - // warning messages but nothing else. Set this to 0 to make the warning - // messages go away (although the counts will still be incremented), or set - // it higher to get more debugging information. - int _verbose; - - // The location of the last token. - cppyyltype _last_token_loc; - -protected: - bool init_cpp(const CPPFile &file); - bool init_const_expr(const std::string &expr); - bool init_type(const std::string &type); - bool push_file(const CPPFile &file); - bool push_string(const std::string &input); - bool push_expansion(const std::string &input, const CPPManifest *manifest, - const YYLTYPE &loc); - -public: - void expand_manifests(std::string &expr, bool expand_undefined = false, - const CPPManifest::Ignores &ignores = CPPManifest::Ignores()) const; - CPPExpression *parse_expr(const std::string &expr, CPPScope *current_scope, - CPPScope *global_scope, const YYLTYPE &loc); - -private: - CPPToken internal_get_next_token(); - int check_digraph(int c); - int check_trigraph(int c); - int skip_whitespace(int c); - int skip_comment(int c); - int skip_c_comment(int c); - int skip_cpp_comment(int c); - int skip_digit_separator(int c); - int process_directive(int c); - - int get_preprocessor_command(int c, std::string &command); - int get_preprocessor_args(int c, std::string &args); - - void handle_define_directive(const std::string &args, const YYLTYPE &loc); - void handle_undef_directive(const std::string &args, const YYLTYPE &loc); - void handle_ifdef_directive(const std::string &args, const YYLTYPE &loc); - void handle_ifndef_directive(const std::string &args, const YYLTYPE &loc); - void handle_if_directive(const std::string &args, const YYLTYPE &loc); - void handle_include_directive(const std::string &args, const YYLTYPE &loc); - void handle_pragma_directive(const std::string &args, const YYLTYPE &loc); - void handle_error_directive(const std::string &args, const YYLTYPE &loc); - - void skip_false_if_block(bool consider_elifs); - bool is_manifest_defined(const std::string &manifest_name) const; - bool find_include(Filename &filename, bool angle_quotes, CPPFile::Source &source) const; - - CPPToken get_quoted_char(int c); - CPPToken get_quoted_string(int c); - CPPToken get_identifier(int c); - CPPToken get_literal(int token, YYLTYPE loc, const std::string &str, - const YYSTYPE &result = YYSTYPE()); - CPPToken expand_manifest(const CPPManifest *manifest, const YYLTYPE &loc); - void r_expand_manifests(std::string &expr, bool expand_undefined, - const YYLTYPE &loc, std::set &expanded); - void extract_manifest_args(const std::string &name, int num_args, - int va_arg, vector_string &args); - void expand_defined_function(std::string &expr, size_t q, size_t &p) const; - void expand_has_include_function(std::string &expr, size_t q, size_t &p) const; - - CPPToken get_number(int c); - int scan_escape_sequence(int c); - std::string scan_quoted(int c); - std::string scan_raw(int c); - - bool should_ignore_manifest(const CPPManifest *manifest) const; - bool should_ignore_preprocessor() const; - - int get(); - int peek(); - void unget(int c); - - CPPTemplateParameterList * - nested_parse_template_instantiation(CPPTemplateScope *scope); - void skip_to_end_nested(); - void skip_to_angle_bracket(); - - int get_file_depth() const; - - class InputFile { - public: - InputFile(); - ~InputFile(); - - bool open(const CPPFile &file); - bool connect_input(const std::string &input); - int get(); - int peek(); - - const CPPManifest *_manifest; - CPPFile _file; - std::string _input; - std::istream *_in; - int _line_number; - int _col_number; - int _next_line_number; - int _next_col_number; - bool _lock_position; - bool _ignore_manifest; - int _prev_last_c; - - InputFile *_parent = nullptr; - }; - - InputFile *_infile = nullptr; - - enum State { - S_normal, S_eof, S_nested, S_end_nested - }; - State _state; - int _paren_nesting; - bool _parsing_template_params; - bool _parsing_attribute; - - bool _start_of_line; - int _unget; - - int _last_c; - bool _last_cpp_comment; - bool _save_comments; - - std::vector _saved_tokens; - - mutable int _warning_count; - mutable int _error_count; - bool _error_abort; -}; - -#endif diff --git a/dtool/src/cppparser/cppReferenceType.cxx b/dtool/src/cppparser/cppReferenceType.cxx deleted file mode 100644 index 100111eac2f..00000000000 --- a/dtool/src/cppparser/cppReferenceType.cxx +++ /dev/null @@ -1,296 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppReferenceType.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppReferenceType.h" -#include "cppTypedefType.h" -#include "cppStructType.h" - -/** - * - */ -CPPReferenceType:: -CPPReferenceType(CPPType *pointing_at, ValueCategory vcat) : - CPPType(CPPFile()), - _pointing_at(pointing_at), - _value_category(vcat) -{ -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPReferenceType:: -is_fully_specified() const { - return CPPType::is_fully_specified() && - _pointing_at->is_fully_specified(); -} - -/** - * - */ -CPPDeclaration *CPPReferenceType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - return (*si).second; - } - - CPPReferenceType *rep = new CPPReferenceType(*this); - rep->_pointing_at = - _pointing_at->substitute_decl(subst, current_scope, global_scope) - ->as_type(); - - if (rep->_pointing_at == _pointing_at) { - delete rep; - rep = this; - } - rep = CPPType::new_type(rep)->as_reference_type(); - subst.insert(SubstDecl::value_type(this, rep)); - return rep; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPReferenceType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPType *ptype = _pointing_at->resolve_type(current_scope, global_scope); - - if (ptype != _pointing_at) { - CPPReferenceType *rep = new CPPReferenceType(*this); - rep->_pointing_at = ptype; - return CPPType::new_type(rep); - } - return this; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPReferenceType:: -is_tbd() const { - return _pointing_at->is_tbd(); -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPReferenceType:: -is_standard_layout() const { - return false; -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPReferenceType:: -is_trivial() const { - return false; -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPReferenceType:: -is_trivially_copyable() const { - return false; -} - -/** - * Returns true if the type can be constructed using the given argument. - */ -bool CPPReferenceType:: -is_constructible(const CPPType *given_type) const { - const CPPType *a; - const CPPType *b; - - CPPReferenceType *ref_type = ((CPPType *)given_type)->as_reference_type(); - if (ref_type != nullptr) { - if (ref_type->_value_category == VC_rvalue) { - return is_constructible(ref_type->_pointing_at); - } - - if (_value_category == VC_rvalue) { - // Can never initialize an rvalue ref from an lvalue ref. - return false; - } - - if (!_pointing_at->is_const()) { - // Cannot initialize a non-const reference using a const one. - if (ref_type->_pointing_at->is_const()) { - return false; - } - } - - a = _pointing_at->remove_cv(); - b = ref_type->_pointing_at->remove_cv(); - - } else { - // Initializing using an rvalue. - if (!_pointing_at->is_const()) { - // Cannot initialize a non-const reference using a const one. - if (given_type->is_const()) { - return false; - } - - // Cannot initalise a non-const lvalue reference with an rvalue ref. - if (_value_category == VC_lvalue) { - return false; - } - } - - a = _pointing_at->remove_cv(); - b = ((CPPType *)given_type)->remove_cv(); - } - - if (a == b || *a == *b) { - return true; - } - - // Can initialize from derived class pointer. - const CPPStructType *a_struct = a->as_struct_type(); - const CPPStructType *b_struct = b->as_struct_type(); - if (a_struct != nullptr && b_struct != nullptr) { - return a_struct->is_base_of(b_struct); - } - - return false; -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPReferenceType:: -is_default_constructible() const { - return false; -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPReferenceType:: -is_copy_constructible() const { - return (_value_category == VC_lvalue); -} - -/** - * Returns true if the type is destructible. - */ -bool CPPReferenceType:: -is_destructible() const { - return false; -} - -/** - * This is a little more forgiving than is_equal(): it returns true if the - * types appear to be referring to the same thing, even if they may have - * different pointers or somewhat different definitions. It's useful for - * parameter matching, etc. - */ -bool CPPReferenceType:: -is_equivalent(const CPPType &other) const { - const CPPReferenceType *ot = ((CPPType *)&other)->as_reference_type(); - if (ot == nullptr) { - return CPPType::is_equivalent(other); - } - - return _pointing_at->is_equivalent(*ot->_pointing_at); -} - -/** - * - */ -void CPPReferenceType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - /* - _pointing_at->output(out, indent_level, scope, complete); - out << " &"; - */ - output_instance(out, indent_level, scope, complete, "", ""); -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPReferenceType:: -output_instance(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const { - - std::string prefix((_value_category == VC_rvalue) ? "&&" : "&"); - - if (!_attributes.is_empty()) { - std::ostringstream strm; - strm << prefix << _attributes << " "; - prefix = strm.str(); - } - - _pointing_at->output_instance(out, indent_level, scope, complete, - prefix + prename, name); -} - -/** - * - */ -CPPDeclaration::SubType CPPReferenceType:: -get_subtype() const { - return ST_reference; -} - -/** - * - */ -CPPReferenceType *CPPReferenceType:: -as_reference_type() { - return this; -} - - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPReferenceType:: -is_equal(const CPPDeclaration *other) const { - const CPPReferenceType *ot = ((CPPDeclaration *)other)->as_reference_type(); - assert(ot != nullptr); - - return (_pointing_at == ot->_pointing_at) && - (_value_category == ot->_value_category); -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPReferenceType:: -is_less(const CPPDeclaration *other) const { - const CPPReferenceType *ot = ((CPPDeclaration *)other)->as_reference_type(); - assert(ot != nullptr); - - if (_value_category != ot->_value_category) { - return (_value_category < ot->_value_category); - } - - return _pointing_at < ot->_pointing_at; -} diff --git a/dtool/src/cppparser/cppReferenceType.h b/dtool/src/cppparser/cppReferenceType.h deleted file mode 100644 index df79a1ec213..00000000000 --- a/dtool/src/cppparser/cppReferenceType.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppReferenceType.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPREFERENCETYPE_H -#define CPPREFERENCETYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" - -/** - * Either an lvalue- or rvalue-reference. - */ -class CPPReferenceType : public CPPType { -public: - enum ValueCategory { - VC_lvalue, - VC_rvalue - }; - - CPPReferenceType(CPPType *pointing_at, ValueCategory vcat=VC_lvalue); - - CPPType *_pointing_at; - ValueCategory _value_category; - - virtual bool is_fully_specified() const; - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_tbd() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *type) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_destructible() const; - virtual bool is_equivalent(const CPPType &other) const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const; - - virtual SubType get_subtype() const; - - virtual CPPReferenceType *as_reference_type(); - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppScope.cxx b/dtool/src/cppparser/cppScope.cxx deleted file mode 100644 index a88961d4b78..00000000000 --- a/dtool/src/cppparser/cppScope.cxx +++ /dev/null @@ -1,1191 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppScope.cxx - * @author drose - * @date 1999-10-21 - */ - -#include "cppScope.h" -#include "cppParser.h" -#include "cppDeclaration.h" -#include "cppNamespace.h" -#include "cppTypedefType.h" -#include "cppTypeDeclaration.h" -#include "cppExtensionType.h" -#include "cppEnumType.h" -#include "cppInstance.h" -#include "cppInstanceIdentifier.h" -#include "cppIdentifier.h" -#include "cppStructType.h" -#include "cppFunctionGroup.h" -#include "cppPreprocessor.h" -#include "cppTemplateScope.h" -#include "cppClassTemplateParameter.h" -#include "cppFunctionType.h" -#include "cppConstType.h" -#include "cppUsing.h" -#include "cppBisonDefs.h" -#include "indent.h" - -using std::ostream; -using std::ostringstream; -using std::pair; -using std::string; - -/** - * - */ -CPPScope:: -CPPScope(CPPScope *parent_scope, - const CPPNameComponent &name, CPPVisibility starting_vis) : - _name(name), - _parent_scope(parent_scope), - _current_vis(starting_vis) -{ - _struct_type = nullptr; - _is_fully_specified = false; - _fully_specified_known = false; - _is_fully_specified_recursive_protect = false; - _subst_decl_recursive_protect = false; -} - -/** - * - */ -CPPScope:: -~CPPScope() { -} - -/** - * Sets the struct or class that owns this scope. This should only be done - * once, when the scope and its associated struct are created. It's provided - * so the scope can check the struct's ancestry for inherited symbols. - */ -void CPPScope:: -set_struct_type(CPPStructType *struct_type) { - _struct_type = struct_type; -} - -/** - * Returns the class or struct that defines this scope, if any. - */ -CPPStructType *CPPScope:: -get_struct_type() const { - return _struct_type; -} - -/** - * Returns the parent scope of this scope, if any. - */ -CPPScope *CPPScope:: -get_parent_scope() const { - return _parent_scope; -} - -/** - * - */ -void CPPScope:: -set_current_vis(CPPVisibility current_vis) { - _current_vis = current_vis; -} - -/** - * - */ -CPPVisibility CPPScope:: -get_current_vis() const { - return _current_vis; -} - -/** - * - */ -void CPPScope:: -add_declaration(CPPDeclaration *decl, CPPScope *global_scope, - CPPPreprocessor *preprocessor, const cppyyltype &pos) { - decl->_vis = _current_vis; - - // Get the recent comments from the preprocessor. These are the comments - // that appeared preceding this particular declaration; they might be - // relevant to the declaration. - - if (decl->_leading_comment == nullptr) { - decl->_leading_comment = - preprocessor->get_comment_before(pos.first_line, pos.file); - } - - _declarations.push_back(decl); - - handle_declaration(decl, global_scope, preprocessor); -} - -/** - * - */ -void CPPScope:: -add_enum_value(CPPInstance *inst) { - inst->_vis = _current_vis; - - string name = inst->get_simple_name(); - if (!name.empty()) { - _enum_values[name] = inst; - } -} - -/** - * - */ -void CPPScope:: -define_typedef_type(CPPTypedefType *type, CPPPreprocessor *error_sink) { - string name = type->get_simple_name(); - - pair result = - _types.insert(Types::value_type(name, type)); - - if (!result.second) { - CPPType *other_type = result.first->second; - CPPTypedefType *other_td = other_type->as_typedef_type(); - - // We don't do redefinitions of typedefs. But we don't complain as long - // as this is actually a typedef to the previous definition. - if (other_type != type->_type && - (other_td == nullptr || !other_td->_type->is_equivalent(*type->_type))) { - - if (error_sink != nullptr) { - ostringstream errstr; - type->output(errstr, 0, nullptr, false); - errstr << " has conflicting declaration as "; - other_type->output(errstr, 0, nullptr, true); - error_sink->error(errstr.str(), type->_ident->_loc); - if (other_td != nullptr && other_td->_ident != nullptr) { - error_sink->error("previous definition is here", - other_td->_ident->_loc); - } - } - } - } else { - _types[name] = type; - } - - // This might be a templated "using" definition. - if (type->is_template()) { - CPPTemplateScope *scope = type->get_template_scope(); - if (scope->_parameters._parameters.size() == 0) { - return; - } - - string simple_name = type->get_simple_name(); - - pair result = - _templates.insert(Templates::value_type(simple_name, type)); - - if (!result.second) { - // The template was not inserted because we already had a template - // definition with the given name. If the previous definition was - // incomplete, replace it. - CPPDeclaration *old_templ = (*result.first).second; - CPPType *old_templ_type = old_templ->as_type(); - if (old_templ_type == nullptr || old_templ_type->is_incomplete()) { - // The previous template definition was incomplete, maybe a forward - // reference; replace it with the good one. - (*result.first).second = type; - } - } - } -} - -/** - * - */ -void CPPScope:: -define_extension_type(CPPExtensionType *type, CPPPreprocessor *error_sink) { - assert(type != nullptr); - string name = type->get_local_name(this); - if (name.empty()) { - return; - } - - switch (type->_type) { - case CPPExtensionType::T_class: - _classes[name] = type; - break; - - case CPPExtensionType::T_struct: - _structs[name] = type; - break; - - case CPPExtensionType::T_union: - _unions[name] = type; - break; - - case CPPExtensionType::T_enum: - case CPPExtensionType::T_enum_struct: - case CPPExtensionType::T_enum_class: - _enums[name] = type; - break; - } - - // Create an implicit typedef for the extension. CPPTypedefType *td = new - // CPPTypedefType(type, name); - pair result = - _types.insert(Types::value_type(name, type)); - - if (!result.second) { - // There's already a typedef for this extension. This one overrides it - // only if the other is a forward declaration. - CPPType *other_type = (*result.first).second; - - if (other_type->get_subtype() == CPPDeclaration::ST_extension) { - CPPExtensionType *other_ext = other_type->as_extension_type(); - - if (other_ext->_type != type->_type) { - if (error_sink != nullptr) { - ostringstream errstr; - errstr << type->_type << " " << type->get_fully_scoped_name() - << " was previously declared as " << other_ext->_type; - error_sink->error(errstr.str(), type->_ident->_loc); - - if (other_ext->_ident != nullptr) { - error_sink->error("previous declaration is here", - other_ext->_ident->_loc); - } - } - } - (*result.first).second = type; - - } else { - CPPTypedefType *other_td = other_type->as_typedef_type(); - - // Error out if the declaration is different than the previous one. - if (other_type != type && - (other_td == nullptr || other_td->_type != type)) { - - if (error_sink != nullptr) { - ostringstream errstr; - if (!cppparser_output_class_keyword) { - errstr << type->_type << " "; - } - type->output(errstr, 0, nullptr, false); - errstr << " has conflicting definition as "; - other_type->output(errstr, 0, nullptr, true); - error_sink->error(errstr.str(), type->_ident->_loc); - - CPPExtensionType *other_ext = other_type->as_extension_type(); - if (other_ext != nullptr && other_ext->_ident != nullptr) { - error_sink->error("previous definition is here", - other_ext->_ident->_loc); - } - } - } - } - } - - if (type->is_template()) { - CPPTemplateScope *scope = type->get_template_scope(); - if (scope->_parameters._parameters.size() == 0) { - return; - } - - string simple_name = type->get_simple_name(); - - pair result = - _templates.insert(Templates::value_type(simple_name, type)); - - if (!result.second) { - // The template was not inserted because we already had a template - // definition with the given name. If the previous definition was - // incomplete, replace it. - CPPDeclaration *old_templ = (*result.first).second; - CPPType *old_templ_type = old_templ->as_type(); - if (old_templ_type == nullptr || old_templ_type->is_incomplete()) { - // The previous template definition was incomplete, maybe a forward - // reference; replace it with the good one. - (*result.first).second = type; - } - } - } -} - -/** - * - */ -void CPPScope:: -define_namespace(CPPNamespace *ns) { - string name = ns->get_simple_name(); - - _namespaces[name] = ns; - - if (ns->_is_inline) { - // Add an implicit using declaration for an inline namespace. - _using.insert(ns->get_scope()); - } -} - -/** - * - */ -void CPPScope:: -add_using(CPPUsing *using_decl, CPPScope *global_scope, - CPPPreprocessor *error_sink) { - if (using_decl->_full_namespace) { - CPPScope *scope = - using_decl->_ident->find_scope(this, global_scope); - if (scope != nullptr) { - _using.insert(scope); - } else { - if (error_sink != nullptr) { - error_sink->warning("Attempt to use undefined namespace: " + using_decl->_ident->get_fully_scoped_name(), using_decl->_ident->_loc); - } - } - } else { - CPPDeclaration *decl = using_decl->_ident->find_symbol(this, global_scope); - if (decl != nullptr) { - handle_declaration(decl, global_scope, error_sink); - } else { - if (error_sink != nullptr) { - error_sink->warning("Attempt to use unknown symbol: " + using_decl->_ident->get_fully_scoped_name(), using_decl->_ident->_loc); - } - } - } -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPScope:: -is_fully_specified() const { - if (_fully_specified_known) { - return _is_fully_specified; - } - - if (_is_fully_specified_recursive_protect) { - // We're already executing this block. - return true; - } - ((CPPScope *)this)->_is_fully_specified_recursive_protect = true; - - bool specified = true; - - if (_parent_scope != nullptr && !_parent_scope->is_fully_specified()) { - specified = false; - } - - Declarations::const_iterator di; - for (di = _declarations.begin(); - di != _declarations.end() && specified; - ++di) { - if (!(*di)->is_fully_specified()) { - specified = false; - } - } - - ((CPPScope *)this)->_fully_specified_known = true; - ((CPPScope *)this)->_is_fully_specified = specified; - ((CPPScope *)this)->_is_fully_specified_recursive_protect = false; - - return specified; -} - -/** - * - */ -CPPScope *CPPScope:: -instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - CPPScope *this_scope = (CPPScope *)this; - - if (_parent_scope == nullptr || - _parent_scope->as_template_scope() == nullptr) { - if (error_sink != nullptr) { - error_sink->warning("Ignoring template parameters for scope " + - get_local_name()); - } - return this_scope; - } - - if (is_fully_specified()) { - return this_scope; - } - - Instantiations::const_iterator ii; - ii = _instantiations.find(actual_params); - if (ii != _instantiations.end()) { - // We've already instantiated this scope with these parameters. Return - // that. - return (*ii).second; - } - - /* - cerr << "Instantiating " << get_simple_name() - << "<" << *actual_params << ">\n"; - */ - - // Build the mapping of formal parameters to actual parameters. - CPPTemplateScope *tscope = _parent_scope->as_template_scope(); - CPPDeclaration::SubstDecl subst; - actual_params->build_subst_decl(tscope->_parameters, subst, - current_scope, global_scope); - - CPPScope *scope; - if (subst.empty()) { - scope = (CPPScope *)this; - - } else { - CPPNameComponent name = _name; - name.set_templ(new CPPTemplateParameterList(*actual_params)); - // scope = new CPPScope(current_scope, name, V_public); - scope = new CPPScope(_parent_scope, name, V_public); - copy_substitute_decl(scope, subst, global_scope); - - // Also define any new template parameter types, in case we "instantiated" - // this scope with another template parameter. - CPPTemplateParameterList::Parameters::const_iterator pi; - for (pi = actual_params->_parameters.begin(); - pi != actual_params->_parameters.end(); - ++pi) { - CPPDeclaration *decl = (*pi); - CPPClassTemplateParameter *ctp = decl->as_class_template_parameter(); - if (ctp != nullptr) { - // CPPTypedefType *td = new CPPTypedefType(ctp, ctp->_ident); - // scope->_typedefs.insert(Typedefs::value_type - // (ctp->_ident->get_local_name(), td)); - scope->_types.insert(Types::value_type - (ctp->_ident->get_local_name(), - ctp)); - } - } - } - - // Finally, record this particular instantiation for future reference, so we - // don't have to do this again. - ((CPPScope *)this)->_instantiations.insert(Instantiations::value_type(actual_params, scope)); - - return scope; -} - -/** - * - */ -CPPScope *CPPScope:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) const { - CPPScope *this_scope = (CPPScope *)this; - - if (is_fully_specified()) { - return this_scope; - } - - if (_subst_decl_recursive_protect) { - // We're already executing this block. - return this_scope; - } - ((CPPScope *)this)->_subst_decl_recursive_protect = true; - - CPPScope *rep = new CPPScope(current_scope, _name, V_public); - bool anything_changed; - - if (_parent_scope != nullptr && - _parent_scope->as_template_scope() != nullptr) { - // If the parent of this scope is a template scope--e.g. this scope has - // template parameters--then we must first remove any of the template - // parameters from the subst list. These will later get substituted - // properly during instantiation. - const CPPTemplateParameterList &p = - _parent_scope->as_template_scope()->_parameters; - - CPPDeclaration::SubstDecl new_subst = subst; - CPPTemplateParameterList::Parameters::const_iterator pi; - for (pi = p._parameters.begin(); pi != p._parameters.end(); ++pi) { - new_subst.erase(*pi); - } - anything_changed = copy_substitute_decl(rep, new_subst, global_scope); - } else { - anything_changed = copy_substitute_decl(rep, subst, global_scope); - } - - if (!anything_changed && rep->_parent_scope == _parent_scope) { - delete rep; - rep = (CPPScope *)this; - } - ((CPPScope *)this)->_subst_decl_recursive_protect = false; - - return rep; -} - -/** - * - */ -CPPType *CPPScope:: -find_type(const string &name, bool recurse) const { - Types::const_iterator ti; - ti = _types.find(name); - if (ti != _types.end()) { - return ti->second; - } - - Using::const_iterator ui; - for (ui = _using.begin(); ui != _using.end(); ++ui) { - CPPType *type = (*ui)->find_type(name, false); - if (type != nullptr) { - return type; - } - } - - if (_struct_type != nullptr) { - CPPStructType::Derivation::const_iterator di; - for (di = _struct_type->_derivation.begin(); - di != _struct_type->_derivation.end(); - ++di) { - CPPStructType *st = (*di)._base->as_struct_type(); - if (st != nullptr) { - CPPType *type = st->_scope->find_type(name, false); - if (type != nullptr) { - return type; - } - } - } - } - - if (recurse && _parent_scope != nullptr) { - return _parent_scope->find_type(name); - } - - return nullptr; -} - -/** - * - */ -CPPType *CPPScope:: -find_type(const string &name, CPPDeclaration::SubstDecl &subst, - CPPScope *global_scope, bool recurse) const { - Types::const_iterator ti; - ti = _types.find(name); - if (ti != _types.end()) { - CPPScope *current_scope = (CPPScope *)this; - return (*ti).second->substitute_decl - (subst, current_scope, global_scope)->as_type(); - } - - Using::const_iterator ui; - for (ui = _using.begin(); ui != _using.end(); ++ui) { - CPPType *type = (*ui)->find_type(name, subst, global_scope, false); - if (type != nullptr) { - return type; - } - } - - if (_struct_type != nullptr) { - CPPStructType::Derivation::const_iterator di; - for (di = _struct_type->_derivation.begin(); - di != _struct_type->_derivation.end(); - ++di) { - CPPStructType *st = (*di)._base->as_struct_type(); - if (st != nullptr) { - CPPType *type = st->_scope->find_type(name, subst, global_scope, - false); - if (type != nullptr) { - return type; - } - } - } - } - - if (recurse && _parent_scope != nullptr) { - return _parent_scope->find_type(name, subst, global_scope); - } - - return nullptr; -} - -/** - * - */ -CPPScope *CPPScope:: -find_scope(const string &name, CPPScope *global_scope, bool recurse) const { - Namespaces::const_iterator ni = _namespaces.find(name); - if (ni != _namespaces.end()) { - return (*ni).second->get_scope(); - } - - CPPType *type = nullptr; - - Types::const_iterator ti; - ti = _types.find(name); - if (ti != _types.end()) { - type = (*ti).second; - // Resolve if this is a typedef or const, or a TBD type. - while (type->get_subtype() == CPPDeclaration::ST_const || - type->get_subtype() == CPPDeclaration::ST_typedef || - type->get_subtype() == CPPDeclaration::ST_tbd) { - if (type->as_typedef_type() != nullptr) { - type = type->as_typedef_type()->_type; - } else if (type->as_const_type() != nullptr) { - type = type->as_const_type()->_wrapped_around; - } else { - CPPType *new_type = type->resolve_type((CPPScope *)this, global_scope); - if (new_type != type) { - type = new_type; - } else { - break; - } - } - } - - } else if (_struct_type != nullptr) { - CPPStructType::Derivation::const_iterator di; - for (di = _struct_type->_derivation.begin(); - di != _struct_type->_derivation.end(); - ++di) { - CPPStructType *st = (*di)._base->as_struct_type(); - if (st != nullptr) { - type = st->_scope->find_type(name, false); - } - } - } - - if (type != nullptr) { - CPPStructType *st = type->as_struct_type(); - if (st != nullptr) { - return st->_scope; - } - - CPPEnumType *et = type->as_enum_type(); - if (et != nullptr) { - return et->_scope; - } - } - - Using::const_iterator ui; - for (ui = _using.begin(); ui != _using.end(); ++ui) { - CPPScope *scope = (*ui)->find_scope(name, global_scope, false); - if (scope != nullptr) { - return scope; - } - } - - if (recurse && _parent_scope != nullptr) { - return _parent_scope->find_scope(name, global_scope); - } - - return nullptr; -} - -/** - * - */ -CPPScope *CPPScope:: -find_scope(const string &name, CPPDeclaration::SubstDecl &subst, - CPPScope *global_scope, bool recurse) const { - CPPType *type = find_type(name, subst, global_scope, recurse); - if (type == nullptr) { - return nullptr; - } - - // Resolve if this is a typedef or const. - while (type->get_subtype() == CPPDeclaration::ST_const || - type->get_subtype() == CPPDeclaration::ST_typedef) { - if (type->as_typedef_type() != nullptr) { - type = type->as_typedef_type()->_type; - } else { - type = type->as_const_type()->_wrapped_around; - } - } - - CPPStructType *st = type->as_struct_type(); - if (st != nullptr) { - return st->_scope; - } - - CPPEnumType *et = type->as_enum_type(); - if (et != nullptr) { - return et->_scope; - } - - return nullptr; -} - -/** - * - */ -CPPDeclaration *CPPScope:: -find_symbol(const string &name, bool recurse) const { - if (_struct_type != nullptr && name == get_simple_name()) { - return _struct_type; - } - - Functions::const_iterator fi; - fi = _functions.find(name); - if (fi != _functions.end()) { - return (*fi).second; - } - - Types::const_iterator ti; - ti = _types.find(name); - if (ti != _types.end()) { - return (*ti).second; - } - - Variables::const_iterator vi; - vi = _variables.find(name); - if (vi != _variables.end()) { - return (*vi).second; - } - - vi = _enum_values.find(name); - if (vi != _enum_values.end()) { - return (*vi).second; - } - - Using::const_iterator ui; - for (ui = _using.begin(); ui != _using.end(); ++ui) { - CPPDeclaration *decl = (*ui)->find_symbol(name, false); - if (decl != nullptr) { - return decl; - } - } - - if (_struct_type != nullptr) { - CPPStructType::Derivation::const_iterator di; - for (di = _struct_type->_derivation.begin(); - di != _struct_type->_derivation.end(); - ++di) { - CPPStructType *st = (*di)._base->as_struct_type(); - if (st != nullptr) { - CPPDeclaration *decl = st->_scope->find_symbol(name, false); - if (decl != nullptr) { - return decl; - } - } - } - } - - if (recurse && _parent_scope != nullptr) { - return _parent_scope->find_symbol(name); - } - - return nullptr; -} - -/** - * - */ -CPPDeclaration *CPPScope:: -find_template(const string &name, bool recurse) const { - Templates::const_iterator ti; - ti = _templates.find(name); - if (ti != _templates.end()) { - return (*ti).second; - } - - Using::const_iterator ui; - for (ui = _using.begin(); ui != _using.end(); ++ui) { - CPPDeclaration *decl = (*ui)->find_template(name, false); - if (decl != nullptr) { - return decl; - } - } - - if (_struct_type != nullptr) { - CPPStructType::Derivation::const_iterator di; - for (di = _struct_type->_derivation.begin(); - di != _struct_type->_derivation.end(); - ++di) { - CPPStructType *st = (*di)._base->as_struct_type(); - if (st != nullptr) { - CPPDeclaration *decl = st->_scope->find_template(name, false); - if (decl != nullptr) { - return decl; - } - } - } - } - - if (recurse && _parent_scope != nullptr) { - return _parent_scope->find_template(name); - } - - return nullptr; -} - -/** - * - */ -string CPPScope:: -get_simple_name() const { - /* - if (_struct_type != (CPPStructType *)NULL) { - return _struct_type->get_simple_name(); - } - */ - return _name.get_name(); -} - -/** - * - */ -string CPPScope:: -get_local_name(CPPScope *scope) const { - /* - if (_struct_type != (CPPStructType *)NULL) { - return _struct_type->get_local_name(scope); - } - */ - - if (scope != nullptr && _parent_scope != nullptr/* && _parent_scope != scope*/) { - string parent_scope_name = _parent_scope->get_local_name(scope); - if (parent_scope_name.empty()) { - return _name.get_name_with_templ(); - } else { - return parent_scope_name + "::" + - _name.get_name_with_templ(); - } - } else { - return _name.get_name_with_templ(); - } -} - -/** - * - */ -string CPPScope:: -get_fully_scoped_name() const { - /* - if (_struct_type != (CPPStructType *)NULL) { - return _struct_type->get_fully_scoped_name(); - } - */ - - if (_parent_scope != nullptr) { - return _parent_scope->get_fully_scoped_name() + "::" + - _name.get_name_with_templ(); - } else { - return _name.get_name_with_templ(); - } -} - -/** - * - */ -void CPPScope:: -output(ostream &out, CPPScope *scope) const { - // out << get_local_name(scope); - if (_parent_scope != nullptr && _parent_scope != scope) { - _parent_scope->output(out, scope); - out << "::"; - } - out << _name; -} - -/** - * - */ -void CPPScope:: -write(ostream &out, int indent_level, CPPScope *scope) const { - CPPVisibility vis = V_unknown; - Declarations::const_iterator di; - for (di = _declarations.begin(); di != _declarations.end(); ++di) { - CPPDeclaration *cd = (*di); - if (cd->_vis != vis && indent_level > 0) { - vis = cd->_vis; - indent(out, indent_level - 2) << vis << ":\n"; - } - bool complete = false; - - if (cd->as_type() != nullptr || cd->as_namespace() != nullptr) { - complete = true; - } - - indent(out, indent_level); - cd->output(out, indent_level, scope, complete); - out << ";\n"; - } -} - -/** - * Returns the nearest ancestor of this scope that is a template scope, or - * NULL if the scope is fully specified. - */ -CPPTemplateScope *CPPScope:: -get_template_scope() { - if (as_template_scope()) { - return as_template_scope(); - } - if (_parent_scope != nullptr) { - return _parent_scope->get_template_scope(); - } - return nullptr; -} - -/** - * - */ -CPPTemplateScope *CPPScope:: -as_template_scope() { - return nullptr; -} - -/** - * This is in support of both substitute_decl() and instantiate(). It's - * similar in purpose to substitute_decl(), but this function assumes the - * caller has already created a new, empty scope. All of the declarations in - * this scope are copied to the new scope, filtering through the subst decl. - * - * The return value is true if the scope is changed, false if it is not. - */ -bool CPPScope:: -copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst, - CPPScope *global_scope) const { - bool anything_changed = false; - - if (_struct_type != nullptr) { - CPPScope *native_scope = nullptr; - if (_struct_type->_ident != nullptr) { - native_scope = _struct_type->_ident->_native_scope; - } - to_scope->_struct_type = - new CPPStructType(_struct_type->_type, - new CPPIdentifier(to_scope->_name, _struct_type->_file), - native_scope, to_scope, _struct_type->_file); - to_scope->_struct_type->_incomplete = false; - - // Copy the derivation to the new type. - CPPStructType::Derivation::const_iterator di; - for (di = _struct_type->_derivation.begin(); - di != _struct_type->_derivation.end(); - ++di) { - CPPStructType::Base b = (*di); - b._base = - (*di)._base->substitute_decl(subst, to_scope, global_scope)->as_type(); - to_scope->_struct_type->_derivation.push_back(b); - if (b._base != (*di)._base) { - anything_changed = true; - } - } - } - - Declarations::const_iterator di; - for (di = _declarations.begin(); di != _declarations.end(); ++di) { - CPPDeclaration *decl = - (*di)->substitute_decl(subst, to_scope, global_scope); - to_scope->_declarations.push_back(decl); - if (decl != (*di)) { - anything_changed = true; - } - } - - ExtensionTypes::const_iterator ei; - for (ei = _structs.begin(); ei != _structs.end(); ++ei) { - string name = (*ei).first; - CPPType *source_type = (*ei).second; - CPPDeclaration *decl = - source_type->substitute_decl(subst, to_scope, global_scope); - assert(decl != nullptr); - CPPType *new_type = decl->as_type(); - assert(new_type != nullptr); - to_scope->_structs.insert(ExtensionTypes::value_type(name, new_type)); - if (new_type != source_type) { - anything_changed = true; - } - } - for (ei = _classes.begin(); ei != _classes.end(); ++ei) { - string name = (*ei).first; - CPPType *source_type = (*ei).second; - CPPDeclaration *decl = - source_type->substitute_decl(subst, to_scope, global_scope); - assert(decl != nullptr); - CPPType *new_type = decl->as_type(); - assert(new_type != nullptr); - to_scope->_classes.insert(ExtensionTypes::value_type(name, new_type)); - if (new_type != source_type) { - anything_changed = true; - } - } - for (ei = _unions.begin(); ei != _unions.end(); ++ei) { - string name = (*ei).first; - CPPType *source_type = (*ei).second; - CPPDeclaration *decl = - source_type->substitute_decl(subst, to_scope, global_scope); - assert(decl != nullptr); - CPPType *new_type = decl->as_type(); - assert(new_type != nullptr); - to_scope->_unions.insert(ExtensionTypes::value_type(name, new_type)); - if (new_type != source_type) { - anything_changed = true; - } - } - for (ei = _enums.begin(); ei != _enums.end(); ++ei) { - string name = (*ei).first; - CPPType *source_type = (*ei).second; - CPPDeclaration *decl = - source_type->substitute_decl(subst, to_scope, global_scope); - assert(decl != nullptr); - CPPType *new_type = decl->as_type(); - assert(new_type != nullptr); - to_scope->_enums.insert(ExtensionTypes::value_type(name, new_type)); - if (new_type != source_type) { - anything_changed = true; - } - } - Functions::const_iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - CPPFunctionGroup *fgroup = (*fi).second; - string name = fgroup->_name; - - CPPFunctionGroup *&to_fgroup = to_scope->_functions[name]; - if (to_fgroup == nullptr) { - to_fgroup = new CPPFunctionGroup(name); - } - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = - (*ii)->substitute_decl(subst, to_scope, global_scope)->as_instance(); - to_fgroup->_instances.push_back(inst); - if (inst != (*ii)) { - anything_changed = true; - } - } - } - - Types::const_iterator ti; - for (ti = _types.begin(); ti != _types.end(); ++ti) { - CPPType *td = - (*ti).second->substitute_decl(subst, to_scope, global_scope)->as_type(); - to_scope->_types.insert(Types::value_type((*ti).first, td)); - if (td != (*ti).second) { - anything_changed = true; - } - } - Variables::const_iterator vi; - for (vi = _variables.begin(); vi != _variables.end(); ++vi) { - CPPInstance *inst = - (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance(); - to_scope->_variables.insert(Variables::value_type((*vi).first, inst)); - if (inst != (*vi).second) { - anything_changed = true; - } - } - - for (vi = _enum_values.begin(); vi != _enum_values.end(); ++vi) { - CPPInstance *inst = - (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance(); - to_scope->_enum_values.insert(Variables::value_type((*vi).first, inst)); - if (inst != (*vi).second) { - anything_changed = true; - } - } - - Templates::const_iterator tmi; - for (tmi = _templates.begin(); tmi != _templates.end(); ++tmi) { - CPPDeclaration *decl = - (*tmi).second->substitute_decl(subst, to_scope, global_scope); - to_scope->_templates.insert(Templates::value_type((*tmi).first, decl)); - if (decl != (*tmi).second) { - anything_changed = true; - } - } - - return anything_changed; -} - - -/** - * Does the right thing with a newly given declaration: adds it to the typedef - * list, or variables or functions, or whatever. - */ -void CPPScope:: -handle_declaration(CPPDeclaration *decl, CPPScope *global_scope, - CPPPreprocessor *error_sink) { - CPPTypedefType *def = decl->as_typedef_type(); - if (def != nullptr) { - define_typedef_type(def, error_sink); - - CPPExtensionType *et = def->_type->as_extension_type(); - if (et != nullptr) { - define_extension_type(et, error_sink); - } - return; - } - - CPPTypeDeclaration *typedecl = decl->as_type_declaration(); - if (typedecl != nullptr) { - CPPExtensionType *et = typedecl->_type->as_extension_type(); - if (et != nullptr) { - define_extension_type(et, error_sink); - } - return; - } - - CPPInstance *inst = decl->as_instance(); - if (inst != nullptr) { - inst->check_for_constructor(this, global_scope); - - if (inst->_ident != nullptr) { - // Not sure if this is the best place to assign this. However, this - // fixes a bug with variables in expressions not having the proper - // scoping prefix. ~rdb - inst->_ident->_native_scope = this; - } - - string name = inst->get_simple_name(); - if (!name.empty() && inst->get_scope(this, global_scope) == this) { - if (inst->_type->as_function_type()) { - // This is a function declaration; hence it gets added to the - // _functions member. But we must be careful to share common-named - // functions. - - CPPFunctionGroup *fgroup; - Functions::const_iterator fi; - fi = _functions.find(name); - if (fi == _functions.end()) { - fgroup = new CPPFunctionGroup(name); - _functions.insert(Functions::value_type(name, fgroup)); - } else { - fgroup = (*fi).second; - } - fgroup->_instances.push_back(inst); - - } else { - // This is not a function declaration; hence it gets added to the - // _variables member. - _variables[name] = inst; - } - - if (inst->is_template()) { - // Don't add a new template definition if we already had one by the - // same name in another scope. - - if (find_template(name) == nullptr) { - _templates.insert(Templates::value_type(name, inst)); - } - - /* - if (inst->_type->as_function_type() == NULL || - (inst->_type->as_function_type()->_flags & - CPPFunctionType::F_constructor) == 0) { - _templates.insert(Templates::value_type(name, inst)); - } - */ - } - } - return; - } - - CPPExtensionType *et = decl->as_extension_type(); - if (et != nullptr) { - define_extension_type(et, error_sink); - } -} diff --git a/dtool/src/cppparser/cppScope.h b/dtool/src/cppparser/cppScope.h deleted file mode 100644 index 2631d6097ac..00000000000 --- a/dtool/src/cppparser/cppScope.h +++ /dev/null @@ -1,165 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppScope.h - * @author drose - * @date 1999-10-21 - */ - -#ifndef CPPSCOPE_H -#define CPPSCOPE_H - -#include "dtoolbase.h" - -#include "cppVisibility.h" -#include "cppTemplateParameterList.h" -#include "cppNameComponent.h" - -#include -#include -#include -#include - -class CPPType; -class CPPDeclaration; -class CPPExtensionType; -class CPPStructType; -class CPPNamespace; -class CPPUsing; -class CPPTypedefType; -class CPPInstance; -class CPPFunctionGroup; -class CPPTemplateScope; -class CPPTemplateParameterList; -class CPPPreprocessor; -class CPPNameComponent; -struct cppyyltype; - -/** - * - */ -class CPPScope { -public: - CPPScope(CPPScope *parent_scope, - const CPPNameComponent &name, CPPVisibility starting_vis); - virtual ~CPPScope(); - - void set_current_vis(CPPVisibility current_vis); - CPPVisibility get_current_vis() const; - - void set_struct_type(CPPStructType *struct_type); - CPPStructType *get_struct_type() const; - CPPScope *get_parent_scope() const; - - virtual void add_declaration(CPPDeclaration *decl, CPPScope *global_scope, - CPPPreprocessor *preprocessor, - const cppyyltype &pos); - virtual void add_enum_value(CPPInstance *inst); - virtual void define_typedef_type(CPPTypedefType *type, - CPPPreprocessor *error_sink = nullptr); - virtual void define_extension_type(CPPExtensionType *type, - CPPPreprocessor *error_sink = nullptr); - virtual void define_namespace(CPPNamespace *scope); - virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr); - - virtual bool is_fully_specified() const; - - CPPScope * - instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - CPPScope * - substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope) const; - - CPPType *find_type(const std::string &name, bool recurse = true) const; - CPPType *find_type(const std::string &name, - CPPDeclaration::SubstDecl &subst, - CPPScope *global_scope, - bool recurse = true) const; - CPPScope *find_scope(const std::string &name, CPPScope *global_scope, - bool recurse = true) const; - CPPScope *find_scope(const std::string &name, - CPPDeclaration::SubstDecl &subst, - CPPScope *global_scope, - bool recurse = true) const; - CPPDeclaration *find_symbol(const std::string &name, - bool recurse = true) const; - CPPDeclaration *find_template(const std::string &name, - bool recurse = true) const; - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - - virtual void output(std::ostream &out, CPPScope *scope) const; - void write(std::ostream &out, int indent, CPPScope *scope) const; - - CPPTemplateScope *get_template_scope(); - virtual CPPTemplateScope *as_template_scope(); - -private: - bool - copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst, - CPPScope *global_scope) const; - - void handle_declaration(CPPDeclaration *decl, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr); - -public: - typedef std::vector Declarations; - Declarations _declarations; - - typedef std::map ExtensionTypes; - ExtensionTypes _structs; - ExtensionTypes _classes; - ExtensionTypes _unions; - ExtensionTypes _enums; - - typedef std::map Namespaces; - Namespaces _namespaces; - - typedef std::map Types; - Types _types; - typedef std::map Variables; - Variables _variables; - Variables _enum_values; - typedef std::map Functions; - Functions _functions; - typedef std::map Templates; - Templates _templates; - CPPNameComponent _name; - - typedef std::set Using; - Using _using; - -protected: - CPPScope *_parent_scope; - CPPStructType *_struct_type; - CPPVisibility _current_vis; - -private: - typedef std::map Instantiations; - Instantiations _instantiations; - - bool _is_fully_specified; - bool _fully_specified_known; - bool _is_fully_specified_recursive_protect; - bool _subst_decl_recursive_protect; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPScope &scope) { - scope.output(out, nullptr); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppSimpleType.cxx b/dtool/src/cppparser/cppSimpleType.cxx deleted file mode 100644 index 990a7cbaeab..00000000000 --- a/dtool/src/cppparser/cppSimpleType.cxx +++ /dev/null @@ -1,288 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppSimpleType.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppSimpleType.h" -#include "cppGlobals.h" - -/** - * - */ -CPPSimpleType:: -CPPSimpleType(CPPSimpleType::Type type, int flags) : - CPPType(CPPFile()), - _type(type), _flags(flags) -{ -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPSimpleType:: -is_tbd() const { - return (_type == T_unknown); -} - -/** - * Returns true if the type is a boolean, floating point or integral type. - */ -bool CPPSimpleType:: -is_arithmetic() const { - return (_type > T_unknown && _type < T_void); -} - -/** - * Returns true if the type is considered a fundamental type. - */ -bool CPPSimpleType:: -is_fundamental() const { - return (_type != T_unknown && _type != T_parameter && _type != T_auto && _type != T_va_list); -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPSimpleType:: -is_standard_layout() const { - return (_type != T_unknown && _type != T_parameter && _type != T_auto && _type != T_va_list); -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPSimpleType:: -is_trivial() const { - return (_type != T_unknown && _type != T_parameter && _type != T_auto && _type != T_va_list); -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPSimpleType:: -is_trivially_copyable() const { - return (_type != T_unknown && _type != T_parameter && _type != T_auto && _type != T_va_list); -} - -/** - * Returns true if the type can be constructed using the given argument. - */ -bool CPPSimpleType:: -is_constructible(const CPPType *given_type) const { - given_type = ((CPPType *)given_type)->remove_reference()->remove_cv(); - - const CPPSimpleType *simple_type = given_type->as_simple_type(); - if (simple_type == nullptr) { - return given_type->is_enum() && is_arithmetic(); - } else if (_type == T_nullptr) { - return simple_type->_type == T_nullptr; - } else if (_type == T_bool) { - return simple_type->is_arithmetic() || simple_type->_type == T_nullptr; - } else if (is_arithmetic()) { - return simple_type->is_arithmetic(); - } else { - return false; - } -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPSimpleType:: -is_default_constructible() const { - return (_type != T_void); -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPSimpleType:: -is_copy_constructible() const { - return (_type != T_void); -} - -/** - * Returns true if the type is copy-assignable. - */ -bool CPPSimpleType:: -is_copy_assignable() const { - return (_type != T_void); -} - -/** - * Returns true if the type is destructible. - */ -bool CPPSimpleType:: -is_destructible() const { - return (_type != T_void); -} - -/** - * Returns true if the type is a special parameter expression type. - * - * This sort of type is created to handle instance declarations that initially - * look like function prototypes. - */ -bool CPPSimpleType:: -is_parameter_expr() const { - return (_type == T_parameter); -} - -/** - * - */ -std::string CPPSimpleType:: -get_preferred_name() const { - // Simple types always prefer to use their native types. - return get_local_name(); -} - -/** - * - */ -void CPPSimpleType:: -output(std::ostream &out, int, CPPScope *, bool) const { - if (_flags & F_unsigned) { - out << "unsigned "; - } - - if (_flags & F_signed) { - out << "signed "; - } - - if ((_type == T_int && (_flags & F_longlong) != 0) && - !cpp_longlong_keyword.empty()) { - // It's a long long, and we have a specific long long type name. This is - // to output code for compilers that don't recognize "long long int". - out << cpp_longlong_keyword; - return; - } - - if (_flags & F_longlong) { - out << "long long "; - } else if (_flags & F_long) { - out << "long "; - } else if (_flags & F_short) { - out << "short "; - } - - switch (_type) { - case T_unknown: - out << "unknown"; - break; - - case T_bool: - out << "bool"; - break; - - case T_char: - out << "char"; - break; - - case T_wchar_t: - out << "wchar_t"; - break; - - case T_char8_t: - out << "char8_t"; - break; - - case T_char16_t: - out << "char16_t"; - break; - - case T_char32_t: - out << "char32_t"; - break; - - case T_int: - out << "int"; - break; - - case T_float: - out << "float"; - break; - - case T_double: - out << "double"; - break; - - case T_void: - out << "void"; - break; - - case T_nullptr: - out << "decltype(nullptr)"; - break; - - case T_parameter: - out << "parameter"; - break; - - case T_auto: - out << "auto"; - break; - - case T_va_list: - out << "__builtin_va_list"; - break; - - default: - out << "***invalid type***"; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPSimpleType:: -get_subtype() const { - return ST_simple; -} - -/** - * - */ -CPPSimpleType *CPPSimpleType:: -as_simple_type() { - return this; -} - - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPSimpleType:: -is_equal(const CPPDeclaration *other) const { - const CPPSimpleType *ot = ((CPPDeclaration *)other)->as_simple_type(); - assert(ot != nullptr); - - return _type == ot->_type && _flags == ot->_flags; -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPSimpleType:: -is_less(const CPPDeclaration *other) const { - const CPPSimpleType *ot = ((CPPDeclaration *)other)->as_simple_type(); - assert(ot != nullptr); - - if (_type != ot->_type) { - return _type < ot->_type; - } - return _flags < ot->_flags; -} diff --git a/dtool/src/cppparser/cppSimpleType.h b/dtool/src/cppparser/cppSimpleType.h deleted file mode 100644 index 70eb6155885..00000000000 --- a/dtool/src/cppparser/cppSimpleType.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppSimpleType.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPSIMPLETYPE_H -#define CPPSIMPLETYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" - -/** - * Represents a C++ fundamental type. - */ -class CPPSimpleType : public CPPType { -public: - enum Type { - T_unknown, - T_bool, - T_char, - T_wchar_t, - T_char8_t, - T_char16_t, - T_char32_t, - T_int, - T_float, - T_double, - T_void, - - // We need something to represent the type of nullptr so that we can - // return it from decltype(nullptr). Note that this is not the same as - // nullptr_t, which is a typedef of decltype(nullptr). - T_nullptr, - - // T_parameter is a special type which is assigned to expressions that are - // discovered where a formal parameter was expected. This is a special - // case for handling cases like this: int foo(0); which really means the - // same thing as: int foo = 0; but it initially looks like a function - // prototype. - T_parameter, - - // T_auto is also a special type that corresponds to the "auto" keyword - // used in a variable assignment. The type of it is automatically - // determined at a later stage based on the type of the expression that is - // assigned to it. - T_auto, - - // This is also a special built-in type. - T_va_list, - }; - - enum Flags { - F_long = 0x001, - F_longlong = 0x002, - F_short = 0x004, - F_unsigned = 0x008, - F_signed = 0x010, - }; - - CPPSimpleType(Type type, int flags = 0); - - Type _type; - int _flags; - - virtual bool is_tbd() const; - bool is_arithmetic() const; - virtual bool is_fundamental() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *type) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_copy_assignable() const; - virtual bool is_destructible() const; - virtual bool is_parameter_expr() const; - - virtual std::string get_preferred_name() const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPSimpleType *as_simple_type(); - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; -}; - -#endif diff --git a/dtool/src/cppparser/cppStructType.cxx b/dtool/src/cppparser/cppStructType.cxx deleted file mode 100644 index b2ce921e70f..00000000000 --- a/dtool/src/cppparser/cppStructType.cxx +++ /dev/null @@ -1,1546 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppStructType.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppStructType.h" -#include "cppTypedefType.h" -#include "cppReferenceType.h" -#include "cppScope.h" -#include "cppTypeProxy.h" -#include "cppTemplateScope.h" -#include "cppFunctionGroup.h" -#include "cppFunctionType.h" -#include "cppParameterList.h" -#include "cppTBDType.h" -#include "indent.h" -#include "cppParser.h" - -/** - * - */ -void CPPStructType::Base:: -output(std::ostream &out) const { - if (_is_virtual) { - out << "virtual "; - } - out << _vis << " " << *_base; -} - -/** - * - */ -CPPStructType:: -CPPStructType(CPPStructType::Type type, CPPIdentifier *ident, - CPPScope *current_scope, CPPScope *scope, - const CPPFile &file, CPPAttributeList attr) : - CPPExtensionType(type, ident, current_scope, file, std::move(attr)), - _scope(scope), - _final(false) -{ - _subst_decl_recursive_protect = false; - _incomplete = true; -} - -/** - * - */ -CPPStructType:: -CPPStructType(const CPPStructType ©) : - CPPExtensionType(copy), - _scope(copy._scope), - _incomplete(copy._incomplete), - _final(copy._final), - _derivation(copy._derivation) -{ - _subst_decl_recursive_protect = false; -} - -/** - * - */ -void CPPStructType:: -operator = (const CPPStructType ©) { - CPPExtensionType::operator = (copy); - _scope = copy._scope; - _incomplete = copy._incomplete; - _derivation = copy._derivation; - _final = copy._final; -} - -/** - * A handy function used while parsing to add a new base class to the list of - * classes (or structs) this class derives from. - */ -void CPPStructType:: -append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual) { - if (base != nullptr) { - // Unwrap any typedefs, since we can't inherit from a typedef. - CPPTypedefType *def = base->as_typedef_type(); - while (def != nullptr) { - base = def->_type; - def = base->as_typedef_type(); - } - - if (vis == V_unknown && base->as_extension_type() != nullptr) { - // Default visibility. - if (base->as_extension_type()->_type == T_class) { - vis = V_private; - } else { - vis = V_public; - } - } - - Base b; - b._base = base; - b._vis = vis; - b._is_virtual = is_virtual; - - _derivation.push_back(b); - } -} - -/** - * - */ -CPPScope *CPPStructType:: -get_scope() const { - return _scope; -} - -/** - * Returns true if this struct declaration is abstract, e.g. it contains or - * inherits at least one method that is pure virtual. - */ -bool CPPStructType:: -is_abstract() const { - VFunctions funcs; - get_pure_virtual_funcs(funcs); - return !funcs.empty(); -} - -/** - * Returns true if this struct declaration is a base class of the other given - * class, or the same class. - */ -bool CPPStructType:: -is_base_of(const CPPStructType *other) const { - if (this == other) { - return true; - } - Derivation::const_iterator di; - for (di = other->_derivation.begin(); di != other->_derivation.end(); ++di) { - const CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr && is_base_of(base)) { - return true; - } - } - return false; -} - -/** - * Returns true if this struct declaration defines no non-static data members - * other than bit-fields of size 0, no virtual functions, no virtual base - * classes, and no non-empty base classes, and is not a union. - */ -bool CPPStructType:: -is_empty() const { - if (_type == T_union) { - return false; - } - - if (check_virtual()) { - return false; - } - - // Make sure all base classes are empty and non-virtual. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if ((*di)._is_virtual || (base != nullptr && !base->is_empty())) { - return false; - } - } - - // Make sure there are no non-static data members. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - // Only members with a bit width of 0 are okay. - if (instance->_bit_width != 0) { - return false; - } - } - - return true; -} - -/** - * Returns true if this class or any of its base classes have virtual methods. - */ -bool CPPStructType:: -is_polymorphic() const { - if (_type == T_union) { - return false; - } - return check_virtual(); -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPStructType:: -is_standard_layout() const { - assert(_scope != nullptr); - - CPPVisibility member_vis = V_unknown; - - // Make sure all data members have the same vis and are standard layout. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - // Finally, check if the data member itself is standard layout. - assert(instance->_type != nullptr); - if (!instance->_type->is_standard_layout()) { - return false; - } - - if (member_vis == V_unknown) { - // The first non-static data member may not be a base class. - CPPStructType *struct_type = instance->_type->remove_cv()->as_struct_type(); - if (struct_type != nullptr && struct_type->is_base_of(this)) { - return false; - } - member_vis = instance->_vis; - - } else if (member_vis != instance->_vis) { - // All members need to have the same access control. - return false; - } - } - - // Make sure all base classes are standard-layout and non-virtual. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if ((*di)._is_virtual) { - return false; - } - - // If this class had instance members, all base classes need to be empty. - if (member_vis != V_unknown) { - if (!base->is_empty()) { - return false; - } - } else { - if (!base->is_standard_layout()) { - return false; - } - } - } - - // Make sure we have no virtual functions. - return !check_virtual(); -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPStructType:: -is_trivial() const { - // Make sure all base classes are trivial and non-virtual. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if ((*di)._is_virtual || (base != nullptr && !base->is_trivial())) { - return false; - } - } - - assert(_scope != nullptr); - - // Make sure all members are trivial. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - if (instance->_initializer != nullptr) { - // A member with an initializer means the default constructor would - // assign a value. This means the type can't be trivial. - return false; - } - - // Finally, check if the data member itself is non-trivial. - assert(instance->_type != nullptr); - if (!instance->_type->is_trivial()) { - return false; - } - } - - // Now look for functions that are virtual or con/destructors. - CPPScope::Functions::const_iterator fi; - for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) { - CPPFunctionGroup *fgroup = (*fi).second; - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) { - CPPInstance *inst = (*ii); - - if (inst->_storage_class & CPPInstance::SC_virtual) { - // Virtual functions are banned right off the bat. - return false; - } - - // The following checks don't apply for defaulted functions. - if (inst->_storage_class & CPPInstance::SC_defaulted) { - continue; - } - - assert(inst->_type != nullptr); - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if (ftype->_flags & (CPPFunctionType::F_destructor | - CPPFunctionType::F_move_constructor | - CPPFunctionType::F_copy_constructor)) { - // User-provided destructors and copy/move constructors are not - // trivial unless they are defaulted (and not virtual). - return false; - } - - if ((ftype->_flags & CPPFunctionType::F_constructor) != 0) { - if (ftype->_parameters->_parameters.size() == 0 && - !ftype->_parameters->_includes_ellipsis) { - // Same for the default constructor. - return false; - } - } - - if (fgroup->_name == "operator =") { - // Or assignment operators. - return false; - } - } - } - - // Finally, the class must be default-constructible. - return is_default_constructible(V_public); -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPStructType:: -is_trivially_copyable() const { - // Make sure all base classes are trivially copyable and non-virtual. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if ((*di)._is_virtual || (base != nullptr && !base->is_trivially_copyable())) { - return false; - } - } - - assert(_scope != nullptr); - - // Make sure all members are trivially copyable. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - assert(instance->_type != nullptr); - if (!instance->_type->is_trivially_copyable()) { - return false; - } - } - - // Now look for functions that are virtual or con/destructors. - CPPScope::Functions::const_iterator fi; - for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) { - CPPFunctionGroup *fgroup = (*fi).second; - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) { - CPPInstance *inst = (*ii); - - if (inst->_storage_class & CPPInstance::SC_virtual) { - // Virtual functions are banned right off the bat. - return false; - } - - // The following checks don't apply for defaulted functions. - if (inst->_storage_class & CPPInstance::SC_defaulted) { - continue; - } - - assert(inst->_type != nullptr); - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if (ftype->_flags & (CPPFunctionType::F_destructor | - CPPFunctionType::F_move_constructor | - CPPFunctionType::F_copy_constructor)) { - // User-provided destructors and copy/move constructors are not - // trivial unless they are defaulted (and not virtual). - return false; - } - - if (fgroup->_name == "operator =") { - // Or assignment operators. - return false; - } - } - } - - return true; -} - -/** - * Returns true if the type can be constructed using the given argument. - * This implementation is rudimentary, as it does not attempt to follow all of - * the implicit type conversion rules, but it is still useful. - */ -bool CPPStructType:: -is_constructible(const CPPType *given_type) const { - // Does the type match the copy constructor or move constructor? - CPPType *base_type = ((CPPType *)given_type)->remove_reference(); - if (is_equivalent(*base_type->remove_cv())) { - const CPPReferenceType *ref_type = given_type->as_reference_type(); - if (ref_type == nullptr || - ref_type->_value_category == CPPReferenceType::VC_rvalue) { - return is_move_constructible(V_public); - } else { - return is_copy_constructible(V_public); - } - } - - if (is_abstract()) { - return false; - } - - // Check for a different constructor. - CPPFunctionGroup *fgroup = get_constructor(); - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - assert(inst->_type != nullptr); - - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - CPPParameterList *params = ftype->_parameters; - if (params->_parameters.size() == 1 && !params->_includes_ellipsis) { - CPPType *param_type = params->_parameters[0]->_type->remove_reference(); - - if (!param_type->is_const() && base_type->is_const()) { - // Can't pass a const object to a function taking a non-const. - continue; - } - - // It's deleted, anyhow. - if ((inst->_storage_class & CPPInstance::SC_deleted) != 0) { - continue; - } - - if (param_type->is_equivalent(*base_type)) { - return true; - } - } - } - } - - return false; -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPStructType:: -is_default_constructible() const { - return is_default_constructible(V_public); -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPStructType:: -is_copy_constructible() const { - return is_copy_constructible(V_public); -} - -/** - * Returns true if the type is copy-assignable. - */ -bool CPPStructType:: -is_copy_assignable() const { - if (is_abstract()) { - return false; - } - return is_copy_assignable(V_public); -} - -/** - * Returns true if the type is destructible. - */ -bool CPPStructType:: -is_destructible() const { - return is_destructible(V_public); -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPStructType:: -is_default_constructible(CPPVisibility min_vis) const { - if (is_abstract()) { - return false; - } - - CPPInstance *constructor = get_default_constructor(); - if (constructor != nullptr) { - // It has a default constructor. - if (constructor->_vis > min_vis) { - // Inaccessible default constructor. - return false; - } - - if (constructor->_storage_class & CPPInstance::SC_deleted) { - // Deleted default constructor. - return false; - } - - return true; - } - - // Does it have constructors at all? If so, no implicit one is generated. - if (get_constructor() != nullptr) { - return false; - } - - // Implicit default constructor. Check if the implicit default constructor - // is deleted. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr) { - if (!base->is_default_constructible(V_protected)) { - return false; - } - } - } - - // Make sure all members are default-constructible or have default values. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - if (instance->_initializer != nullptr) { - // It has a default value. - continue; - } - - if (!instance->_type->is_default_constructible()) { - return false; - } - } - - return true; -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPStructType:: -is_copy_constructible(CPPVisibility min_vis) const { - if (is_abstract()) { - return false; - } - - CPPInstance *constructor = get_copy_constructor(); - if (constructor != nullptr) { - // It has a copy constructor. - if (constructor->_vis > min_vis) { - // Inaccessible copy constructor. - return false; - } - - if (constructor->_storage_class & CPPInstance::SC_deleted) { - // Deleted copy constructor. - return false; - } - - return true; - } - - if (get_move_constructor() != nullptr || - get_move_assignment_operator() != nullptr) { - // A user-declared move constructor or move assignment operator means that - // the implicitly-declared copy constructor is deleted. - return false; - } - - CPPInstance *destructor = get_destructor(); - if (destructor != nullptr) { - if (destructor->_vis > min_vis) { - // Inaccessible destructor. - return false; - } - - if (destructor->_storage_class & CPPInstance::SC_deleted) { - // Deleted destructor. - return false; - } - } - - // Implicit copy constructor. Check if the implicit copy constructor is - // deleted. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr) { - if (!base->is_copy_constructible(V_protected)) { - return false; - } - } - } - - // Make sure all members are copy-constructible. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - if (!instance->_type->is_copy_constructible()) { - return false; - } - } - - return true; -} - -/** - * Returns true if the type is move-constructible. - */ -bool CPPStructType:: -is_move_constructible(CPPVisibility min_vis) const { - CPPInstance *constructor = get_move_constructor(); - if (constructor != nullptr) { - // It has a user-declared move constructor. - if (constructor->_vis > min_vis) { - // Inaccessible move constructor. - return false; - } - - if (constructor->_storage_class & CPPInstance::SC_deleted) { - // It is deleted. - return false; - } - - if (is_abstract()) { - return false; - } - - return true; - } - - return is_copy_constructible(min_vis); -} - -/** - * Returns true if the type is copy-assignable, without checking whether the - * class is abstract. - */ -bool CPPStructType:: -is_copy_assignable(CPPVisibility min_vis) const { - CPPInstance *assignment_operator = get_copy_assignment_operator(); - if (assignment_operator != nullptr) { - // It has a copy assignment operator. - if (assignment_operator->_vis > min_vis) { - // Inaccessible copy assignment operator. - return false; - } - - if (assignment_operator->_storage_class & CPPInstance::SC_deleted) { - // Deleted copy assignment operator. - return false; - } - - // NB: if it's defaulted, it may still be deleted. - if ((assignment_operator->_storage_class & CPPInstance::SC_defaulted) == 0) { - return true; - } - } - - // Implicit copy assignment operator. Check if the implicit or defaulted - // copy assignment operator is deleted. - if (!assignment_operator && (get_move_constructor() || get_move_assignment_operator())) { - // It's not explicitly defaulted, and there is a move constructor or move - // assignment operator, so the implicitly-declared one is deleted. - return false; - } - - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr) { - if (!base->is_copy_assignable(V_protected)) { - return false; - } - } - } - - // Make sure all members are assignable. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - if (!instance->_type->is_copy_assignable()) { - // Const or reference member, can't do it. - return false; - } - } - - return true; -} - -/** - * Returns true if the type is move-assignable. - */ -bool CPPStructType:: -is_move_assignable(CPPVisibility min_vis) const { - CPPInstance *assignment_operator = get_move_assignment_operator(); - if (assignment_operator != nullptr) { - // It has a user-declared move assignment_operator. - if (assignment_operator->_vis > min_vis) { - // Inaccessible move assignment_operator. - return false; - } - - if (assignment_operator->_storage_class & CPPInstance::SC_deleted) { - // It is deleted. - return false; - } - - if (is_abstract()) { - return false; - } - - return true; - } - - return is_copy_assignable(min_vis); -} - -/** - * Returns true if the type is destructible. - */ -bool CPPStructType:: -is_destructible(CPPVisibility min_vis) const { - // Do we have an explicit destructor? - CPPInstance *destructor = get_destructor(); - if (destructor != nullptr) { - if (destructor->_vis > min_vis) { - // Yes, but it's inaccessible. - return false; - } - - if (destructor->_storage_class & CPPInstance::SC_deleted) { - // Yes, but it's explicitly been deleted. - return false; - } - - return true; - } - - // Make sure all base classes are destructible. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr && !base->is_destructible(V_protected)) { - return false; - } - } - - assert(_scope != nullptr); - - // Make sure all members are destructible. - CPPScope::Variables::const_iterator vi; - for (vi = _scope->_variables.begin(); vi != _scope->_variables.end(); ++vi) { - CPPInstance *instance = (*vi).second; - assert(instance != nullptr); - - if (instance->_storage_class & CPPInstance::SC_static) { - // Static members don't count. - continue; - } - - // If the data member is not destructible, no go. - assert(instance->_type != nullptr); - if (!instance->_type->is_destructible()) { - return false; - } - } - - return true; -} - -/** - * Returns true if variables of this type may be implicitly converted to - * the other type. - */ -bool CPPStructType:: -is_convertible_to(const CPPType *other) const { - if (CPPType::is_convertible_to(other)) { - return true; - } - - // Check all typecast operators to see whether we can cast to a type that is - // convertible to the other type. - CPPScope::Functions::const_iterator fi; - for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) { - CPPFunctionGroup *fgroup = (*fi).second; - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) { - CPPInstance *inst = (*ii); - - if (inst->_storage_class & (CPPInstance::SC_deleted | CPPInstance::SC_static | CPPInstance::SC_explicit)) { - // Exclude static/deleted/explicit methods. - continue; - } - - // Also, the instance needs to be publicly visible. - if (inst->_vis > V_public) { - continue; - } - - assert(inst->_type != nullptr); - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if (ftype->_return_type != nullptr && - (ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) { - // Yes, this is a typecast operator. Test using the return type. - if (ftype->_return_type->is_convertible_to(other)) { - return true; - } - } - } - } - - // Check whether any of the base classes are convertible. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr && (*di)._vis <= V_public && !base->is_convertible_to(other)) { - return true; - } - } - - return false; -} - -/** - * Ensures all functions are correctly marked with the "virtual" flag if they - * are truly virtual by virtue of inheritance, rather than simply being - * labeled virtual. - * - * This also sets the CPPInstance::SC_inherited_virtual flags on those virtual - * methods that override a virtual method defined in a parent class (as - * opposed to those that appear for this first time in this class). It is - * sometimes useful to know whether a given virtual method represents the - * first time that particular method appears. - * - * The return value is true if this class defines or inherits any virtual - * methods (and thus requires a virtual function pointer), or false otherwise. - */ -bool CPPStructType:: -check_virtual() const { - VFunctions funcs; - get_virtual_funcs(funcs); - return !funcs.empty(); -} - -/** - * Returns true if this class, or any of its base classes, has a virtual - * destructor. - */ -bool CPPStructType:: -has_virtual_destructor() const { - CPPInstance *destructor = get_destructor(); - if (destructor != nullptr) { - if (destructor->_storage_class & CPPInstance::SC_virtual) { - return true; - } - } - - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr && base->has_virtual_destructor()) { - return true; - } - } - - return false; -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPStructType:: -is_fully_specified() const { - if (_scope != nullptr && !_scope->is_fully_specified()) { - return false; - } - return CPPType::is_fully_specified(); -} - -/** - * Returns true if the type has not yet been fully specified, false if it has. - */ -bool CPPStructType:: -is_incomplete() const { - return _incomplete; -} - -/** - * Returns the constructor defined for the struct type, if any, or NULL if no - * constructor is found. - */ -CPPFunctionGroup *CPPStructType:: -get_constructor() const { - // Just look for the function with the same name as the class. - CPPScope::Functions::const_iterator fi; - fi = _scope->_functions.find(get_simple_name()); - if (fi != _scope->_functions.end()) { - return fi->second; - } else { - return nullptr; - } -} - -/** - * Returns the default constructor defined for the struct type, or NULL if - * there is no user-declared constructor that takes 0 arguments. - */ -CPPInstance *CPPStructType:: -get_default_constructor() const { - CPPFunctionGroup *fgroup = get_constructor(); - if (fgroup == nullptr) { - return nullptr; - } - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - assert(inst->_type != nullptr); - - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if (ftype->_parameters->_parameters.size() == 0 || - ftype->_parameters->_parameters.front()->_initializer != nullptr) { - // It takes 0 parameters (or all parameters have default values). - return inst; - } - } - - return nullptr; -} - -/** - * Returns the copy constructor defined for the struct type, or NULL if no - * user-declared copy constructor exists. - */ -CPPInstance *CPPStructType:: -get_copy_constructor() const { - CPPFunctionGroup *fgroup = get_constructor(); - if (fgroup == nullptr) { - return nullptr; - } - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - assert(inst->_type != nullptr); - - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if ((ftype->_flags & CPPFunctionType::F_copy_constructor) != 0) { - return inst; - } - } - - return nullptr; -} - -/** - * Returns the move constructor defined for the struct type, or NULL if no - * user-declared move constructor exists. - */ -CPPInstance *CPPStructType:: -get_move_constructor() const { - CPPFunctionGroup *fgroup = get_constructor(); - if (fgroup == nullptr) { - return nullptr; - } - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - assert(inst->_type != nullptr); - - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if ((ftype->_flags & CPPFunctionType::F_move_constructor) != 0) { - return inst; - } - } - - return nullptr; -} - -/** - * Returns the assignment operator defined for the struct type, if any, or - * NULL if no assignment operator is found. - */ -CPPFunctionGroup *CPPStructType:: -get_assignment_operator() const { - // Just look for the function with the name "operator =" - CPPScope::Functions::const_iterator fi; - fi = _scope->_functions.find("operator ="); - if (fi != _scope->_functions.end()) { - return fi->second; - } else { - return nullptr; - } -} - -/** - * Returns the copy assignment operator defined for the struct type, or NULL - * if no user-declared copy assignment operator exists. - */ -CPPInstance *CPPStructType:: -get_copy_assignment_operator() const { - CPPFunctionGroup *fgroup = get_assignment_operator(); - if (fgroup == nullptr) { - return nullptr; - } - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - assert(inst->_type != nullptr); - - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if ((ftype->_flags & CPPFunctionType::F_copy_assignment_operator) != 0) { - return inst; - } - } - - return nullptr; -} - -/** - * Returns the move assignment operator defined for the struct type, or NULL - * if no user-declared move assignment operator exists. - */ -CPPInstance *CPPStructType:: -get_move_assignment_operator() const { - CPPFunctionGroup *fgroup = get_assignment_operator(); - if (fgroup == nullptr) { - return nullptr; - } - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - assert(inst->_type != nullptr); - - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if ((ftype->_flags & CPPFunctionType::F_move_assignment_operator) != 0) { - return inst; - } - } - - return nullptr; -} - -/** - * Returns the destructor defined for the struct type, if any, or NULL if no - * user-declared destructor is found. - */ -CPPInstance *CPPStructType:: -get_destructor() const { - // Iterate through all the functions that begin with '~' until we find one - // that claims to be a destructor. In theory, there should only be one such - // function. - CPPScope::Functions::const_iterator fi; - fi = _scope->_functions.lower_bound("~"); - - while (fi != _scope->_functions.end() && - (*fi).first[0] == '~') { - CPPFunctionGroup *fgroup = (*fi).second; - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - assert(inst->_type != nullptr); - - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - - if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) { - return inst; - } - } - ++fi; - } - - return nullptr; -} - -/** - * - */ -CPPDeclaration *CPPStructType:: -instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - - // I *think* this assertion is no longer valid. Who knows. - // assert(!_incomplete); - - if (_scope == nullptr) { - if (error_sink != nullptr) { - error_sink->warning("Ignoring template parameters for class " + - get_local_name()); - } - return (CPPDeclaration *)this; - } - - CPPScope *scope = - _scope->instantiate(actual_params, current_scope, global_scope, error_sink); - - if (scope->get_struct_type()->get_scope() != scope) { - // Hmm, this type seems to be not completely defined. We must be in the - // middle of recursively instantiating the scope. Thus, we don't yet know - // what its associated struct type will be. - - // Postpone the evaluation of this type. - CPPIdentifier *ident = new CPPIdentifier(get_fully_scoped_name(), _file); - - return CPPType::new_type(new CPPTBDType(ident)); - } - - CPPType *result = scope->get_struct_type(); - result = CPPType::new_type(result); - if (result != (CPPType *)this) { - // This really means the method ought to be non-const. But I'm too lazy - // to propagate this change all the way back right now, so this hack is - // here. - ((CPPStructType *)this)->_instantiations.insert(result); - } - return result; -} - -/** - * - */ -CPPDeclaration *CPPStructType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - SubstDecl::const_iterator si = subst.find(this); - if (si != subst.end()) { - assert((*si).second != nullptr); - return (*si).second; - } - - if (_incomplete) { - // We haven't finished defining the class yet. - return this; - } - - if (_subst_decl_recursive_protect) { - // We're already executing this block; we'll have to return a proxy to the - // type which we'll define later. - CPPTypeProxy *proxy = new CPPTypeProxy; - _proxies.push_back(proxy); - assert(proxy != nullptr); - return proxy; - } - _subst_decl_recursive_protect = true; - - CPPStructType *rep = new CPPStructType(*this); - - if (_ident != nullptr) { - rep->_ident = - _ident->substitute_decl(subst, current_scope, global_scope); - } - - if (_scope != nullptr) { - rep->_scope = - _scope->substitute_decl(subst, current_scope, global_scope); - if (rep->_scope != _scope) { - rep->_scope->set_struct_type(rep); - - // If we just instantiated a template scope, write the template - // parameters into our identifier. - CPPScope *pscope = rep->_scope->get_parent_scope(); - - if (pscope != nullptr && - pscope->_name.has_templ()) { - - // If the struct name didn't have an explicit template reference - // before, now it does. - if (_ident != nullptr && !_ident->_names.empty() && !_ident->_names.back().has_templ()) { - if (rep->is_template()) { - rep->_template_scope = nullptr; - CPPNameComponent nc(get_simple_name()); - nc.set_templ(pscope->_name.get_templ()); - rep->_ident = new CPPIdentifier(nc, _file); - } - } - } - } - } - - bool unchanged = - (rep->_ident == _ident && rep->_scope == _scope); - - for (int i = 0; i < (int)_derivation.size(); ++i) { - rep->_derivation[i]._base = - _derivation[i]._base->substitute_decl(subst, current_scope, global_scope)->as_type(); - if (rep->_derivation[i]._base != _derivation[i]._base) { - unchanged = false; - } - } - - if (unchanged) { - delete rep; - rep = this; - } - - subst.insert(SubstDecl::value_type(this, rep)); - - _subst_decl_recursive_protect = false; - // Now fill in all the proxies we created for our recursive references. - Proxies::iterator pi; - for (pi = _proxies.begin(); pi != _proxies.end(); ++pi) { - (*pi)->_actual_type = rep; - } - - assert(rep != nullptr); - rep = CPPType::new_type(rep)->as_struct_type(); - assert(rep != nullptr); - if (rep != this) { - _instantiations.insert(rep); - } - return rep; -} - -/** - * - */ -void CPPStructType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - if (!complete && _ident != nullptr) { - // If we have a name, use it. - if (cppparser_output_class_keyword) { - out << _type << " "; - } - out << _ident->get_local_name(scope); - - if (is_template()) { - CPPTemplateScope *tscope = get_template_scope(); - tscope->_parameters.output(out, scope); - } - - } else { - if (is_template()) { - get_template_scope()->_parameters.write_formal(out, scope); - indent(out, indent_level); - } - out << _type; - - if (!_attributes.is_empty()) { - out << " " << _attributes; - } - - if (_ident != nullptr) { - out << " " << _ident->get_local_name(scope); - } - - if (_final) { - out << " final"; - } - - // Show any derivation we may have - if (!_derivation.empty()) { - Derivation::const_iterator di = _derivation.begin(); - out << " : " << *di; - ++di; - while (di != _derivation.end()) { - out << ", " << *di; - ++di; - } - } - - out << " {\n"; - _scope->write(out, indent_level + 2, _scope); - indent(out, indent_level) << "}"; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPStructType:: -get_subtype() const { - return ST_struct; -} - -/** - * - */ -CPPStructType *CPPStructType:: -as_struct_type() { - return this; -} - - -/** - * Fills funcs up with a list of all the virtual function declarations (pure- - * virtual or otherwise) defined at or above this class. This is used to - * determine which functions in a given class are actually virtual, since a - * function is virtual whose parent class holds a virtual function by the same - * name, whether or not it is actually declared virtual in the derived class. - */ -void CPPStructType:: -get_virtual_funcs(VFunctions &funcs) const { - // First, get all the virtual funcs from our parents. - Derivation::const_iterator di; - for (di = _derivation.begin(); di != _derivation.end(); ++di) { - VFunctions vf; - CPPStructType *base = (*di)._base->as_struct_type(); - if (base != nullptr) { - base->get_virtual_funcs(vf); - funcs.splice(funcs.end(), vf); - } - } - - // Now look for matching functions in this class that we can now infer are - // virtual. - VFunctions::iterator vfi, vfnext; - vfi = funcs.begin(); - while (vfi != funcs.end()) { - vfnext = vfi; - ++vfnext; - - CPPInstance *inst = (*vfi); - assert(inst->_type != nullptr); - CPPFunctionType *base_ftype = inst->_type->as_function_type(); - assert(base_ftype != nullptr); - - if (inst->_storage_class & CPPInstance::SC_deleted) { - // Ignore deleted functions. - - } else if ((base_ftype->_flags & CPPFunctionType::F_destructor) != 0) { - // Match destructor-for-destructor; don't try to match destructors up by - // name. - CPPInstance *destructor = get_destructor(); - if (destructor != nullptr) { - // It's a match! This destructor is virtual. - funcs.erase(vfi); - destructor->_storage_class |= - (CPPInstance::SC_virtual | CPPInstance::SC_inherited_virtual); - } - - } else { - // Non-destructors we can try to match up by name. - std::string fname = inst->get_local_name(); - CPPScope::Functions::const_iterator fi; - fi = _scope->_functions.find(fname); - - if (fi != _scope->_functions.end()) { - CPPFunctionGroup *fgroup = (*fi).second; - - // Look for a matching function amid this group. - bool match_found = false; - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end() && !match_found; - ++ii) { - CPPInstance *new_inst = (*ii); - assert(new_inst->_type != nullptr); - - CPPFunctionType *new_ftype = new_inst->_type->as_function_type(); - assert(new_ftype != nullptr); - - if (new_ftype->match_virtual_override(*base_ftype)) { - // It's a match! We now know it's virtual. Erase this function - // from the list, so we can add it back in below. - funcs.erase(vfi); - match_found = true; - - // In fact, it's not only definitely virtual, but it's *inherited* - // virtual, which means only that the interface is defined in some - // parent class. Sometimes this is useful to know. - new_inst->_storage_class |= - (CPPInstance::SC_virtual | CPPInstance::SC_inherited_virtual); - } - } - } - } - vfi = vfnext; - } - - // Finally, look for more virtual function definitions. - CPPScope::Functions::const_iterator fi; - for (fi = _scope->_functions.begin(); - fi != _scope->_functions.end(); - ++fi) { - CPPFunctionGroup *fgroup = (*fi).second; - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - if ((inst->_storage_class & CPPInstance::SC_virtual) != 0 && - (inst->_storage_class & CPPInstance::SC_deleted) == 0) { - // Here's a virtual function. - funcs.push_back(inst); - } - } - } -} - -/** - * Fills funcs up with a list of all the pure virtual function declarations - * defined at or above this class that have not been given definitions. - */ -void CPPStructType:: -get_pure_virtual_funcs(VFunctions &funcs) const { - // First, get all the virtual functions. - VFunctions vfuncs; - get_virtual_funcs(vfuncs); - - // Now traverse the list, getting out those functions that are pure virtual. - VFunctions::iterator vfi; - for (vfi = vfuncs.begin(); vfi != vfuncs.end(); ++vfi) { - CPPInstance *inst = (*vfi); - if ((inst->_storage_class & CPPInstance::SC_pure_virtual) != 0) { - funcs.push_back(inst); - } - } -} - -/** - * Called by CPPDeclaration to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPStructType:: -is_equal(const CPPDeclaration *other) const { - return CPPDeclaration::is_equal(other); - /* - const CPPStructType *ot = ((CPPDeclaration *)other)->as_struct_type(); - assert(ot != NULL); - - return this == ot || - (get_fully_scoped_name() == ot->get_fully_scoped_name()); - */ -} - -/** - * Called by CPPDeclaration to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPStructType:: -is_less(const CPPDeclaration *other) const { - return CPPDeclaration::is_less(other); - /* - const CPPStructType *ot = ((CPPDeclaration *)other)->as_struct_type(); - assert(ot != NULL); - - if (this == ot) { - return false; - } - - return - (get_fully_scoped_name() < ot->get_fully_scoped_name()); - */ -} diff --git a/dtool/src/cppparser/cppStructType.h b/dtool/src/cppparser/cppStructType.h deleted file mode 100644 index c3eb8f1bae7..00000000000 --- a/dtool/src/cppparser/cppStructType.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppStructType.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPSTRUCTTYPE_H -#define CPPSTRUCTTYPE_H - -#include "dtoolbase.h" - -#include "cppIdentifier.h" -#include "cppExtensionType.h" -#include "cppFunctionGroup.h" -#include "cppVisibility.h" - -#include -#include - -class CPPScope; -class CPPTypeProxy; - -/** - * - */ -class CPPStructType : public CPPExtensionType { -public: - CPPStructType(Type type, CPPIdentifier *ident, - CPPScope *current_scope, - CPPScope *scope, - const CPPFile &file, - CPPAttributeList attr = CPPAttributeList()); - CPPStructType(const CPPStructType ©); - void operator = (const CPPStructType ©); - - void append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual); - - CPPScope *get_scope() const; - - bool is_abstract() const; - bool is_base_of(const CPPStructType *other) const; - bool is_empty() const; - bool is_polymorphic() const; - bool check_virtual() const; - bool has_virtual_destructor() const; - virtual bool is_fully_specified() const; - virtual bool is_incomplete() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *arg_type) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_copy_assignable() const; - virtual bool is_destructible() const; - bool is_default_constructible(CPPVisibility min_vis) const; - bool is_copy_constructible(CPPVisibility min_vis) const; - bool is_move_constructible(CPPVisibility min_vis = V_public) const; - bool is_copy_assignable(CPPVisibility min_vis) const; - bool is_move_assignable(CPPVisibility min_vis = V_public) const; - bool is_destructible(CPPVisibility min_vis) const; - virtual bool is_convertible_to(const CPPType *other) const; - - inline bool is_final() const { return _final; } - - CPPFunctionGroup *get_constructor() const; - CPPInstance *get_default_constructor() const; - CPPInstance *get_copy_constructor() const; - CPPInstance *get_move_constructor() const; - CPPFunctionGroup *get_assignment_operator() const; - CPPInstance *get_copy_assignment_operator() const; - CPPInstance *get_move_assignment_operator() const; - CPPInstance *get_destructor() const; - - virtual CPPDeclaration * - instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPStructType *as_struct_type(); - - CPPScope *_scope; - bool _incomplete; - bool _final; - - class Base { - public: - void output(std::ostream &out) const; - - CPPType *_base; - CPPVisibility _vis; - bool _is_virtual; - }; - - typedef std::vector Derivation; - Derivation _derivation; - - typedef std::list VFunctions; - void get_virtual_funcs(VFunctions &funcs) const; - void get_pure_virtual_funcs(VFunctions &funcs) const; - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; - - bool _subst_decl_recursive_protect; - typedef std::vector Proxies; - Proxies _proxies; -}; - -inline std::ostream &operator << (std::ostream &out, const CPPStructType::Base &base) { - base.output(out); - return out; -} - - -#endif diff --git a/dtool/src/cppparser/cppTBDType.cxx b/dtool/src/cppparser/cppTBDType.cxx deleted file mode 100644 index 5c583453ca4..00000000000 --- a/dtool/src/cppparser/cppTBDType.cxx +++ /dev/null @@ -1,175 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTBDType.cxx - * @author drose - * @date 1999-11-05 - */ - -#include "cppTBDType.h" -#include "cppIdentifier.h" - -#include "cppSimpleType.h" - -/** - * - */ -CPPTBDType:: -CPPTBDType(CPPIdentifier *ident) : - CPPType(CPPFile()), - _ident(ident) -{ - _subst_decl_recursive_protect = false; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPTBDType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPType *type = _ident->find_type(current_scope, global_scope); - if (type != nullptr) { - return type; - } - return this; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPTBDType:: -is_tbd() const { - return true; -} - -/** - * Returns a fundametal one-word name for the type. This name will not - * include any scoping operators or template parameters, so it may not be a - * compilable reference to the type. - */ -std::string CPPTBDType:: -get_simple_name() const { - return _ident->get_simple_name(); -} - -/** - * Returns the compilable, correct name for this type within the indicated - * scope. If the scope is NULL, within the scope the type is declared in. - */ -std::string CPPTBDType:: -get_local_name(CPPScope *scope) const { - return _ident->get_local_name(scope); -} - -/** - * Returns the compilable, correct name for the type, with completely explicit - * scoping. - */ -std::string CPPTBDType:: -get_fully_scoped_name() const { - return _ident->get_fully_scoped_name(); -} - -/** - * - */ -CPPDeclaration *CPPTBDType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - CPPDeclaration *top = - CPPDeclaration::substitute_decl(subst, current_scope, global_scope); - if (top != this) { - return top; - } - - // Protect against recursive entry into this function block. I know it's - // ugly--have you got any better suggestions? - if (_subst_decl_recursive_protect) { - // We're already executing this block. - return this; - } - _subst_decl_recursive_protect = true; - - CPPTBDType *rep = new CPPTBDType(*this); - rep->_ident = _ident->substitute_decl(subst, current_scope, global_scope); - - if (rep->_ident == _ident) { - delete rep; - rep = this; - } - - rep = CPPType::new_type(rep)->as_tbd_type(); - assert(rep != nullptr); - - CPPType *result = rep; - - // Can we now define it as a real type? - CPPType *type = rep->_ident->find_type(current_scope, global_scope, subst); - if (type != nullptr) { - result = type; - } - - subst.insert(SubstDecl::value_type(this, result)); - - _subst_decl_recursive_protect = false; - return result; -} - -/** - * - */ -void CPPTBDType:: -output(std::ostream &out, int, CPPScope *, bool) const { - out /* << "typename " */ << *_ident; -} - -/** - * - */ -CPPDeclaration::SubType CPPTBDType:: -get_subtype() const { - return ST_tbd; -} - -/** - * - */ -CPPTBDType *CPPTBDType:: -as_tbd_type() { - return this; -} - - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPTBDType:: -is_equal(const CPPDeclaration *other) const { - const CPPTBDType *ot = ((CPPDeclaration *)other)->as_tbd_type(); - assert(ot != nullptr); - - return (*_ident) == (*ot->_ident); -} - - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPTBDType:: -is_less(const CPPDeclaration *other) const { - const CPPTBDType *ot = ((CPPDeclaration *)other)->as_tbd_type(); - assert(ot != nullptr); - - return (*_ident) < (*ot->_ident); -} diff --git a/dtool/src/cppparser/cppTBDType.h b/dtool/src/cppparser/cppTBDType.h deleted file mode 100644 index beec68adebc..00000000000 --- a/dtool/src/cppparser/cppTBDType.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTBDType.h - * @author drose - * @date 1999-11-05 - */ - -#ifndef CPPTBDTYPE_H -#define CPPTBDTYPE_H - -#include "dtoolbase.h" - -#include "cppType.h" - -class CPPIdentifier; - -/** - * This represents a type whose exact meaning is still to-be-determined. It - * happens when a typename is referenced in a template class (especially using - * the 'typename' keyword) but the actual type cannot be known until the class - * is instantiated. - */ -class CPPTBDType : public CPPType { -public: - CPPTBDType(CPPIdentifier *ident); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_tbd() const; - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPTBDType *as_tbd_type(); - - CPPIdentifier *_ident; - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; - -private: - bool _subst_decl_recursive_protect; -}; - -#endif diff --git a/dtool/src/cppparser/cppTemplateParameterList.cxx b/dtool/src/cppparser/cppTemplateParameterList.cxx deleted file mode 100644 index fd129677114..00000000000 --- a/dtool/src/cppparser/cppTemplateParameterList.cxx +++ /dev/null @@ -1,234 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTemplateParameterList.cxx - * @author drose - * @date 1999-10-28 - */ - -#include "cppTemplateParameterList.h" -#include "cppClassTemplateParameter.h" -#include "cppInstance.h" -#include "cppExpression.h" - -/** - * - */ -CPPTemplateParameterList:: -CPPTemplateParameterList() { -} - -/** - * - */ -std::string CPPTemplateParameterList:: -get_string() const { - std::ostringstream strname; - strname << "< " << *this << " >"; - return strname.str(); -} - -/** - * Matches up the actual parameters one-to-one with the formal parameters they - * are replacing, so the template may be instantiated by swapping out each - * occurrence of a template standin type with its appropriate replacement. - */ -void CPPTemplateParameterList:: -build_subst_decl(const CPPTemplateParameterList &formal_params, - CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) const { - - Parameters::const_iterator pfi, pai; - for (pfi = formal_params._parameters.begin(), pai = _parameters.begin(); - pfi != formal_params._parameters.end() && pai != _parameters.end(); - ++pfi, ++pai) { - CPPDeclaration *formal = *pfi; - CPPDeclaration *actual = *pai; - - if (actual->as_type()) { - actual = actual->as_type()->resolve_type(current_scope, global_scope); - } - - if (!(formal == actual)) { - subst.insert(CPPDeclaration::SubstDecl::value_type(formal, actual)); - } - } - - // Fill in the default template parameters. - while (pfi != formal_params._parameters.end()) { - CPPDeclaration *decl = (*pfi); - if (decl->as_instance()) { - // A value template parameter. Its default is an expression. - CPPInstance *inst = decl->as_instance(); - if (inst->_initializer != nullptr) { - CPPDeclaration *decl = - inst->_initializer->substitute_decl(subst, current_scope, - global_scope); - if (!(*decl == *inst)) { - subst.insert(CPPDeclaration::SubstDecl::value_type - (inst, decl)); - } - } - } else if (decl->as_class_template_parameter()) { - // A class template parameter. - CPPClassTemplateParameter *cparam = decl->as_class_template_parameter(); - if (cparam->_default_type != nullptr) { - CPPDeclaration *decl = - cparam->_default_type->substitute_decl(subst, current_scope, - global_scope); - if (!(*cparam == *decl)) { - subst.insert(CPPDeclaration::SubstDecl::value_type - (cparam, decl)); - } - } - } - ++pfi; - } -} - -/** - * This function returns true if all the parameters in the list are real - * expressions or classes, and not types yet to-be-determined or template - * parameter types. That is, this returns true for a normal template - * instantiation, and false for a template instantiation based on template - * parameters that have not yet been specified. - */ -bool CPPTemplateParameterList:: -is_fully_specified() const { - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (!_parameters[i]->is_fully_specified()) { - return false; - } - } - return true; -} - -/** - * Returns true if any type within the parameter list is a CPPTBDType and thus - * isn't fully determined right now. - */ -bool CPPTemplateParameterList:: -is_tbd() const { - for (int i = 0; i < (int)_parameters.size(); ++i) { - CPPType *type = _parameters[i]->as_type(); - if (type != nullptr && - (type->is_tbd() || type->as_class_template_parameter() != nullptr)) { - return true; - } - CPPExpression *expr = _parameters[i]->as_expression(); - if (expr != nullptr && expr->is_tbd()) { - return true; - } - } - return false; -} - -/** - * - */ -bool CPPTemplateParameterList:: -operator == (const CPPTemplateParameterList &other) const { - if (_parameters.size() != other._parameters.size()) { - return false; - } - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (*_parameters[i] != *other._parameters[i]) { - return false; - } - } - return true; -} - -/** - * - */ -bool CPPTemplateParameterList:: -operator != (const CPPTemplateParameterList &other) const { - return !(*this == other); -} - -/** - * - */ -bool CPPTemplateParameterList:: -operator < (const CPPTemplateParameterList &other) const { - if (_parameters.size() != other._parameters.size()) { - return _parameters.size() < other._parameters.size(); - } - for (int i = 0; i < (int)_parameters.size(); ++i) { - if (*_parameters[i] != *other._parameters[i]) { - return *_parameters[i] < *other._parameters[i]; - } - } - return false; -} - -/** - * - */ -CPPTemplateParameterList *CPPTemplateParameterList:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - CPPTemplateParameterList *rep = new CPPTemplateParameterList(*this); - - bool anything_changed = false; - for (int i = 0; i < (int)rep->_parameters.size(); ++i) { - rep->_parameters[i] = - _parameters[i]->substitute_decl(subst, current_scope, global_scope); - if (rep->_parameters[i] != _parameters[i]) { - anything_changed = true; - } - } - - if (!anything_changed) { - delete rep; - rep = this; - } - - return rep; -} - -/** - * - */ -void CPPTemplateParameterList:: -output(std::ostream &out, CPPScope *scope) const { - if (!_parameters.empty()) { - Parameters::const_iterator pi = _parameters.begin(); - (*pi)->output(out, 0, scope, false); - - ++pi; - while (pi != _parameters.end()) { - out << ", "; - (*pi)->output(out, 0, scope, false); - ++pi; - } - } -} - -/** - * Writes the list as a set of formal parameters for a template scope. - * Includes the keyword "template" and the angle brackets, as well as the - * trailing newline. - */ -void CPPTemplateParameterList:: -write_formal(std::ostream &out, CPPScope *scope) const { - out << "template<"; - if (!_parameters.empty()) { - Parameters::const_iterator pi = _parameters.begin(); - (*pi)->output(out, 0, scope, true); - - ++pi; - while (pi != _parameters.end()) { - out << ", "; - (*pi)->output(out, 0, scope, true); - ++pi; - } - } - out << ">\n"; -} diff --git a/dtool/src/cppparser/cppTemplateParameterList.h b/dtool/src/cppparser/cppTemplateParameterList.h deleted file mode 100644 index d47f8fdd9ec..00000000000 --- a/dtool/src/cppparser/cppTemplateParameterList.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTemplateParameterList.h - * @author drose - * @date 1999-10-28 - */ - -#ifndef CPPTEMPLATEPARAMETERLIST_H -#define CPPTEMPLATEPARAMETERLIST_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" - -#include -#include - -class CPPScope; - -/** - * This class serves to store the parameter list for a template function or - * class, both for the formal parameter list (given when the template is - * defined) and for the actual parameter list (given when the template is - * instantiated). - */ -class CPPTemplateParameterList { -public: - CPPTemplateParameterList(); - - std::string get_string() const; - void build_subst_decl(const CPPTemplateParameterList &formal_params, - CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) const; - - bool is_fully_specified() const; - bool is_tbd() const; - - bool operator == (const CPPTemplateParameterList &other) const; - bool operator != (const CPPTemplateParameterList &other) const; - bool operator < (const CPPTemplateParameterList &other) const; - - CPPTemplateParameterList *substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - void output(std::ostream &out, CPPScope *scope) const; - void write_formal(std::ostream &out, CPPScope *scope) const; - - typedef std::vector Parameters; - Parameters _parameters; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPTemplateParameterList &plist) { - plist.output(out, nullptr); - return out; -} - - -// This is an STL function object used to uniquely order -// CPPTemplateParameterList pointers. -class CPPTPLCompare { -public: - bool operator () (const CPPTemplateParameterList *a, - const CPPTemplateParameterList *b) const { - return (*a) < (*b); - } -}; - -#endif diff --git a/dtool/src/cppparser/cppTemplateScope.cxx b/dtool/src/cppparser/cppTemplateScope.cxx deleted file mode 100644 index a71c1760058..00000000000 --- a/dtool/src/cppparser/cppTemplateScope.cxx +++ /dev/null @@ -1,172 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTemplateScope.cxx - * @author drose - * @date 1999-10-28 - */ - -#include "cppTemplateScope.h" -#include "cppExtensionType.h" -#include "cppClassTemplateParameter.h" -#include "cppIdentifier.h" -#include "cppTypedefType.h" - -using std::string; - -/** - * - */ -CPPTemplateScope:: -CPPTemplateScope(CPPScope *parent_scope) : - CPPScope(parent_scope, CPPNameComponent("template"), V_public) -{ -} - - -/** - * - */ -void CPPTemplateScope:: -add_declaration(CPPDeclaration *decl, CPPScope *global_scope, - CPPPreprocessor *preprocessor, - const cppyyltype &pos) { - decl->_template_scope = this; - assert(_parent_scope != nullptr); - _parent_scope->add_declaration(decl, global_scope, preprocessor, pos); -} - -/** - * - */ -void CPPTemplateScope:: -add_enum_value(CPPInstance *inst) { - inst->_template_scope = this; - assert(_parent_scope != nullptr); - _parent_scope->add_enum_value(inst); -} - -/** - * - */ -void CPPTemplateScope:: -define_typedef_type(CPPTypedefType *type, CPPPreprocessor *error_sink) { - type->_template_scope = this; - assert(_parent_scope != nullptr); - _parent_scope->define_typedef_type(type, error_sink); -} - -/** - * - */ -void CPPTemplateScope:: -define_extension_type(CPPExtensionType *type, CPPPreprocessor *error_sink) { - type->_template_scope = this; - assert(_parent_scope != nullptr); - _parent_scope->define_extension_type(type, error_sink); -} - -/** - * - */ -void CPPTemplateScope:: -define_namespace(CPPNamespace *scope) { - assert(_parent_scope != nullptr); - _parent_scope->define_namespace(scope); -} - -/** - * - */ -void CPPTemplateScope:: -add_using(CPPUsing *using_decl, CPPScope *global_scope, - CPPPreprocessor *error_sink) { - assert(_parent_scope != nullptr); - _parent_scope->add_using(using_decl, global_scope, error_sink); -} - -/** - * - */ -void CPPTemplateScope:: -add_template_parameter(CPPDeclaration *param) { - _parameters._parameters.push_back(param); - CPPClassTemplateParameter *cl = param->as_class_template_parameter(); - if (cl != nullptr) { - // Create an implicit typedef for this class parameter. - if (cl->_ident != nullptr) { - string name = cl->_ident->get_local_name(); - _types[name] = cl; - } - } - - CPPInstance *inst = param->as_instance(); - if (inst != nullptr) { - // Register the variable for this value parameter. - string name = inst->get_local_name(); - if (!name.empty()) { - _variables[name] = inst; - } - } -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPTemplateScope:: -is_fully_specified() const { - return false; -} - -/** - * - */ -string CPPTemplateScope:: -get_simple_name() const { - assert(_parent_scope != nullptr); - return _parent_scope->get_simple_name(); -} - -/** - * - */ -string CPPTemplateScope:: -get_local_name(CPPScope *scope) const { - assert(_parent_scope != nullptr); - return _parent_scope->get_local_name(scope); -} - -/** - * - */ -string CPPTemplateScope:: -get_fully_scoped_name() const { - assert(_parent_scope != nullptr); - return _parent_scope->get_fully_scoped_name(); -} - -/** - * - */ -void CPPTemplateScope:: -output(std::ostream &out, CPPScope *scope) const { - CPPScope::output(out, scope); - out << "< "; - _parameters.output(out, scope); - out << " >"; -} - -/** - * - */ -CPPTemplateScope *CPPTemplateScope:: -as_template_scope() { - return this; -} diff --git a/dtool/src/cppparser/cppTemplateScope.h b/dtool/src/cppparser/cppTemplateScope.h deleted file mode 100644 index 8a30b686a54..00000000000 --- a/dtool/src/cppparser/cppTemplateScope.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTemplateScope.h - * @author drose - * @date 1999-10-28 - */ - -#ifndef CPPTEMPLATESCOPE_H -#define CPPTEMPLATESCOPE_H - -#include "dtoolbase.h" - -#include "cppScope.h" -#include "cppTemplateParameterList.h" - -/** - * This is an implicit scope that is created following the appearance of a - * "template" or some such line in a C++ file. It simply - * defines the template parameters. - */ -class CPPTemplateScope : public CPPScope { -public: - CPPTemplateScope(CPPScope *parent_scope); - - void add_template_parameter(CPPDeclaration *param); - - virtual void add_declaration(CPPDeclaration *decl, CPPScope *global_scope, - CPPPreprocessor *preprocessor, - const cppyyltype &pos); - virtual void add_enum_value(CPPInstance *inst); - virtual void define_typedef_type(CPPTypedefType *type, - CPPPreprocessor *error_sink = nullptr); - virtual void define_extension_type(CPPExtensionType *type, - CPPPreprocessor *error_sink = nullptr); - virtual void define_namespace(CPPNamespace *scope); - virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr); - - virtual bool is_fully_specified() const; - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - - virtual void output(std::ostream &out, CPPScope *scope) const; - - virtual CPPTemplateScope *as_template_scope(); - - CPPTemplateParameterList _parameters; -}; - -#endif diff --git a/dtool/src/cppparser/cppToken.cxx b/dtool/src/cppparser/cppToken.cxx deleted file mode 100644 index daa624f17f4..00000000000 --- a/dtool/src/cppparser/cppToken.cxx +++ /dev/null @@ -1,1327 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppToken.cxx - * @author drose - * @date 1999-10-22 - */ - -#include "cppToken.h" -#include "cppExpression.h" -#include "cppIdentifier.h" -#include "cppBison.h" -#include "pdtoa.h" - -#include - -/** - * - */ -CPPToken:: -CPPToken(int token, int line_number, int col_number, - const CPPFile &file, const std::string &str, - const YYSTYPE &lval) : - _token(token), _lval(lval) -{ - _lval.str = str; - _lloc.first_line = line_number; - _lloc.first_column = col_number; - _lloc.last_line = line_number; - _lloc.last_column = col_number; - _lloc.file = file; -} - -/** - * - */ -CPPToken:: -CPPToken(int token, const YYLTYPE &loc, const std::string &str, const YYSTYPE &val) : - _token(token), _lval(val), _lloc(loc) -{ - _lval.str = str; -} - -/** - * A named constructor for the token returned when the end of file has been - * reached. - */ -CPPToken CPPToken:: -eof() { - return CPPToken(0); -} - -/** - * Returns true if this is the EOF token. - */ -bool CPPToken:: -is_eof() const { - return _token == 0; -} - -/** - * - */ -void CPPToken:: -output(std::ostream &out) const { - switch (_token) { - case REAL: - out << "REAL " << _lval.u.real; - break; - - case INTEGER: - out << "INTEGER " << _lval.u.integer; - break; - - case CHAR_TOK: - out << "CHAR_TOK " << _lval.u.integer << " = " << _lval.str; - break; - - case SIMPLE_STRING: - out << "SIMPLE_STRING " << _lval.str; - break; - - case STRING_LITERAL: - out << "STRING_LITERAL " << *_lval.u.expr; - break; - - case SIMPLE_IDENTIFIER: - out << "SIMPLE_IDENTIFIER " << _lval.str; - break; - - case IDENTIFIER: - out << "IDENTIFIER " << *_lval.u.identifier; - break; - - case TYPENAME_IDENTIFIER: - out << "TYPENAME_IDENTIFIER " << *_lval.u.identifier; - break; - - case SCOPING: - out << "SCOPING " << *_lval.u.identifier << "::"; - break; - - case TYPEDEFNAME: - out << "TYPEDEFNAME " << _lval.str; - break; - - case ELLIPSIS: - out << "ELLIPSIS"; - break; - - case OROR: - out << "OROR"; - break; - - case ANDAND: - out << "ANDAND"; - break; - - case EQCOMPARE: - out << "EQCOMPARE"; - break; - - case NECOMPARE: - out << "NECOMPARE"; - break; - - case LECOMPARE: - out << "LECOMPARE"; - break; - - case GECOMPARE: - out << "GECOMPARE"; - break; - - case LSHIFT: - out << "LSHIFT"; - break; - - case RSHIFT: - out << "RSHIFT"; - break; - - case POINTSAT_STAR: - out << "POINTSAT_STAR"; - break; - - case DOT_STAR: - out << "DOT_STAR"; - break; - - case UNARY_NOT: - out << "UNARY_NOT"; - break; - - case UNARY_MINUS: - out << "UNARY_MINUS"; - break; - - case UNARY_PLUS: - out << "UNARY_PLUS"; - break; - - case UNARY_NEGATE: - out << "UNARY_NEGATE"; - break; - - case UNARY_STAR: - out << "UNARY_STAR"; - break; - - case UNARY_REF: - out << "UNARY_REF"; - break; - - case POINTSAT: - out << "POINTSAT"; - break; - - case SCOPE: - out << "SCOPE"; - break; - - case PLUSPLUS: - out << "PLUSPLUS"; - break; - - case MINUSMINUS: - out << "MINUSMINUS"; - break; - - case TIMESEQUAL: - out << "TIMESEQUAL"; - break; - - case DIVIDEEQUAL: - out << "DIVIDEEQUAL"; - break; - - case MODEQUAL: - out << "MODEQUAL"; - break; - - case PLUSEQUAL: - out << "PLUSEQUAL"; - break; - - case MINUSEQUAL: - out << "MINUSEQUAL"; - break; - - case OREQUAL: - out << "OREQUAL"; - break; - - case ANDEQUAL: - out << "ANDEQUAL"; - break; - - case XOREQUAL: - out << "XOREQUAL"; - break; - - case LSHIFTEQUAL: - out << "LSHIFTEQUAL"; - break; - - case RSHIFTEQUAL: - out << "RSHIFTEQUAL"; - break; - - case ATTR_LEFT: - out << "ATTR_LEFT"; - break; - - case ATTR_RIGHT: - out << "ATTR_RIGHT"; - break; - - case KW_ALIGNAS: - out << "KW_ALIGNAS"; - break; - - case KW_ALIGNOF: - out << "KW_ALIGNOF"; - break; - - case KW_AUTO: - out << "KW_AUTO"; - break; - - case KW_BEGIN_PUBLISH: - out << "KW_BEGIN_PUBLISH"; - break; - - case KW_BLOCKING: - out << "KW_BLOCKING"; - break; - - case KW_BOOL: - out << "KW_BOOL"; - break; - - case KW_BUILTIN_VA_LIST: - out << "KW_BUILTIN_VA_LIST"; - break; - - case KW_CATCH: - out << "KW_CATCH"; - break; - - case KW_CHAR: - out << "KW_CHAR"; - break; - - case KW_CHAR8_T: - out << "KW_CHAR8_T"; - break; - - case KW_CHAR16_T: - out << "KW_CHAR16_T"; - break; - - case KW_CHAR32_T: - out << "KW_CHAR32_T"; - break; - - case KW_CLASS: - out << "KW_CLASS"; - break; - - case KW_CONST: - out << "KW_CONST"; - break; - - case KW_CONSTEVAL: - out << "KW_CONSTEVAL"; - break; - - case KW_CONSTEXPR: - out << "KW_CONSTEXPR"; - break; - - case KW_CONSTINIT: - out << "KW_CONSTINIT"; - break; - - case KW_DECLTYPE: - out << "KW_DECLTYPE"; - break; - - case KW_DEFAULT: - out << "KW_DECLTYPE"; - break; - - case KW_DELETE: - out << "KW_DELETE"; - break; - - case KW_DOUBLE: - out << "KW_DOUBLE"; - break; - - case KW_DYNAMIC_CAST: - out << "KW_DYNAMIC_CAST"; - break; - - case KW_ELSE: - out << "KW_ELSE"; - break; - - case KW_ENUM: - out << "KW_ENUM"; - break; - - case KW_EXPLICIT: - out << "KW_EXPLICIT"; - break; - - case KW_EXPLICIT_LPAREN: - out << "KW_EXPLICIT_LPAREN"; - break; - - case KW_EXTENSION: - out << "KW_EXTENSION"; - break; - - case KW_EXTERN: - out << "KW_EXTERN"; - break; - - case KW_FALSE: - out << "KW_FALSE"; - break; - - case KW_FINAL: - out << "KW_FINAL"; - break; - - case KW_FLOAT: - out << "KW_FLOAT"; - break; - - case KW_FRIEND: - out << "KW_FRIEND"; - break; - - case KW_FOR: - out << "KW_FOR"; - break; - - case KW_GOTO: - out << "KW_GOTO"; - break; - - case KW_HAS_VIRTUAL_DESTRUCTOR: - out << "KW_HAS_VIRTUAL_DESTRUCTOR"; - break; - - case KW_IF: - out << "KW_IF"; - break; - - case KW_INLINE: - out << "KW_INLINE"; - break; - - case KW_INT: - out << "KW_INT"; - break; - - case KW_IS_ABSTRACT: - out << "KW_IS_ABSTRACT"; - break; - - case KW_IS_BASE_OF: - out << "KW_IS_BASE_OF"; - break; - - case KW_IS_CLASS: - out << "KW_IS_CLASS"; - break; - - case KW_IS_CONSTRUCTIBLE: - out << "KW_IS_CONSTRUCTIBLE"; - break; - - case KW_IS_CONVERTIBLE_TO: - out << "KW_IS_CONVERTIBLE_TO"; - break; - - case KW_IS_DESTRUCTIBLE: - out << "KW_IS_DESTRUCTIBLE"; - break; - - case KW_IS_EMPTY: - out << "KW_IS_EMPTY"; - break; - - case KW_IS_ENUM: - out << "KW_IS_ENUM"; - break; - - case KW_IS_FINAL: - out << "KW_IS_FINAL"; - break; - - case KW_IS_FUNDAMENTAL: - out << "KW_IS_FUNDAMENTAL"; - break; - - case KW_IS_POD: - out << "KW_IS_POD"; - break; - - case KW_IS_POLYMORPHIC: - out << "KW_IS_POLYMORPHIC"; - break; - - case KW_IS_STANDARD_LAYOUT: - out << "KW_IS_STANDARD_LAYOUT"; - break; - - case KW_IS_TRIVIAL: - out << "KW_IS_TRIVIAL"; - break; - - case KW_IS_TRIVIALLY_COPYABLE: - out << "KW_IS_TRIVIALLY_COPYABLE"; - break; - - case KW_IS_UNION: - out << "KW_IS_UNION"; - break; - - case KW_LONG: - out << "KW_LONG"; - break; - - case KW_MAKE_MAP_KEYS_SEQ: - out << "KW_MAKE_MAP_KEYS_SEQ"; - break; - - case KW_MAKE_MAP_PROPERTY: - out << "KW_MAKE_MAP_PROPERTY"; - break; - - case KW_MAKE_PROPERTY: - out << "KW_MAKE_PROPERTY"; - break; - - case KW_MAKE_PROPERTY2: - out << "KW_MAKE_PROPERTY2"; - break; - - case KW_MAKE_SEQ: - out << "KW_MAKE_SEQ"; - break; - - case KW_MAKE_SEQ_PROPERTY: - out << "KW_MAKE_SEQ_PROPERTY"; - break; - - case KW_MUTABLE: - out << "KW_MUTABLE"; - break; - - case KW_NAMESPACE: - out << "KW_NAMESPACE"; - break; - - case KW_NEW: - out << "KW_NEW"; - break; - - case KW_NOEXCEPT: - out << "KW_NOEXCEPT"; - break; - - case KW_NOEXCEPT_LPAREN: - out << "KW_NOEXCEPT_LPAREN"; - break; - - case KW_NULLPTR: - out << "KW_NULLPTR"; - break; - - case KW_OPERATOR: - if (_lval.u.identifier != nullptr) { - out << *_lval.u.identifier << "::"; - } - out << "KW_OPERATOR"; - break; - - case KW_OVERRIDE: - out << "KW_OVERRIDE"; - break; - - case KW_PRIVATE: - out << "KW_PRIVATE"; - break; - - case KW_PROTECTED: - out << "KW_PROTECTED"; - break; - - case KW_PUBLIC: - out << "KW_PUBLIC"; - break; - - case KW_PUBLISHED: - out << "KW_PUBLISHED"; - break; - - case KW_REGISTER: - out << "KW_REGISTER"; - break; - - case KW_REINTERPRET_CAST: - out << "KW_REINTERPRET_CAST"; - break; - - case KW_RESTRICT: - out << "KW_RESTRICT"; - break; - - case KW_RETURN: - out << "KW_RETURN"; - break; - - case KW_SHORT: - out << "KW_SHORT"; - break; - - case KW_SIGNED: - out << "KW_SIGNED"; - break; - - case KW_SIZEOF: - out << "KW_SIZEOF"; - break; - - case KW_STATIC: - out << "KW_STATIC"; - break; - - case KW_STATIC_ASSERT: - out << "KW_STATIC_ASSERT"; - break; - - case KW_STATIC_CAST: - out << "KW_STATIC_CAST"; - break; - - case KW_STRUCT: - out << "KW_STRUCT"; - break; - - case KW_TEMPLATE: - out << "KW_TEMPLATE"; - break; - - case KW_THREAD_LOCAL: - out << "KW_THREAD_LOCAL"; - break; - - case KW_THROW: - out << "KW_THROW"; - break; - - case KW_TRUE: - out << "KW_TRUE"; - break; - - case KW_TRY: - out << "KW_TRY"; - break; - - case KW_TYPEDEF: - out << "KW_TYPEDEF"; - break; - - case KW_TYPEID: - out << "KW_TYPEID"; - break; - - case KW_TYPENAME: - out << "KW_TYPENAME"; - break; - - case KW_UNDERLYING_TYPE: - out << "KW_UNDERLYING_TYPE"; - break; - - case KW_USING: - out << "KW_USING"; - break; - - case KW_UNION: - out << "KW_UNION"; - break; - - case KW_UNSIGNED: - out << "KW_UNSIGNED"; - break; - - case KW_VIRTUAL: - out << "KW_VIRTUAL"; - break; - - case KW_VOID: - out << "KW_VOID"; - break; - - case KW_VOLATILE: - out << "KW_VOLATILE"; - break; - - case KW_WCHAR_T: - out << "KW_WCHAR_T"; - break; - - case KW_WHILE: - out << "KW_WHILE"; - break; - - case START_CPP: - out << "START_CPP"; - break; - - case START_CONST_EXPR: - out << "START_CONST_EXPR"; - break; - - case START_TYPE: - out << "START_TYPE"; - break; - - default: - if (_token < 128 && isprint(_token)) { - out << "'" << (char)_token << "'"; - } else { - out << "token " << _token << "\n"; - } - } -} - -/** - * - */ -void CPPToken:: -output_code(std::ostream &out) const { - switch (_token) { - case REAL: - { - char buffer[128]; - pdtoa(_lval.u.real, buffer); - out << buffer; - } - break; - - case INTEGER: - out << _lval.u.integer; - break; - - case CHAR_TOK: - case SIMPLE_STRING: - out << (_token == CHAR_TOK ? '\'' : '"'); - for (char c : _lval.str) { - switch (c) { - case '\n': - out << "\\n"; - break; - - case '\t': - out << "\\t"; - break; - - case '\r': - out << "\\r"; - break; - - case '\a': - out << "\\a"; - break; - - case '\b': - out << "\\b"; - break; - - case '\v': - out << "\\v"; - break; - - case '\f': - out << "\\f"; - break; - - case '\'': - out << (_token == CHAR_TOK ? "\\\'" : "'"); - break; - - case '"': - out << (_token == CHAR_TOK ? "\"" : "\\\""); - break; - - case '\\': - out << "\\\\"; - break; - - default: - if (isprint(c)) { - out << c; - } else { - out << '\\' << std::oct << std::setw(3) << std::setfill('0') << (int)(c) - << std::dec << std::setw(0); - } - break; - } - } - out << (_token == CHAR_TOK ? '\'' : '"'); - break; - - case STRING_LITERAL: - out << *_lval.u.expr; - break; - - case SIMPLE_IDENTIFIER: - out << _lval.str; - break; - - case IDENTIFIER: - out << *_lval.u.identifier; - break; - - case TYPENAME_IDENTIFIER: - out << *_lval.u.identifier; - break; - - case SCOPING: - out << *_lval.u.identifier << "::"; - break; - - case TYPEDEFNAME: - out << _lval.str; - break; - - case ELLIPSIS: - out << "..."; - break; - - case OROR: - out << "||"; - break; - - case ANDAND: - out << "&&"; - break; - - case EQCOMPARE: - out << "=="; - break; - - case NECOMPARE: - out << "!="; - break; - - case LECOMPARE: - out << "<="; - break; - - case GECOMPARE: - out << ">="; - break; - - case LSHIFT: - out << "<<"; - break; - - case RSHIFT: - out << ">>"; - break; - - case POINTSAT_STAR: - out << "->*"; - break; - - case DOT_STAR: - out << ".*"; - break; - - case UNARY_NOT: - out << "!"; - break; - - case UNARY_MINUS: - out << "-"; - break; - - case UNARY_PLUS: - out << "+"; - break; - - case UNARY_NEGATE: - out << "~"; - break; - - case UNARY_STAR: - out << "*"; - break; - - case UNARY_REF: - out << "&"; - break; - - case POINTSAT: - out << "->"; - break; - - case SCOPE: - out << "::"; - break; - - case PLUSPLUS: - out << "++"; - break; - - case MINUSMINUS: - out << "--"; - break; - - case TIMESEQUAL: - out << "*="; - break; - - case DIVIDEEQUAL: - out << "/="; - break; - - case MODEQUAL: - out << "%="; - break; - - case PLUSEQUAL: - out << "+="; - break; - - case MINUSEQUAL: - out << "-="; - break; - - case OREQUAL: - out << "|="; - break; - - case ANDEQUAL: - out << "&="; - break; - - case XOREQUAL: - out << "^="; - break; - - case LSHIFTEQUAL: - out << "<<="; - break; - - case RSHIFTEQUAL: - out << ">>="; - break; - - case ATTR_LEFT: - out << "[["; - break; - - case ATTR_RIGHT: - out << "]]"; - break; - - case KW_ALIGNAS: - out << "alignas"; - break; - - case KW_ALIGNOF: - out << "alignof"; - break; - - case KW_AUTO: - out << "auto"; - break; - - case KW_BEGIN_PUBLISH: - out << "__begin_publish"; - break; - - case KW_BLOCKING: - out << "__blocking"; - break; - - case KW_BOOL: - out << "bool"; - break; - - case KW_BUILTIN_VA_LIST: - out << "__builtin_va_list"; - break; - - case KW_CATCH: - out << "catch"; - break; - - case KW_CHAR: - out << "char"; - break; - - case KW_CHAR8_T: - out << "char8_t"; - break; - - case KW_CHAR16_T: - out << "char16_t"; - break; - - case KW_CHAR32_T: - out << "char32_t"; - break; - - case KW_CLASS: - out << "class"; - break; - - case KW_CONST: - out << "const"; - break; - - case KW_CONSTEVAL: - out << "consteval"; - break; - - case KW_CONSTEXPR: - out << "constexpr"; - break; - - case KW_CONSTINIT: - out << "constinit"; - break; - - case KW_CONST_CAST: - out << "const_cast"; - break; - - case KW_DECLTYPE: - out << "decltype"; - break; - - case KW_DEFAULT: - out << "default"; - break; - - case KW_DELETE: - out << "delete"; - break; - - case KW_DOUBLE: - out << "double"; - break; - - case KW_DYNAMIC_CAST: - out << "dynamic_cast"; - break; - - case KW_ELSE: - out << "else"; - break; - - case KW_ENUM: - out << "enum"; - break; - - case KW_EXPLICIT: - out << "explicit"; - break; - - case KW_EXPLICIT_LPAREN: - out << "explicit("; - break; - - case KW_EXTENSION: - out << "__extension"; - break; - - case KW_EXTERN: - out << "extern"; - break; - - case KW_FALSE: - out << "false"; - break; - - case KW_FINAL: - out << "final"; - break; - - case KW_FLOAT: - out << "float"; - break; - - case KW_FRIEND: - out << "friend"; - break; - - case KW_FOR: - out << "for"; - break; - - case KW_GOTO: - out << "goto"; - break; - - case KW_HAS_VIRTUAL_DESTRUCTOR: - out << "__has_virtual_destructor"; - break; - - case KW_IF: - out << "if"; - break; - - case KW_INLINE: - out << "inline"; - break; - - case KW_INT: - out << "int"; - break; - - case KW_IS_ABSTRACT: - out << "__is_abstract"; - break; - - case KW_IS_BASE_OF: - out << "__is_base_of"; - break; - - case KW_IS_CLASS: - out << "__is_class"; - break; - - case KW_IS_CONSTRUCTIBLE: - out << "__is_constructible"; - break; - - case KW_IS_CONVERTIBLE_TO: - out << "__is_convertible_to"; - break; - - case KW_IS_DESTRUCTIBLE: - out << "__is_destructible"; - break; - - case KW_IS_EMPTY: - out << "__is_empty"; - break; - - case KW_IS_ENUM: - out << "__is_enum"; - break; - - case KW_IS_FINAL: - out << "__is_final"; - break; - - case KW_IS_FUNDAMENTAL: - out << "__is_fundamental"; - break; - - case KW_IS_POD: - out << "__is_pod"; - break; - - case KW_IS_POLYMORPHIC: - out << "__is_polymorphic"; - break; - - case KW_IS_STANDARD_LAYOUT: - out << "__is_standard_layout"; - break; - - case KW_IS_TRIVIAL: - out << "__is_trivial"; - break; - - case KW_IS_TRIVIALLY_COPYABLE: - out << "__is_trivially_copyable"; - break; - - case KW_IS_UNION: - out << "__is_union"; - break; - - case KW_LONG: - out << "long"; - break; - - case KW_MAKE_MAP_KEYS_SEQ: - out << "__make_map_keys_seq"; - break; - - case KW_MAKE_MAP_PROPERTY: - out << "__make_map_property"; - break; - - case KW_MAKE_PROPERTY: - out << "__make_property"; - break; - - case KW_MAKE_PROPERTY2: - out << "__make_property2"; - break; - - case KW_MAKE_SEQ: - out << "__make_seq"; - break; - - case KW_MAKE_SEQ_PROPERTY: - out << "__make_seq_property"; - break; - - case KW_MUTABLE: - out << "mutable"; - break; - - case KW_NAMESPACE: - out << "namespace"; - break; - - case KW_NEW: - out << "new"; - break; - - case KW_NOEXCEPT: - out << "noexcept"; - break; - - case KW_NOEXCEPT_LPAREN: - out << "noexcept("; - break; - - case KW_NULLPTR: - out << "nullptr"; - break; - - case KW_OPERATOR: - if (_lval.u.identifier != nullptr) { - out << *_lval.u.identifier << "::"; - } - out << "operator"; - break; - - case KW_OVERRIDE: - out << "override"; - break; - - case KW_PRIVATE: - out << "private"; - break; - - case KW_PROTECTED: - out << "protected"; - break; - - case KW_PUBLIC: - out << "public"; - break; - - case KW_PUBLISHED: - out << "__published"; - break; - - case KW_REGISTER: - out << "register"; - break; - - case KW_REINTERPRET_CAST: - out << "reinterpret_cast"; - break; - - case KW_RESTRICT: - out << "__restrict"; - break; - - case KW_RETURN: - out << "return"; - break; - - case KW_SHORT: - out << "short"; - break; - - case KW_SIGNED: - out << "signed"; - break; - - case KW_SIZEOF: - out << "sizeof"; - break; - - case KW_STATIC: - out << "static"; - break; - - case KW_STATIC_ASSERT: - out << "static_assert"; - break; - - case KW_STATIC_CAST: - out << "static_cast"; - break; - - case KW_STRUCT: - out << "struct"; - break; - - case KW_TEMPLATE: - out << "template"; - break; - - case KW_THREAD_LOCAL: - out << "thread_local"; - break; - - case KW_THROW: - out << "throw"; - break; - - case KW_TRUE: - out << "true"; - break; - - case KW_TRY: - out << "try"; - break; - - case KW_TYPEDEF: - out << "typedef"; - break; - - case KW_TYPEID: - out << "typeid"; - break; - - case KW_TYPENAME: - out << "typename"; - break; - - case KW_UNDERLYING_TYPE: - out << "__underlying_type"; - break; - - case KW_USING: - out << "using"; - break; - - case KW_UNION: - out << "union"; - break; - - case KW_UNSIGNED: - out << "unsigned"; - break; - - case KW_VIRTUAL: - out << "virtual"; - break; - - case KW_VOID: - out << "void"; - break; - - case KW_VOLATILE: - out << "volatile"; - break; - - case KW_WCHAR_T: - out << "wchar_t"; - break; - - case KW_WHILE: - out << "while"; - break; - - case START_CPP: - case START_CONST_EXPR: - case START_TYPE: - break; - - default: - if (_token < 128 && isprint(_token)) { - out << (char)_token; - } else { - out << "\n"; - } - } -} diff --git a/dtool/src/cppparser/cppToken.h b/dtool/src/cppparser/cppToken.h deleted file mode 100644 index 89ced98800a..00000000000 --- a/dtool/src/cppparser/cppToken.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppToken.h - * @author drose - * @date 1999-10-22 - */ - -#ifndef CPPTOKEN_H -#define CPPTOKEN_H - -#include "dtoolbase.h" - -#include "cppBisonDefs.h" - -/** - * - */ -class CPPToken { -public: - CPPToken(int token, int line_number = 0, int col_number = 0, - const CPPFile &file = CPPFile(""), - const std::string &str = std::string(), - const YYSTYPE &lval = YYSTYPE()); - CPPToken(int token, const YYLTYPE &loc, - const std::string &str = std::string(), - const YYSTYPE &lval = YYSTYPE()); - - static CPPToken eof(); - bool is_eof() const; - - void output(std::ostream &out) const; - void output_code(std::ostream &out) const; - - int _token; - YYSTYPE _lval; - YYLTYPE _lloc; -}; - -inline std::ostream &operator << (std::ostream &out, const CPPToken &token) { - token.output(out); - return out; -} - - -#endif diff --git a/dtool/src/cppparser/cppType.cxx b/dtool/src/cppparser/cppType.cxx deleted file mode 100644 index fcc593bbde2..00000000000 --- a/dtool/src/cppparser/cppType.cxx +++ /dev/null @@ -1,535 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppType.cxx - * @author drose - * @date 1999-10-19 - */ - -#include "cppType.h" -#include "cppConstType.h" -#include "cppPointerType.h" -#include "cppReferenceType.h" -#include "cppStructType.h" -#include "cppTypedefType.h" -#include "cppExtensionType.h" -#include - -using std::string; - -CPPType::Types CPPType::_types; -CPPType::PreferredNames CPPType::_preferred_names; -CPPType::AltNames CPPType::_alt_names; - -bool CPPTypeCompare:: -operator () (CPPType *a, CPPType *b) const { - return (*a) < (*b); -} - -/** - * - */ -CPPType:: -CPPType(const CPPFile &file) : - CPPDeclaration(file) -{ - _declaration = nullptr; - - // This is set true by interrogate when the "forcetype" keyword is used. - _forcetype = false; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPType:: -resolve_type(CPPScope *, CPPScope *) { - return this; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPType:: -is_tbd() const { - return false; -} - -/** - * Returns true if the type is considered a fundamental type. - */ -bool CPPType:: -is_fundamental() const { - return false; -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPType:: -is_standard_layout() const { - return false; -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPType:: -is_trivial() const { - return false; -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPType:: -is_trivially_copyable() const { - return false; -} - -/** - * Returns true if the type can be constructed using the given argument. - */ -bool CPPType:: -is_constructible(const CPPType *given_type) const { - return false; -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPType:: -is_default_constructible() const { - return false; -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPType:: -is_copy_constructible() const { - return false; -} - -/** - * Returns true if the type is copy-assignable. - */ -bool CPPType:: -is_copy_assignable() const { - return false; -} - -/** - * Returns true if the type is destructible. - */ -bool CPPType:: -is_destructible() const { - return !is_incomplete(); -} - -/** - * Returns true if the type is a special parameter expression type. - * - * This sort of type is created to handle instance declarations that initially - * look like function prototypes. - */ -bool CPPType:: -is_parameter_expr() const { - return false; -} - -/** - * Returns true if this is an enum type, or a typedef to an enum type. - */ -bool CPPType:: -is_enum() const { - const CPPTypedefType *td_type = as_typedef_type(); - if (td_type != nullptr) { - return td_type->_type->is_enum(); - } - const CPPExtensionType *ext_type = as_extension_type(); - if (ext_type != nullptr) { - return ext_type->_type == CPPExtensionType::T_enum || - ext_type->_type == CPPExtensionType::T_enum_struct || - ext_type->_type == CPPExtensionType::T_enum_class; - } - return false; -} - -/** - * Returns true if this is a const type, or a typedef to a const type. - */ -bool CPPType:: -is_const() const { - const CPPTypedefType *td_type = as_typedef_type(); - if (td_type != nullptr) { - return td_type->_type->is_const(); - } - return get_subtype() == ST_const; -} - -/** - * Returns true if this is a reference type, or a typedef to a reference type. - */ -bool CPPType:: -is_reference() const { - const CPPTypedefType *td_type = as_typedef_type(); - if (td_type != nullptr) { - return td_type->_type->is_reference(); - } - return get_subtype() == ST_reference; -} - -/** - * Returns true if this is an unqualified or cv-qualified pointer type, or a - * typedef to one. - */ -bool CPPType:: -is_pointer() const { - const CPPTypedefType *td_type = as_typedef_type(); - if (td_type != nullptr) { - return td_type->_type->is_pointer(); - } - const CPPConstType *const_type = as_const_type(); - if (const_type != nullptr) { - return const_type->_wrapped_around->is_pointer(); - } - return get_subtype() == ST_pointer; -} - -/** - * Returns the type with any const qualifier stripped off. Will follow - * typedefs, but only if necessary. - */ -CPPType *CPPType:: -remove_const() { - const CPPTypedefType *td_type = as_typedef_type(); - if (td_type != nullptr) { - CPPType *unwrapped = td_type->_type->remove_const(); - if (unwrapped != td_type->_type) { - return unwrapped; - } else { - return this; - } - } - const CPPConstType *const_type = as_const_type(); - if (const_type != nullptr) { - return const_type->_wrapped_around->remove_const(); - } - return this; -} - -/** - * Returns the type with any reference stripped off. - */ -CPPType *CPPType:: -remove_reference() { - const CPPTypedefType *td_type = as_typedef_type(); - if (td_type != nullptr) { - CPPType *unwrapped = td_type->_type->remove_reference(); - if (unwrapped != td_type->_type) { - return unwrapped; - } else { - return this; - } - } - const CPPReferenceType *ref_type = as_reference_type(); - if (ref_type != nullptr) { - return ref_type->_pointing_at; - } - return this; -} - -/** - * Returns the type with any pointer and cv-qualifiers stripped off. - */ -CPPType *CPPType:: -remove_pointer() { - switch (get_subtype()) { - case ST_typedef: - { - const CPPTypedefType *td_type = as_typedef_type(); - CPPType *unwrapped = td_type->_type->remove_pointer(); - if (unwrapped != td_type->_type) { - return unwrapped; - } else { - return this; - } - } - - case ST_pointer: - return ((const CPPPointerType *)this)->_pointing_at; - - case ST_const: - return ((const CPPConstType *)this)->_wrapped_around->remove_pointer(); - - default: - return this; - } -} - -/** - * Returns true if the type has even been typedef'ed and therefore has a - * simple name available to stand for it. Extension types are all implicitly - * typedef'ed on declaration. - */ -bool CPPType:: -has_typedef_name() const { - return !_typedefs.empty(); -} - -/** - * Returns a string that can be used to name the type, if has_typedef_name() - * returned true. This will be the first typedef name applied to the type. - */ -string CPPType:: -get_typedef_name(CPPScope *scope) const { - if (_typedefs.empty()) { - return string(); - } else { - return _typedefs.front()->get_local_name(scope); - } -} - -/** - * Returns a fundametal one-word name for the type. This name will not - * include any scoping operators or template parameters, so it may not be a - * compilable reference to the type. - */ -string CPPType:: -get_simple_name() const { - return get_local_name(); -} - -/** - * Returns the compilable, correct name for this type within the indicated - * scope. If the scope is NULL, within the scope the type is declared in. - */ -string CPPType:: -get_local_name(CPPScope *scope) const { - std::ostringstream ostrm; - output(ostrm, 0, scope, false); - return ostrm.str(); -} - -/** - * Returns the compilable, correct name for the type, with completely explicit - * scoping. - */ -string CPPType:: -get_fully_scoped_name() const { - return get_local_name(); -} - -/** - * Returns the best name to use for the type from a programmer's point of - * view. This will typically be a typedef name if one is available, or the - * full C++ name if it is not. The typedef may or may not be visible within - * the current scope, so this type name may not be compilable. - */ -string CPPType:: -get_preferred_name() const { - string preferred_name = get_preferred_name_for(this); - if (!preferred_name.empty()) { - return preferred_name; - } - return get_local_name(); -} - -/** - * Returns the number of "alternate" names for this type. The alternate names - * are alternate typedef names. This list might be empty, or it might be - * long. One of these names may or may not be the same as the "preferred" - * name. - */ -int CPPType:: -get_num_alt_names() const { - // We do a lookup based on the type's name, instead of its pointer, so we - // can resolve different expansions of the same type. - string tname = this->get_fully_scoped_name(); - - if (!tname.empty()) { - AltNames::const_iterator ai; - ai = _alt_names.find(tname); - if (ai != _alt_names.end()) { - const Names &names = (*ai).second; - return names.size(); - } - } - - return 0; -} - -/** - * Returns the nth "alternate" name for this type. See get_num_alt_names(). - */ -string CPPType:: -get_alt_name(int n) const { - // We do a lookup based on the type's name, instead of its pointer, so we - // can resolve different expansions of the same type. - string tname = this->get_fully_scoped_name(); - - if (!tname.empty()) { - AltNames::const_iterator ai; - ai = _alt_names.find(tname); - if (ai != _alt_names.end()) { - const Names &names = (*ai).second; - if (n >= 0 && n < (int)names.size()) { - return names[n]; - } - } - } - - return string(); -} - -/** - * Returns true if the type has not yet been fully specified, false if it has. - */ -bool CPPType:: -is_incomplete() const { - return false; -} - -/** - * This is a little more forgiving than is_equal(): it returns true if the - * types appear to be referring to the same thing, even if they may have - * different pointers or somewhat different definitions. It's useful for - * parameter matching, etc. - */ -bool CPPType:: -is_equivalent(const CPPType &other) const { - if (get_subtype() != other.get_subtype()) { - return false; - } - return is_equal(&other); -} - -/** - * Returns true if variables of this type may be implicitly converted to - * the other type. - */ -bool CPPType:: -is_convertible_to(const CPPType *other) const { - return other->is_constructible(this); -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPType:: -output_instance(std::ostream &out, const string &name, CPPScope *scope) const { - output_instance(out, 0, scope, false, "", name); -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPType:: -output_instance(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, const string &prename, - const string &name) const { - output(out, indent_level, scope, complete); - out << " " << prename << name; -} - - -/** - * - */ -CPPType *CPPType:: -as_type() { - return this; -} - - -/** - * This should be called whenever a new CPPType object is created. It will - * uniquify the type pointers by checking to see if some equivalent CPPType - * object has previously been created; if it has, it returns the old object - * and deletes the new one. Otherwise, it stores the new one and returns it. - */ -CPPType *CPPType:: -new_type(CPPType *type) { - std::pair result = _types.insert(type); - if (result.second) { - // The insertion has taken place; thus, this is the first time this type - // has been declared. - assert(*result.first == type); - return type; - } - - // If this triggers, we probably messed up by defining is_less() - // incorrectly; they provide a relative ordering even though they are equal - // to each other. Or, we provided an is_equal() that gives false negatives. - assert(**result.first == *type); - - // The insertion has not taken place; thus, there was previously another - // equivalent type declared. - if (*result.first != type) { - // *** Something wrong here. Deleting this should always be safe; - // however, it's not. Thus, someone failed to call new_type() on a type - // pointer before saving it somewhere. Fix me soon. **** - - delete type; - } - return *result.first; -} - -/** - * Records a global typedef name associated with the indicated Type. This - * will be an "alt" name, and it may also become the "preferred" name. - */ -void CPPType:: -record_alt_name_for(const CPPType *type, const string &name) { - if (!name.empty()) { - string tname = type->get_fully_scoped_name(); - if (!tname.empty()) { - if (tname.find('<') != string::npos) { - // If the name contains a funny character like a template name, then - // we implicitly take the first typedef as the preferred name. - _preferred_names.insert(PreferredNames::value_type(tname, name)); - } - - Names &names = _alt_names[tname]; - if (find(names.begin(), names.end(), name) == names.end()) { - // It's not already recorded as an alt name, so record it now. - names.push_back(name); - } - } - } -} - -/** - * Returns the previously-stored "preferred" name associated with the type, if - * any, or empty string if no name is associated. - */ -string CPPType:: -get_preferred_name_for(const CPPType *type) { - // We do a lookup based on the type's name, instead of its pointer, so we - // can resolve different expansions of the same type. - string tname = type->get_fully_scoped_name(); - - if (!tname.empty()) { - PreferredNames::const_iterator pi; - pi = _preferred_names.find(tname); - if (pi != _preferred_names.end()) { - return (*pi).second; - } - } - - return string(); -} diff --git a/dtool/src/cppparser/cppType.h b/dtool/src/cppparser/cppType.h deleted file mode 100644 index d5245ac8fe5..00000000000 --- a/dtool/src/cppparser/cppType.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppType.h - * @author drose - * @date 1999-10-19 - */ - -#ifndef CPPTYPE_H -#define CPPTYPE_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" - -#include - -class CPPType; -class CPPTypedefType; -class CPPTypeDeclaration; - - -// This is an STL function object used to uniquely order CPPType pointers. -class CPPTypeCompare { -public: - bool operator () (CPPType *a, CPPType *b) const; -}; - -/** - * - */ -class CPPType : public CPPDeclaration { -public: - typedef std::vector Typedefs; - Typedefs _typedefs; - - CPPType(const CPPFile &file); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_tbd() const; - virtual bool is_fundamental() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *type) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_copy_assignable() const; - virtual bool is_destructible() const; - virtual bool is_parameter_expr() const; - - // Convenience methods. - bool is_enum() const; - bool is_const() const; - bool is_reference() const; - bool is_pointer() const; - - CPPType *remove_const(); - inline CPPType *remove_volatile() { return this; } - inline CPPType *remove_cv() { return remove_const(); }; - CPPType *remove_reference(); - CPPType *remove_pointer(); - - bool has_typedef_name() const; - std::string get_typedef_name(CPPScope *scope = nullptr) const; - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - virtual std::string get_preferred_name() const; - int get_num_alt_names() const; - std::string get_alt_name(int n) const; - - virtual bool is_incomplete() const; - virtual bool is_convertible_to(const CPPType *other) const; - virtual bool is_equivalent(const CPPType &other) const; - - void output_instance(std::ostream &out, const std::string &name, - CPPScope *scope) const; - virtual void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const; - - virtual CPPType *as_type(); - - - static CPPType *new_type(CPPType *type); - - static void record_alt_name_for(const CPPType *type, const std::string &name); - static std::string get_preferred_name_for(const CPPType *type); - - CPPTypeDeclaration *_declaration; - bool _forcetype; - -protected: - typedef std::set Types; - static Types _types; - - typedef std::map PreferredNames; - static PreferredNames _preferred_names; - - typedef std::vector Names; - typedef std::map AltNames; - static AltNames _alt_names; -}; - -#endif diff --git a/dtool/src/cppparser/cppTypeDeclaration.cxx b/dtool/src/cppparser/cppTypeDeclaration.cxx deleted file mode 100644 index 84b60751720..00000000000 --- a/dtool/src/cppparser/cppTypeDeclaration.cxx +++ /dev/null @@ -1,67 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypeDeclaration.cxx - * @author drose - * @date 2000-08-14 - */ - -#include "cppTypeDeclaration.h" - -/** - * Constructs a new CPPTypeDeclaration object for the given type. - */ -CPPTypeDeclaration:: -CPPTypeDeclaration(CPPType *type) : - CPPInstance(type, nullptr) -{ - assert(_type != nullptr); - if (_type->_declaration == nullptr) { - _type->_declaration = this; - } -} - -/** - * - */ -CPPDeclaration *CPPTypeDeclaration:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - CPPDeclaration *decl = - CPPInstance::substitute_decl(subst, current_scope, global_scope); - assert(decl != nullptr); - if (decl->as_type_declaration()) { - return decl; - } - assert(decl->as_instance() != nullptr); - return new CPPTypeDeclaration(decl->as_instance()->_type); -} - -/** - * - */ -void CPPTypeDeclaration:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool) const { - _type->output(out, indent_level, scope, true); -} - -/** - * - */ -CPPDeclaration::SubType CPPTypeDeclaration:: -get_subtype() const { - return ST_type_declaration; -} - -/** - * - */ -CPPTypeDeclaration *CPPTypeDeclaration:: -as_type_declaration() { - return this; -} diff --git a/dtool/src/cppparser/cppTypeDeclaration.h b/dtool/src/cppparser/cppTypeDeclaration.h deleted file mode 100644 index cd93ed0fdc5..00000000000 --- a/dtool/src/cppparser/cppTypeDeclaration.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypeDeclaration.h - * @author drose - * @date 2000-08-14 - */ - -#ifndef CPPTYPEDECLARATION_H -#define CPPTYPEDECLARATION_H - -#include "dtoolbase.h" - -#include "cppInstance.h" - -/** - * A CPPTypeDeclaration is a special declaration that represents the top-level - * declaration of a type in a source file. Typically this is the first - * appearance of the type. - */ -class CPPTypeDeclaration : public CPPInstance { -public: - CPPTypeDeclaration(CPPType *type); - - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPTypeDeclaration *as_type_declaration(); -}; - -#endif diff --git a/dtool/src/cppparser/cppTypeParser.cxx b/dtool/src/cppparser/cppTypeParser.cxx deleted file mode 100644 index cdaa1d02882..00000000000 --- a/dtool/src/cppparser/cppTypeParser.cxx +++ /dev/null @@ -1,77 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypeParser.cxx - * @author drose - * @date 1999-12-14 - */ - -#include "cppTypeParser.h" -#include "cppType.h" - -/** - * - */ -CPPTypeParser:: -CPPTypeParser(CPPScope *current_scope, CPPScope *global_scope) : - _current_scope(current_scope), - _global_scope(global_scope) -{ - _type = nullptr; -} - -/** - * - */ -CPPTypeParser:: -~CPPTypeParser() { -} - -/** - * - */ -bool CPPTypeParser:: -parse_type(const std::string &type) { - if (!init_type(type)) { - std::cerr << "Unable to parse type\n"; - return false; - } - - _type = ::parse_type(this, _current_scope, _global_scope); - - return get_error_count() == 0; -} - -/** - * - */ -bool CPPTypeParser:: -parse_type(const std::string &type, const CPPPreprocessor &filepos) { - if (!init_type(type)) { - std::cerr << "Unable to parse type\n"; - return false; - } - - copy_filepos(filepos); - - _type = ::parse_type(this, _current_scope, _global_scope); - - return get_error_count() == 0; -} - -/** - * - */ -void CPPTypeParser:: -output(std::ostream &out) const { - if (_type == nullptr) { - out << "(null type)"; - } else { - out << *_type; - } -} diff --git a/dtool/src/cppparser/cppTypeParser.h b/dtool/src/cppparser/cppTypeParser.h deleted file mode 100644 index 4064e846873..00000000000 --- a/dtool/src/cppparser/cppTypeParser.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypeParser.h - * @author drose - * @date 1999-12-14 - */ - -#ifndef CPPTYPEPARSER_H -#define CPPTYPEPARSER_H - -#include "dtoolbase.h" - -#include "cppPreprocessor.h" - -class CPPType; -class CPPScope; - -/** - * - */ -class CPPTypeParser : public CPPPreprocessor { -public: - CPPTypeParser(CPPScope *current_scope, CPPScope *global_scope); - ~CPPTypeParser(); - - bool parse_type(const std::string &type); - bool parse_type(const std::string &type, const CPPPreprocessor &filepos); - - void output(std::ostream &out) const; - - CPPScope *_current_scope; - CPPScope *_global_scope; - CPPType *_type; -}; - -inline std::ostream & -operator << (std::ostream &out, const CPPTypeParser &ep) { - ep.output(out); - return out; -} - -#endif diff --git a/dtool/src/cppparser/cppTypeProxy.cxx b/dtool/src/cppparser/cppTypeProxy.cxx deleted file mode 100644 index 4843ac5b345..00000000000 --- a/dtool/src/cppparser/cppTypeProxy.cxx +++ /dev/null @@ -1,319 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypeProxy.cxx - * @author drose - * @date 1999-12-07 - */ - -#include "cppTypeProxy.h" -#include "cppFile.h" - -using std::string; - -/** - * - */ -CPPTypeProxy:: -CPPTypeProxy() : - CPPType(CPPFile()) -{ - _actual_type = nullptr; -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPTypeProxy:: -resolve_type(CPPScope *, CPPScope *) { - if (_actual_type == nullptr) { - return this; - } - return _actual_type; -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPTypeProxy:: -is_tbd() const { - if (_actual_type == nullptr) { - return false; - } - return _actual_type->is_tbd(); -} - -/** - * Returns true if the type has even been typedef'ed and therefore has a - * simple name available to stand for it. Extension types are all implicitly - * typedef'ed on declaration. - */ -bool CPPTypeProxy:: -has_typedef_name() const { - if (_actual_type == nullptr) { - return false; - } - return _actual_type->has_typedef_name(); -} - -/** - * Returns a string that can be used to name the type, if has_typedef_name() - * returned true. This will be the first typedef name applied to the type. - */ -string CPPTypeProxy:: -get_typedef_name(CPPScope *) const { - if (_actual_type == nullptr) { - return string(); - } - return _actual_type->get_typedef_name(); -} - - -/** - * Returns a fundametal one-word name for the type. This name will not - * include any scoping operators or template parameters, so it may not be a - * compilable reference to the type. - */ -string CPPTypeProxy:: -get_simple_name() const { - if (_actual_type == nullptr) { - return "unknown"; - } - return _actual_type->get_simple_name(); -} - -/** - * Returns the compilable, correct name for this type within the indicated - * scope. If the scope is NULL, within the scope the type is declared in. - */ -string CPPTypeProxy:: -get_local_name(CPPScope *scope) const { - if (_actual_type == nullptr) { - return "unknown"; - } - return _actual_type->get_local_name(scope); -} - -/** - * Returns the compilable, correct name for the type, with completely explicit - * scoping. - */ -string CPPTypeProxy:: -get_fully_scoped_name() const { - if (_actual_type == nullptr) { - return "unknown"; - } - return _actual_type->get_fully_scoped_name(); -} - -/** - * Returns the best name to use for the type from a programmer's point of - * view. This will typically be a typedef name if one is available, or the - * full C++ name if it is not. The typedef may or may not be visible within - * the current scope, so this type name may not be compilable. - */ -string CPPTypeProxy:: -get_preferred_name() const { - if (_actual_type == nullptr) { - return "unknown"; - } - return _actual_type->get_preferred_name(); -} - -/** - * Returns true if the type has not yet been fully specified, false if it has. - */ -bool CPPTypeProxy:: -is_incomplete() const { - if (_actual_type == nullptr) { - return true; - } - return _actual_type->is_incomplete(); -} - -/** - * Formats a C++-looking line that defines an instance of the given type, with - * the indicated name. In most cases this will be "type name", but some types - * have special exceptions. - */ -void CPPTypeProxy:: -output_instance(std::ostream &out, int indent_level, CPPScope *scope, - bool complete, const string &prename, - const string &name) const { - if (_actual_type == nullptr) { - out << "unknown " << prename << name; - return; - } - _actual_type->output_instance(out, indent_level, scope, complete, - prename, name); -} - -/** - * - */ -void CPPTypeProxy:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - if (_actual_type == nullptr) { - out << "unknown"; - return; - } - _actual_type->output(out, indent_level, scope, complete); -} - - -/** - * - */ -CPPDeclaration::SubType CPPTypeProxy:: -get_subtype() const { - return ST_type_proxy; -} - -/** - * - */ -CPPType *CPPTypeProxy:: -as_type() { - if (_actual_type == nullptr) { - return this; - } - return _actual_type; -} - -/** - * - */ -CPPSimpleType *CPPTypeProxy:: -as_simple_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_simple_type(); -} - -/** - * - */ -CPPPointerType *CPPTypeProxy:: -as_pointer_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_pointer_type(); -} - -/** - * - */ -CPPReferenceType *CPPTypeProxy:: -as_reference_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_reference_type(); -} - -/** - * - */ -CPPArrayType *CPPTypeProxy:: -as_array_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_array_type(); -} - -/** - * - */ -CPPConstType *CPPTypeProxy:: -as_const_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_const_type(); -} - -/** - * - */ -CPPFunctionType *CPPTypeProxy:: -as_function_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_function_type(); -} - -/** - * - */ -CPPExtensionType *CPPTypeProxy:: -as_extension_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_extension_type(); -} - -/** - * - */ -CPPStructType *CPPTypeProxy:: -as_struct_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_struct_type(); -} - -/** - * - */ -CPPEnumType *CPPTypeProxy:: -as_enum_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_enum_type(); -} - -/** - * - */ -CPPTBDType *CPPTypeProxy:: -as_tbd_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_tbd_type(); -} - -/** - * - */ -CPPTypedefType *CPPTypeProxy:: -as_typedef_type() { - if (_actual_type == nullptr) { - return nullptr; - } - return _actual_type->as_typedef_type(); -} - -/** - * - */ -CPPTypeProxy *CPPTypeProxy:: -as_type_proxy() { - return this; -} diff --git a/dtool/src/cppparser/cppTypeProxy.h b/dtool/src/cppparser/cppTypeProxy.h deleted file mode 100644 index 87d064a3b54..00000000000 --- a/dtool/src/cppparser/cppTypeProxy.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypeProxy.h - * @author drose - * @date 1999-12-07 - */ - -#ifndef CPPTYPEPROXY_H -#define CPPTYPEPROXY_H - -#include "dtoolbase.h" - -#include "cppType.h" - -/** - * This is a special kind of type that is a placeholder for some type, - * currently unknown, that will be filled in later. It's used when a type - * that references itself must instantiate. - */ -class CPPTypeProxy : public CPPType { -public: - CPPTypeProxy(); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_tbd() const; - - bool has_typedef_name() const; - std::string get_typedef_name(CPPScope *scope = nullptr) const; - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - virtual std::string get_preferred_name() const; - - virtual bool is_incomplete() const; - - virtual void output_instance(std::ostream &out, int indent_level, - CPPScope *scope, - bool complete, const std::string &prename, - const std::string &name) const; - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - - virtual SubType get_subtype() const; - - virtual CPPType *as_type(); - virtual CPPSimpleType *as_simple_type(); - virtual CPPPointerType *as_pointer_type(); - virtual CPPReferenceType *as_reference_type(); - virtual CPPArrayType *as_array_type(); - virtual CPPConstType *as_const_type(); - virtual CPPFunctionType *as_function_type(); - virtual CPPExtensionType *as_extension_type(); - virtual CPPStructType *as_struct_type(); - virtual CPPEnumType *as_enum_type(); - virtual CPPTBDType *as_tbd_type(); - virtual CPPTypedefType *as_typedef_type(); - virtual CPPTypeProxy *as_type_proxy(); - - CPPType *_actual_type; -}; - -#endif diff --git a/dtool/src/cppparser/cppTypedefType.cxx b/dtool/src/cppparser/cppTypedefType.cxx deleted file mode 100644 index cd325d73499..00000000000 --- a/dtool/src/cppparser/cppTypedefType.cxx +++ /dev/null @@ -1,471 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypedefType.cxx - * @author rdb - * @date 2014-08-01 - */ - -#include "cppTypedefType.h" -#include "cppIdentifier.h" -#include "cppInstanceIdentifier.h" -#include "cppTemplateScope.h" -#include "indent.h" - -using std::string; - -/** - * - */ -CPPTypedefType:: -CPPTypedefType(CPPType *type, const string &name, CPPScope *current_scope) : - CPPType(CPPFile()), - _type(type), - _ident(new CPPIdentifier(name)), - _using(false) -{ - if (_ident != nullptr) { - _ident->_native_scope = current_scope; - } - - _subst_decl_recursive_protect = false; - - // assert(_type != NULL); if (global) { _type->_typedefs.push_back(this); - // CPPType::record_alt_name_for(_type, inst->get_local_name()); } -} - -/** - * - */ -CPPTypedefType:: -CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope, - CPPAttributeList attr) : - CPPType(CPPFile()), - _type(type), - _ident(ident), - _using(false) -{ - if (_ident != nullptr) { - _ident->_native_scope = current_scope; - } - _subst_decl_recursive_protect = false; - - _attributes = std::move(attr); -} - -/** - * Constructs a new CPPTypedefType object that defines a typedef to the - * indicated type according to the type and the InstanceIdentifier. The - * InstanceIdentifier pointer is deallocated. - */ -CPPTypedefType:: -CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii, - CPPScope *current_scope, const CPPFile &file) : - CPPType(file), - _using(false) -{ - assert(ii != nullptr); - _type = ii->unroll_type(type); - _ident = ii->_ident; - _attributes = std::move(ii->_attributes); - ii->_ident = nullptr; - delete ii; - - if (_ident != nullptr) { - _ident->_native_scope = current_scope; - } - - _subst_decl_recursive_protect = false; -} - -/** - * - */ -bool CPPTypedefType:: -is_scoped() const { - if (_ident == nullptr) { - return false; - } else { - return _ident->is_scoped(); - } -} - -/** - * - */ -CPPScope *CPPTypedefType:: -get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - if (_ident == nullptr) { - return current_scope; - } else { - return _ident->get_scope(current_scope, global_scope, error_sink); - } -} - -/** - * - */ -string CPPTypedefType:: -get_simple_name() const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_simple_name(); -} - -/** - * - */ -string CPPTypedefType:: -get_local_name(CPPScope *scope) const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_local_name(scope); -} - -/** - * - */ -string CPPTypedefType:: -get_fully_scoped_name() const { - if (_ident == nullptr) { - return ""; - } - return _ident->get_fully_scoped_name(); -} - -/** - * Returns true if the type has not yet been fully specified, false if it has. - */ -bool CPPTypedefType:: -is_incomplete() const { - return false; - // return _type->is_incomplete(); -} - -/** - * Returns true if the type, or any nested type within the type, is a - * CPPTBDType and thus isn't fully determined right now. In this case, - * calling resolve_type() may or may not resolve the type. - */ -bool CPPTypedefType:: -is_tbd() const { - if (_ident != nullptr && _ident->is_tbd()) { - return true; - } - return _type->is_tbd(); -} - -/** - * Returns true if the type is considered a fundamental type. - */ -bool CPPTypedefType:: -is_fundamental() const { - return _type->is_fundamental(); -} - -/** - * Returns true if the type is considered a standard layout type. - */ -bool CPPTypedefType:: -is_standard_layout() const { - return _type->is_standard_layout(); -} - -/** - * Returns true if the type is considered a Plain Old Data (POD) type. - */ -bool CPPTypedefType:: -is_trivial() const { - return _type->is_trivial(); -} - -/** - * Returns true if the type can be safely copied by memcpy or memmove. - */ -bool CPPTypedefType:: -is_trivially_copyable() const { - return _type->is_trivially_copyable(); -} - -/** - * Returns true if the type can be constructed using the given argument. - */ -bool CPPTypedefType:: -is_constructible(const CPPType *given_type) const { - return _type->is_constructible(given_type); -} - -/** - * Returns true if the type is default-constructible. - */ -bool CPPTypedefType:: -is_default_constructible() const { - return _type->is_default_constructible(); -} - -/** - * Returns true if the type is copy-constructible. - */ -bool CPPTypedefType:: -is_copy_constructible() const { - return _type->is_copy_constructible(); -} - -/** - * Returns true if the type is copy-assignable. - */ -bool CPPTypedefType:: -is_copy_assignable() const { - return _type->is_copy_assignable(); -} - -/** - * Returns true if the type is destructible. - */ -bool CPPTypedefType:: -is_destructible() const { - return _type->is_destructible(); -} - -/** - * Returns true if this declaration is an actual, factual declaration, or - * false if some part of the declaration depends on a template parameter which - * has not yet been instantiated. - */ -bool CPPTypedefType:: -is_fully_specified() const { - if (_ident != nullptr && !_ident->is_fully_specified()) { - return false; - } - return CPPDeclaration::is_fully_specified() && - _type->is_fully_specified(); -} - -/** - * - */ -CPPDeclaration *CPPTypedefType:: -instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink) const { - - return _type->instantiate(actual_params, current_scope, global_scope, error_sink); -} - -/** - * - */ -CPPDeclaration *CPPTypedefType:: -substitute_decl(CPPDeclaration::SubstDecl &subst, - CPPScope *current_scope, CPPScope *global_scope) { - - if (_ident != nullptr && _ident->get_scope(current_scope, global_scope) == global_scope) { - // Hack... I know that size_t etc is supposed to work fine, so preserve - // these top-level typedefs. - CPPDeclaration *top = - CPPType::substitute_decl(subst, current_scope, global_scope); - if (top != this) { - return top; - } - top = new CPPTypedefType(*this); - subst.insert(SubstDecl::value_type(this, top)); - return top; - } - - return _type->substitute_decl(subst, current_scope, global_scope); - - // Bah, this doesn't seem to work, and I can't figure out why. Well, for - // now, let's just substitute it with the type we're pointing to. This is - // not a huge deal for now, until we find that we need to preserve these - // typedefs. - - /* - CPPDeclaration *top = - CPPType::substitute_decl(subst, current_scope, global_scope); - if (top != this) { - return top; - } - - if (_subst_decl_recursive_protect) { - // We're already executing this block; we'll have to return a proxy to the - // type which we'll define later. - CPPTypeProxy *proxy = new CPPTypeProxy; - _proxies.push_back(proxy); - assert(proxy != NULL); - return proxy; - } - _subst_decl_recursive_protect = true; - - CPPTypedefType *rep = new CPPTypedefType(*this); - CPPDeclaration *new_type = - _type->substitute_decl(subst, current_scope, global_scope); - rep->_type = new_type->as_type(); - - if (rep->_type == NULL) { - rep->_type = _type; - } - - if (_ident != NULL) { - rep->_ident = - _ident->substitute_decl(subst, current_scope, global_scope); - } - - if (rep->_type == _type && rep->_ident == _ident) { - delete rep; - rep = this; - } - - rep = CPPType::new_type(rep)->as_typedef_type(); - subst.insert(SubstDecl::value_type(this, rep)); - - _subst_decl_recursive_protect = false; - // Now fill in all the proxies we created for our recursive references. - Proxies::iterator pi; - for (pi = _proxies.begin(); pi != _proxies.end(); ++pi) { - (*pi)->_actual_type = rep; - } - - return rep; */ -} - -/** - * If this CPPType object is a forward reference or other nonspecified - * reference to a type that might now be known a real type, returns the real - * type. Otherwise returns the type itself. - */ -CPPType *CPPTypedefType:: -resolve_type(CPPScope *current_scope, CPPScope *global_scope) { - CPPType *ptype = _type->resolve_type(current_scope, global_scope); - - if (ptype != _type) { - CPPTypedefType *rep = new CPPTypedefType(*this); - rep->_type = ptype; - return CPPType::new_type(rep); - } - - return this; -} - -/** - * Returns true if variables of this type may be implicitly converted to - * the other type. - */ -bool CPPTypedefType:: -is_convertible_to(const CPPType *other) const { - return _type->is_convertible_to(other); -} - -/** - * This is a little more forgiving than is_equal(): it returns true if the - * types appear to be referring to the same thing, even if they may have - * different pointers or somewhat different definitions. It's useful for - * parameter matching, etc. - */ -bool CPPTypedefType:: -is_equivalent(const CPPType &other) const { - CPPType *ot = (CPPType *)&other; - - // Unwrap all the typedefs to get to where it is pointing. - while (ot->get_subtype() == ST_typedef) { - ot = ot->as_typedef_type()->_type; - } - - // Compare the unwrapped type to what we are pointing to. If we are - // pointing to a typedef ourselves, then this will automatically recurse. - return _type->is_equivalent(*ot); -} - -/** - * - */ -void CPPTypedefType:: -output(std::ostream &out, int indent_level, CPPScope *scope, bool complete) const { - string name; - if (_ident != nullptr) { - name = _ident->get_local_name(scope); - } - - if (complete) { - if (_using) { - // It was declared using the "using" keyword. - if (is_template()) { - get_template_scope()->_parameters.write_formal(out, scope); - indent(out, indent_level); - } - out << "using " << name; - if (!_attributes.is_empty()) { - out << " " << _attributes; - } - out << " = "; - _type->output(out, 0, scope, false); - } else { - if (!_attributes.is_empty()) { - out << _attributes << " "; - } - out << "typedef "; - _type->output_instance(out, indent_level, scope, false, "", name); - } - } else { - out << name; - } -} - -/** - * - */ -CPPDeclaration::SubType CPPTypedefType:: -get_subtype() const { - return ST_typedef; -} - -/** - * - */ -CPPTypedefType *CPPTypedefType:: -as_typedef_type() { - return this; -} - -/** - * Called by CPPDeclaration() to determine whether this type is equivalent to - * another type of the same type. - */ -bool CPPTypedefType:: -is_equal(const CPPDeclaration *other) const { - const CPPTypedefType *ot = ((CPPDeclaration *)other)->as_typedef_type(); - assert(ot != nullptr); - - return (*_type == *ot->_type) && (*_ident == *ot->_ident) && (_using == ot->_using); -} - -/** - * Called by CPPDeclaration() to determine whether this type should be ordered - * before another type of the same type, in an arbitrary but fixed ordering. - */ -bool CPPTypedefType:: -is_less(const CPPDeclaration *other) const { - return CPPDeclaration::is_less(other); - - // The below code causes a crash for unknown reasons. - /* - const CPPTypedefType *ot = ((CPPDeclaration *)other)->as_typedef_type(); - assert(ot != NULL); - - if (_type != ot->_type) { - return _type < ot->_type; - } - - if (*_ident != *ot->_ident) { - return *_ident < *ot->_ident; - } - - return false; */ -} diff --git a/dtool/src/cppparser/cppTypedefType.h b/dtool/src/cppparser/cppTypedefType.h deleted file mode 100644 index 298505f06b0..00000000000 --- a/dtool/src/cppparser/cppTypedefType.h +++ /dev/null @@ -1,92 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppTypedefType.h - * @author rdb - * @date 2014-08-01 - */ - -#ifndef CPPTYPEDEFTYPE_H -#define CPPTYPEDEFTYPE_H - -#include "dtoolbase.h" -#include "cppType.h" - -class CPPIdentifier; -class CPPInstanceIdentifier; - -/** - * A type alias created by a C++ typedef or using declaration. These aren't - * officially supposed to be types in themselves, but we represent them as - * such so that we can preserve typedef names in the generated code. - */ -class CPPTypedefType : public CPPType { -public: - CPPTypedefType(CPPType *type, const std::string &name, CPPScope *current_scope); - CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope, - CPPAttributeList attr = CPPAttributeList()); - CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii, - CPPScope *current_scope, const CPPFile &file); - - bool is_scoped() const; - CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - virtual std::string get_simple_name() const; - virtual std::string get_local_name(CPPScope *scope = nullptr) const; - virtual std::string get_fully_scoped_name() const; - - virtual bool is_incomplete() const; - virtual bool is_tbd() const; - virtual bool is_fundamental() const; - virtual bool is_standard_layout() const; - virtual bool is_trivial() const; - virtual bool is_trivially_copyable() const; - virtual bool is_constructible(const CPPType *type) const; - virtual bool is_default_constructible() const; - virtual bool is_copy_constructible() const; - virtual bool is_copy_assignable() const; - virtual bool is_destructible() const; - - virtual bool is_fully_specified() const; - - virtual CPPDeclaration * - instantiate(const CPPTemplateParameterList *actual_params, - CPPScope *current_scope, CPPScope *global_scope, - CPPPreprocessor *error_sink = nullptr) const; - - virtual CPPDeclaration *substitute_decl(SubstDecl &subst, - CPPScope *current_scope, - CPPScope *global_scope); - - virtual CPPType *resolve_type(CPPScope *current_scope, - CPPScope *global_scope); - - virtual bool is_convertible_to(const CPPType *other) const; - virtual bool is_equivalent(const CPPType &other) const; - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPTypedefType *as_typedef_type(); - - CPPType *_type; - CPPIdentifier *_ident; - bool _using; - -protected: - virtual bool is_equal(const CPPDeclaration *other) const; - virtual bool is_less(const CPPDeclaration *other) const; - - bool _subst_decl_recursive_protect; - typedef std::vector Proxies; - Proxies _proxies; -}; - -#endif diff --git a/dtool/src/cppparser/cppUsing.cxx b/dtool/src/cppparser/cppUsing.cxx deleted file mode 100644 index 146f8f3f48d..00000000000 --- a/dtool/src/cppparser/cppUsing.cxx +++ /dev/null @@ -1,53 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppUsing.cxx - * @author drose - * @date 1999-11-16 - */ - -#include "cppUsing.h" -#include "cppIdentifier.h" - -/** - * - */ -CPPUsing:: -CPPUsing(CPPIdentifier *ident, bool full_namespace, const CPPFile &file) : - CPPDeclaration(file), - _ident(ident), _full_namespace(full_namespace) -{ -} - -/** - * - */ -void CPPUsing:: -output(std::ostream &out, int, CPPScope *, bool) const { - out << "using "; - if (_full_namespace) { - out << "namespace "; - } - out << *_ident; -} - -/** - * - */ -CPPDeclaration::SubType CPPUsing:: -get_subtype() const { - return ST_using; -} - -/** - * - */ -CPPUsing *CPPUsing:: -as_using() { - return this; -} diff --git a/dtool/src/cppparser/cppUsing.h b/dtool/src/cppparser/cppUsing.h deleted file mode 100644 index 13de9ce855b..00000000000 --- a/dtool/src/cppparser/cppUsing.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppUsing.h - * @author drose - * @date 1999-11-16 - */ - -#ifndef CPPUSING_H -#define CPPUSING_H - -#include "dtoolbase.h" - -#include "cppDeclaration.h" - -class CPPIdentifier; -class CPPScope; - -/** - * - */ -class CPPUsing : public CPPDeclaration { -public: - CPPUsing(CPPIdentifier *ident, bool full_namespace, const CPPFile &file); - - virtual void output(std::ostream &out, int indent_level, CPPScope *scope, - bool complete) const; - virtual SubType get_subtype() const; - - virtual CPPUsing *as_using(); - - CPPIdentifier *_ident; - bool _full_namespace; -}; - -#endif diff --git a/dtool/src/cppparser/cppVisibility.cxx b/dtool/src/cppparser/cppVisibility.cxx deleted file mode 100644 index 92273c00a35..00000000000 --- a/dtool/src/cppparser/cppVisibility.cxx +++ /dev/null @@ -1,36 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppVisibility.cxx - * @author drose - * @date 1999-10-22 - */ - -#include "cppVisibility.h" - -std::ostream & -operator << (std::ostream &out, CPPVisibility vis) { - switch (vis) { - case V_published: - return out << "__published"; - - case V_public: - return out << "public"; - - case V_protected: - return out << "protected"; - - case V_private: - return out << "private"; - - case V_unknown: - return out << "unknown"; - } - - return out << "(**invalid visibility**)"; -} diff --git a/dtool/src/cppparser/cppVisibility.h b/dtool/src/cppparser/cppVisibility.h deleted file mode 100644 index 7165aaecc1f..00000000000 --- a/dtool/src/cppparser/cppVisibility.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file cppVisibility.h - * @author drose - * @date 1999-10-22 - */ - -#ifndef CPPVISIBILITY_H -#define CPPVISIBILITY_H - -#include "dtoolbase.h" - -enum CPPVisibility { - V_published, - V_public, - V_protected, - V_private, - V_unknown -}; - -std::ostream &operator << (std::ostream &out, CPPVisibility vis); - -#endif diff --git a/dtool/src/cppparser/p3cppParser_composite1.cxx b/dtool/src/cppparser/p3cppParser_composite1.cxx deleted file mode 100644 index 3cf2094252b..00000000000 --- a/dtool/src/cppparser/p3cppParser_composite1.cxx +++ /dev/null @@ -1,26 +0,0 @@ -#include "cppAttributeList.cxx" -#include "cppFunctionType.cxx" -#include "cppGlobals.cxx" -#include "cppCommentBlock.cxx" -#include "cppClosureType.cxx" -#include "cppConstType.cxx" -#include "cppDeclaration.cxx" -#include "cppMakeProperty.cxx" -#include "cppMakeSeq.cxx" -#include "cppParameterList.cxx" -#include "cppParser.cxx" -#include "cppPointerType.cxx" -#include "cppPreprocessor.cxx" -#include "cppReferenceType.cxx" -#include "cppTemplateParameterList.cxx" -#include "cppTemplateScope.cxx" -#include "cppToken.cxx" -#include "cppType.cxx" -#include "cppTypeDeclaration.cxx" -#include "cppTypeParser.cxx" -#include "cppTypeProxy.cxx" -#include "cppTypedefType.cxx" -#include "cppSimpleType.cxx" -#include "cppTBDType.cxx" -#include "cppUsing.cxx" -#include "cppVisibility.cxx" diff --git a/dtool/src/cppparser/p3cppParser_composite2.cxx b/dtool/src/cppparser/p3cppParser_composite2.cxx deleted file mode 100644 index 1a78bd698ef..00000000000 --- a/dtool/src/cppparser/p3cppParser_composite2.cxx +++ /dev/null @@ -1,17 +0,0 @@ -#include "cppArrayType.cxx" -#include "cppClassTemplateParameter.cxx" -#include "cppEnumType.cxx" -#include "cppExpression.cxx" -#include "cppExpressionParser.cxx" -#include "cppExtensionType.cxx" -#include "cppFile.cxx" -#include "cppFunctionGroup.cxx" -#include "cppIdentifier.cxx" -#include "cppInstance.cxx" -#include "cppInstanceIdentifier.cxx" -#include "cppManifest.cxx" -#include "cppNameComponent.cxx" -#include "cppNamespace.cxx" -#include "cppScope.cxx" -#include "cppStructType.cxx" - diff --git a/dtool/src/dtoolbase/CMakeLists.txt b/dtool/src/dtoolbase/CMakeLists.txt index 7e9340ec714..d62f879029c 100644 --- a/dtool/src/dtoolbase/CMakeLists.txt +++ b/dtool/src/dtoolbase/CMakeLists.txt @@ -24,6 +24,7 @@ set(P3DTOOLBASE_HEADERS deletedChain.h deletedChain.I dtoolbase.h dtoolbase_cc.h dtoolsymbols.h dtool_platform.h + extension.h fakestringstream.h indent.I indent.h memoryBase.h diff --git a/dtool/src/dtoolbase/dtoolbase_cc.h b/dtool/src/dtoolbase/dtoolbase_cc.h index d19db7f5eff..ed556881941 100644 --- a/dtool/src/dtoolbase/dtoolbase_cc.h +++ b/dtool/src/dtoolbase/dtoolbase_cc.h @@ -110,9 +110,9 @@ typedef std::ios::seekdir ios_seekdir; #define INLINE inline #endif -// Determine the availability of C++11 features. -#if defined(_MSC_VER) && _MSC_VER < 1900 // Visual Studio 2015 -#error Microsoft Visual C++ 2015 or later is required to compile Panda3D. +// Determine the availability of C++14 features. +#if defined(_MSC_VER) && _MSC_VER < 1910 // Visual Studio 2017 +#error Microsoft Visual C++ 2017 or later is required to compile Panda3D. #endif // This is just to support code generated with older versions of interrogate. diff --git a/dtool/src/interrogatedb/extension.h b/dtool/src/dtoolbase/extension.h similarity index 100% rename from dtool/src/interrogatedb/extension.h rename to dtool/src/dtoolbase/extension.h diff --git a/dtool/src/dtoolbase/pdtoa.cxx b/dtool/src/dtoolbase/pdtoa.cxx index 2b508654ba6..552391a6fc0 100644 --- a/dtool/src/dtoolbase/pdtoa.cxx +++ b/dtool/src/dtoolbase/pdtoa.cxx @@ -32,6 +32,8 @@ THE SOFTWARE. #include #include #define copysign _copysign + +#pragma float_control(precise, on, push) #endif #define UINT64_C2(h, l) ((static_cast(h) << 32) | static_cast(l)) @@ -428,3 +430,165 @@ void pdtoa(double value, char *buffer) { Prettify(buffer, length, K); } } + +/** + * Version of pdtoa that tries hard to find the minimal string representation + * for a single-precision floating-point number. + */ +void pftoa(float value, char *buffer) { +#ifdef _MSC_VER + if (copysign(1.0f, value) < 0) { +#else + if (std::signbit(value)) { +#endif + *buffer++ = '-'; + value = -value; + } + if (cinf(value)) { + buffer[0] = 'i'; + buffer[1] = 'n'; + buffer[2] = 'f'; + buffer[3] = '\0'; + } else if (cnan(value)) { + buffer[0] = 'n'; + buffer[1] = 'a'; + buffer[2] = 'n'; + buffer[3] = '\0'; + } else if (value == 0.0f) { + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + buffer[3] = '\0'; + } else if (value == 1.0f) { + buffer[0] = '1'; + buffer[1] = '.'; + buffer[2] = '0'; + buffer[3] = '\0'; + } else { + int length, k; + Grisu2(value, buffer, &length, &k); + + const int kk = length + k; // 10^(kk-1) <= v < 10^kk + + if (length <= kk && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + buffer[kk + 2] = '\0'; + } + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + memmove(&buffer[kk + 1], &buffer[kk], length - kk); + + // We want the shortest possible representation, so keep reading digits + // until strtod would give the correct float value. + buffer[kk] = '\0'; + double v = (double)atoi(buffer); + buffer[kk] = '.'; + + double multiplicand = 0.1; + for (int i = kk + 1; i <= length; ++i) { + double vplus = v + (buffer[i] - '0' + 1) * multiplicand; + v += (buffer[i] - '0') * multiplicand; + multiplicand *= 0.1; + + if ((float)v == value) { + length = i; + break; + } + if (buffer[i] < '9' && (float)vplus == value) { + ++buffer[i]; + length = i; + break; + } + } + + buffer[length + 1] = '\0'; + } + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + memmove(&buffer[offset], &buffer[0], length); + buffer[0] = '0'; + buffer[1] = '.'; + + // We want the shortest possible representation, so keep reading digits + // until strtod would give the correct float value. + double multiplicand = 1.0; + for (int i = 2; i < offset; i++) { + buffer[i] = '0'; + multiplicand *= 0.1; + } + if ((float)multiplicand == value) { + length = 0; + buffer[offset - 1] = '1'; + } else { + multiplicand *= 0.1; + double v = 0.0; + for (int i = offset; i < length + offset; ++i) { + double vplus = v + (buffer[i] - '0' + 1) * multiplicand; + v += (buffer[i] - '0') * multiplicand; + multiplicand *= 0.1; + + if ((float)v == value) { + buffer[i + 1] = '\0'; + break; + } + if (buffer[i] < '9' && (float)vplus == value) { + buffer[i]++; + buffer[i + 1] = '\0'; + break; + } + } + } + buffer[length + offset] = '\0'; + } + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + WriteExponent(kk - 1, &buffer[2]); + } + else { + // 1234e30 -> 1.234e33 + memmove(&buffer[2], &buffer[1], length - 1); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + + double e_mult = pow(10.0, kk - 1); + if ((float)(10.0 * e_mult) == value) { + buffer[0] = '1'; + buffer[1] = 'e'; + WriteExponent(kk, &buffer[2]); + } else { + // We want the shortest possible representation, so keep reading + // digits until strtod would give the correct float value. + double v = buffer[0] - '0'; + double multiplicand = 0.1; + for (int i = 2; i < length + 2; ++i) { + double vplus = v + (buffer[i] - '0' + 1) * multiplicand; + v += (buffer[i] - '0') * multiplicand; + multiplicand *= 0.1; + + if ((float)(v * e_mult) == value) { + length = i; + buffer[i + 1] = 'e'; + break; + } + if (buffer[i] < '9' && (float)(vplus * e_mult) == value) { + buffer[i]++; + length = i; + buffer[i + 1] = 'e'; + break; + } + } + WriteExponent(kk - 1, &buffer[0 + length + 2]); + } + } + } +} + +#ifdef _MSC_VER +#pragma float_control(pop) +#endif diff --git a/dtool/src/dtoolbase/pdtoa.h b/dtool/src/dtoolbase/pdtoa.h index 908ca24deb4..44b0d9e2718 100644 --- a/dtool/src/dtoolbase/pdtoa.h +++ b/dtool/src/dtoolbase/pdtoa.h @@ -16,6 +16,7 @@ extern "C" { #endif EXPCL_DTOOL_DTOOLBASE void pdtoa(double value, char *buffer); +EXPCL_DTOOL_DTOOLBASE void pftoa(float value, char *buffer); #ifdef __cplusplus }; /* end of extern "C" */ diff --git a/dtool/src/dtoolbase/pstrtod.cxx b/dtool/src/dtoolbase/pstrtod.cxx index 933d342f2c6..f6c0a83c3c4 100644 --- a/dtool/src/dtoolbase/pstrtod.cxx +++ b/dtool/src/dtoolbase/pstrtod.cxx @@ -16,9 +16,12 @@ #include #include #include +#include #ifdef _WIN32 #define strncasecmp _strnicmp +#else +#include #endif /** diff --git a/dtool/src/dtoolbase/typeHandle_ext.cxx b/dtool/src/dtoolbase/typeHandle_ext.cxx index 5e0d80f2a83..be97efd0a65 100644 --- a/dtool/src/dtoolbase/typeHandle_ext.cxx +++ b/dtool/src/dtoolbase/typeHandle_ext.cxx @@ -49,19 +49,26 @@ __reduce__() const { PyTypeObject *py_type = _this->get_python_type(); if (py_type != nullptr && py_type->tp_dict != nullptr) { // Look for a get_class_type method, if it returns this handle. - PyObject *func = PyDict_GetItemString(py_type->tp_dict, "get_class_type"); - if (func != nullptr && PyCallable_Check(func)) { - PyObject *result = PyObject_CallNoArgs(func); - TypeHandle *result_handle = nullptr; - if (result == nullptr) { - // Never mind. - PyErr_Clear(); - } - else if (DtoolInstance_GetPointer(result, result_handle, Dtool_TypeHandle) && - *result_handle == *_this) { - // It returned the correct result, so we can use this. - return Py_BuildValue("O()", func); + PyObject *func; + int result = PyDict_GetItemStringRef(py_type->tp_dict, "get_class_type", &func); + if (result > 0) { + if (PyCallable_Check(func)) { + PyObject *result = PyObject_CallNoArgs(func); + TypeHandle *result_handle = nullptr; + if (result == nullptr) { + // Never mind. + PyErr_Clear(); + } + else if (DtoolInstance_GetPointer(result, result_handle, Dtool_TypeHandle) && + *result_handle == *_this) { + // It returned the correct result, so we can use this. + return Py_BuildValue("N()", func); + } } + Py_DECREF(func); + } + else if (result < 0) { + PyErr_Clear(); } } diff --git a/dtool/src/dtoolutil/CMakeLists.txt b/dtool/src/dtoolutil/CMakeLists.txt index 5885534178a..fdab210e145 100644 --- a/dtool/src/dtoolutil/CMakeLists.txt +++ b/dtool/src/dtoolutil/CMakeLists.txt @@ -69,6 +69,8 @@ set(P3DTOOLUTIL_IGATEEXT globPattern_ext.h iostream_ext.cxx iostream_ext.h + pyenv_init.cxx + pyenv_init.h textEncoder_ext.cxx textEncoder_ext.h ) diff --git a/dtool/src/dtoolutil/config_dtoolutil.cxx b/dtool/src/dtoolutil/config_dtoolutil.cxx index b7b6505d28a..0bfa8b4f16d 100644 --- a/dtool/src/dtoolutil/config_dtoolutil.cxx +++ b/dtool/src/dtoolutil/config_dtoolutil.cxx @@ -17,7 +17,7 @@ #include "pandaSystem.h" #if !defined(CPPPARSER) && !defined(LINK_ALL_STATIC) && !defined(BUILDING_DTOOL_DTOOLUTIL) - #error Buildsystem error: BUILDING_DTOOL_DCTOOLUTIL not defined + #error Buildsystem error: BUILDING_DTOOL_DTOOLUTIL not defined #endif /** diff --git a/dtool/src/dtoolutil/console_preamble.js b/dtool/src/dtoolutil/console_preamble.js new file mode 100644 index 00000000000..151f5c1e032 --- /dev/null +++ b/dtool/src/dtoolutil/console_preamble.js @@ -0,0 +1,50 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file console_preamble.js + * @author rdb + * @date 2025-02-03 + */ + +if (ENVIRONMENT_IS_NODE) { + Module["preInit"] = Module["preInit"] || []; + Module["preInit"].push(function() { + if (typeof process === "object" && typeof process.env === "object") { + // These are made up by emscripten if we don't set them to undefined + ENV['USER'] = undefined; + ENV['LOGNAME'] = undefined; + ENV['PATH'] = undefined; + ENV['PWD'] = undefined; + ENV['HOME'] = undefined; + ENV['LANG'] = undefined; + ENV['_'] = undefined; + for (var variable in process.env) { + ENV[variable] = process.env[variable]; + } + } + + addOnPreMain(function preloadNodeEnv() { + var sp = stackSave(); + var set_binary_name = wasmExports["_set_binary_name"]; + if (set_binary_name && typeof __filename === "string") { + set_binary_name(stringToUTF8OnStack(__filename)); + } + + var set_env_var = wasmExports["_set_env_var"]; + if (set_env_var) { + for (var variable in ENV) { + var value = ENV[variable]; + if (value !== undefined) { + set_env_var(stringToUTF8OnStack(variable), stringToUTF8OnStack(value)); + } + } + } + stackRestore(sp); + }); + }); +} diff --git a/dtool/src/dtoolutil/dSearchPath.h b/dtool/src/dtoolutil/dSearchPath.h index 8a13ebf0636..7fcd56a2489 100644 --- a/dtool/src/dtoolutil/dSearchPath.h +++ b/dtool/src/dtoolutil/dSearchPath.h @@ -11,8 +11,8 @@ * @date 2000-07-01 */ -#ifndef PANDASEARCHPATH_H -#define PANDASEARCHPATH_H +#ifndef DSEARCHPATH_H +#define DSEARCHPATH_H #include "dtoolbase.h" diff --git a/dtool/src/dtoolutil/executionEnvironment.cxx b/dtool/src/dtoolutil/executionEnvironment.cxx index eda3dc58fa7..371a2116128 100644 --- a/dtool/src/dtoolutil/executionEnvironment.cxx +++ b/dtool/src/dtoolutil/executionEnvironment.cxx @@ -72,7 +72,7 @@ extern char **environ; // read environment variables at static init time. In this case, we must read // all of the environment variables directly and cache them locally. -#ifndef STATIC_INIT_GETENV +#if !defined(STATIC_INIT_GETENV) || defined(__EMSCRIPTEN__) #define PREREAD_ENVIRONMENT #endif @@ -123,7 +123,20 @@ static const char *const libp3dtool_filenames[] = { }; #endif /* !LINK_ALL_STATIC */ -// Linux with GNU libc does have global argvargc variables, but we can't +#if defined(__EMSCRIPTEN__) && !defined(CPPPARSER) +extern "C" void EMSCRIPTEN_KEEPALIVE +_set_env_var(const char *var, const char *value) { + ExecutionEnvironment *ptr = ExecutionEnvironment::get_ptr(); + ptr->_variables[std::string(var)] = std::string(value); +} + +extern "C" void EMSCRIPTEN_KEEPALIVE +_set_binary_name(const char *path) { + ExecutionEnvironment::set_binary_name(std::string(path)); +} +#endif + +// Linux with GNU libc does have global argv/argc variables, but we can't // safely access them at stat init time--at least, not in libc5. (It does seem // to work with glibc2, however.) @@ -449,7 +462,7 @@ ns_set_environment_variable(const string &var, const string &value) { void ExecutionEnvironment:: ns_shadow_environment_variable(const string &var, const string &value) { _variables[var] = value; - string putstr = var + "=" + value; + //string putstr = var + "=" + value; } /** @@ -577,7 +590,10 @@ read_environment_variables() { } } #elif defined(__EMSCRIPTEN__) - // Emscripten has no environment vars. Don't even try. + // The environment variables get loaded in by the .js file before main() + // using the _set_env_var exported function, defined above. Trying to load + // env vars at static init time otherwise makes some optimizations more + // difficult, notably wasm-ctor-eval/wizer. #elif defined(HAVE_PROC_SELF_ENVIRON) // In some cases, we may have a file called procselfenviron that may be read diff --git a/dtool/src/dtoolutil/executionEnvironment.h b/dtool/src/dtoolutil/executionEnvironment.h index 0ff0814cdd7..ddb83fcecc5 100644 --- a/dtool/src/dtoolutil/executionEnvironment.h +++ b/dtool/src/dtoolutil/executionEnvironment.h @@ -21,6 +21,13 @@ #include +#if defined(__EMSCRIPTEN__) && !defined(CPPPARSER) +extern "C" void EMSCRIPTEN_KEEPALIVE +_set_env_var(const char *var, const char *value); +extern "C" void EMSCRIPTEN_KEEPALIVE +_set_binary_name(const char *path); +#endif + /** * Encapsulates access to the environment variables and command-line arguments * at the time of execution. This is encapsulated to support accessing these @@ -89,6 +96,10 @@ class EXPCL_DTOOL_DTOOLUTIL ExecutionEnvironment { std::string _dtool_name; static ExecutionEnvironment *_global_ptr; + +#ifdef __EMSCRIPTEN__ + friend void ::_set_env_var(const char *var, const char *value); +#endif }; #include "executionEnvironment.I" diff --git a/dtool/src/dtoolutil/filename.I b/dtool/src/dtoolutil/filename.I index 56ba90d838c..c7776673519 100644 --- a/dtool/src/dtoolutil/filename.I +++ b/dtool/src/dtoolutil/filename.I @@ -594,7 +594,7 @@ operator < (const std::string &other) const { */ INLINE int Filename:: compare_to(const Filename &other) const { - return strcmp(_filename.c_str(), other._filename.c_str()); + return _filename.compare(other._filename); } diff --git a/dtool/src/dtoolutil/filename_ext.cxx b/dtool/src/dtoolutil/filename_ext.cxx index cc67d9dd2e7..12b85111d07 100644 --- a/dtool/src/dtoolutil/filename_ext.cxx +++ b/dtool/src/dtoolutil/filename_ext.cxx @@ -33,10 +33,17 @@ __init__(PyObject *path) { Py_ssize_t length; if (PyUnicode_CheckExact(path)) { - wchar_t *data; - data = PyUnicode_AsWideCharString(path, &length); - (*_this) = wstring(data, length); - PyMem_Free(data); + if (Filename::get_filesystem_encoding() == TextEncoder::E_utf8) { + const char *data = PyUnicode_AsUTF8AndSize(path, &length); + if (data != nullptr) { + (*_this) = string(data, length); + } + } else { + wchar_t *data; + data = PyUnicode_AsWideCharString(path, &length); + (*_this) = wstring(data, length); + PyMem_Free(data); + } return; } @@ -47,7 +54,7 @@ __init__(PyObject *path) { return; } - if (Py_TYPE(path) == &Dtool_Filename._PyType) { + if (Py_IS_TYPE(path, Dtool_GetPyTypeObject(&Dtool_Filename))) { // Copy constructor. *_this = *(Filename *)DtoolInstance_VOID_PTR(path); return; @@ -67,10 +74,17 @@ __init__(PyObject *path) { } if (PyUnicode_CheckExact(path_str)) { - wchar_t *data; - data = PyUnicode_AsWideCharString(path_str, &length); - (*_this) = Filename::from_os_specific_w(wstring(data, length)); - PyMem_Free(data); + if (Filename::get_filesystem_encoding() == TextEncoder::E_utf8) { + const char *data = PyUnicode_AsUTF8AndSize(path_str, &length); + if (data != nullptr) { + (*_this) = Filename::from_os_specific(string(data, length)); + } + } else { + wchar_t *data; + data = PyUnicode_AsWideCharString(path_str, &length); + (*_this) = Filename::from_os_specific_w(wstring(data, length)); + PyMem_Free(data); + } } else if (PyBytes_CheckExact(path_str)) { char *data; diff --git a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx index ceb2f01bf1f..3a8de69d4d8 100644 --- a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx +++ b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx @@ -1,4 +1,5 @@ #include "filename_ext.cxx" #include "globPattern_ext.cxx" #include "iostream_ext.cxx" +#include "pyenv_init.cxx" #include "textEncoder_ext.cxx" diff --git a/dtool/src/dtoolutil/pfstreamBuf.cxx b/dtool/src/dtoolutil/pfstreamBuf.cxx index f746ca5ac96..a9a2abd12ad 100644 --- a/dtool/src/dtoolutil/pfstreamBuf.cxx +++ b/dtool/src/dtoolutil/pfstreamBuf.cxx @@ -185,7 +185,7 @@ is_open() const { */ bool PipeStreamBuf:: eof_pipe() const { - return (_pipe == nullptr) && feof(_pipe); + return (_pipe == nullptr) || feof(_pipe); } /** diff --git a/dtool/src/dtoolutil/pyenv_init.cxx b/dtool/src/dtoolutil/pyenv_init.cxx new file mode 100644 index 00000000000..d806a8ef7c5 --- /dev/null +++ b/dtool/src/dtoolutil/pyenv_init.cxx @@ -0,0 +1,80 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file pyenv_init.cxx + * @author rdb + * @date 2025-02-02 + */ + +#include "pyenv_init.h" +#include "py_panda.h" +#include "executionEnvironment.h" + +/** + * Called when panda3d.core is initialized, does some initialization specific + * to the Python environment. + */ +void +pyenv_init() { + // MAIN_DIR needs to be set very early; this seems like a convenient place + // to do that. Perhaps we'll find a better place for this in the future. + static bool initialized_main_dir = false; + if (!initialized_main_dir) { + /*if (interrogatedb_cat.is_debug()) { + // Good opportunity to print this out once, at startup. + interrogatedb_cat.debug() + << "Python " << version << "\n"; + }*/ + + if (!ExecutionEnvironment::has_environment_variable("MAIN_DIR")) { + // Grab the __main__ module and extract its __file__ attribute. + Filename main_dir; + PyObject *main_module = PyImport_ImportModule("__main__"); + PyObject *file_attr = nullptr; + if (main_module != nullptr) { + file_attr = PyObject_GetAttrString(main_module, "__file__"); + } else { + std::cerr << "Warning: unable to import __main__\n"; + } + if (file_attr == nullptr) { + // Must be running in the interactive interpreter. Use the CWD. + main_dir = ExecutionEnvironment::get_cwd(); + } else { +#if PY_MAJOR_VERSION >= 3 + Py_ssize_t length; + wchar_t *buffer = PyUnicode_AsWideCharString(file_attr, &length); + if (buffer != nullptr) { + main_dir = Filename::from_os_specific_w(std::wstring(buffer, length)); + main_dir.make_absolute(); + main_dir = main_dir.get_dirname(); + PyMem_Free(buffer); + } +#else + char *buffer; + Py_ssize_t length; + if (PyString_AsStringAndSize(file_attr, &buffer, &length) != -1) { + main_dir = Filename::from_os_specific(std::string(buffer, length)); + main_dir.make_absolute(); + main_dir = main_dir.get_dirname(); + } +#endif + else { + std::cerr << "Invalid string for __main__.__file__\n"; + } + } + ExecutionEnvironment::shadow_environment_variable("MAIN_DIR", main_dir.to_os_specific()); + PyErr_Clear(); + } + initialized_main_dir = true; + } + + // Also, while we are at it, initialize the thread swap hook. +#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) + global_thread_state_swap = PyThreadState_Swap; +#endif +} diff --git a/dtool/src/cppparser/cppCommentBlock.cxx b/dtool/src/dtoolutil/pyenv_init.h similarity index 75% rename from dtool/src/cppparser/cppCommentBlock.cxx rename to dtool/src/dtoolutil/pyenv_init.h index 46865ba44d7..2369ca1871b 100644 --- a/dtool/src/cppparser/cppCommentBlock.cxx +++ b/dtool/src/dtoolutil/pyenv_init.h @@ -6,9 +6,9 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * @file cppCommentBlock.cxx - * @author drose - * @date 2000-08-15 + * @file pyenv_init.h + * @author rdb + * @date 2025-02-02 */ -#include "cppCommentBlock.h" +extern "C" void pyenv_init(); diff --git a/dtool/src/dtoolutil/string_utils.I b/dtool/src/dtoolutil/string_utils.I index 1861e86ffae..d821deffdff 100644 --- a/dtool/src/dtoolutil/string_utils.I +++ b/dtool/src/dtoolutil/string_utils.I @@ -32,7 +32,7 @@ format_string(bool value) { INLINE std::string format_string(float value) { char buffer[32]; - pdtoa((double)value, buffer); + pftoa(value, buffer); return std::string(buffer); } diff --git a/dtool/src/interrogate/CMakeLists.txt b/dtool/src/interrogate/CMakeLists.txt deleted file mode 100644 index 1ecba4623dc..00000000000 --- a/dtool/src/interrogate/CMakeLists.txt +++ /dev/null @@ -1,128 +0,0 @@ -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() diff --git a/dtool/src/interrogate/README.md b/dtool/src/interrogate/README.md deleted file mode 100644 index 4da044c8b50..00000000000 --- a/dtool/src/interrogate/README.md +++ /dev/null @@ -1,28 +0,0 @@ -A key advantage of Panda3D is that it provides developers with the -ability to use both C++ and Python simultaneously. Essentially, Panda3D -gives programmers the best of both worlds, as they are able to take -advantage of the high performance and low-level programming found in -C++ in addition to the flexibility, interactive scripting, and -rapid-prototyping capabilities of Python. This feature is made possible -due to Python’s ability to call C libraries, and ultimately make use of -Panda3D’s Interrogate System: an automated C++ Extension Module -generation utility similar to SWIG. Although Python is the favored -scripting language of Panda3D, the engine is highly extensible in this -aspect, as any language that has a foreign function interface can make -use of the Interrogate System. - -The Interrogate System works like a compiler by scanning and parsing -C++ code for the Panda3D-specific, “PUBLISHED†keyword. This keyword -marks the particular methods of a class that are to be exposed within a -C++ Extension Module for that class which is eventually generated. One -benefit of using the “PUBLISHED†keyword is that it alleviates the need -for an interface file that provides function prototypes for the class -methods that will be exposed within the extension module, as is the -case with SWIG. Interrogate turns a class into a loose collection of -Python interface wrapper functions that make up the C++ Extension -Module. - -This package depends on the 'cppparser' package, which contains the -code that parses the C++ headers, and the 'interrogatedb' package, -which contains the intermediate representation of the interfaces that -can be saved to a database file for FFI generation tools to consume. diff --git a/dtool/src/interrogate/functionRemap.cxx b/dtool/src/interrogate/functionRemap.cxx deleted file mode 100644 index b6925770675..00000000000 --- a/dtool/src/interrogate/functionRemap.cxx +++ /dev/null @@ -1,1030 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionRemap.cxx - * @author drose - * @date 2001-09-19 - */ - -#include "functionRemap.h" -#include "typeManager.h" -#include "interrogate.h" -#include "parameterRemap.h" -#include "parameterRemapThis.h" -#include "parameterRemapHandleToInt.h" -#include "parameterRemapUnchanged.h" -#include "interfaceMaker.h" -#include "interrogateBuilder.h" - -#include "interrogateDatabase.h" -#include "cppExpression.h" -#include "cppInstance.h" -#include "cppArrayType.h" -#include "cppConstType.h" -#include "cppFunctionType.h" -#include "cppParameterList.h" -#include "cppReferenceType.h" -#include "interrogateType.h" -#include "pnotify.h" - -using std::ostream; -using std::ostringstream; -using std::string; - -/** - * - */ -FunctionRemap:: -FunctionRemap(const InterrogateType &itype, const InterrogateFunction &ifunc, - CPPInstance *cppfunc, int num_default_parameters, - InterfaceMaker *interface_maker) { - _return_type = nullptr; - _void_return = true; - _ForcedVoidReturn = false; - _has_this = false; - _blocking = false; - _extension = false; - _const_method = false; - _first_true_parameter = 0; - _num_default_parameters = num_default_parameters; - _type = T_normal; - _flags = 0; - _args_type = 0; - _wrapper_index = 0; - - _return_value_needs_management = false; - _return_value_destructor = 0; - _manage_reference_count = false; - - _cppfunc = cppfunc; - _ftype = _cppfunc->_type->as_function_type(); - _cpptype = itype._cpptype; - _cppscope = itype._cppscope; - - _is_valid = setup_properties(ifunc, interface_maker); -} - -/** - * - */ -FunctionRemap:: -~FunctionRemap() { -} - -/** - * Returns a string that will be a suitable name for the nth parameter in the - * generated code. This may not correspond to the name of the parameter in - * the original code. - */ -string FunctionRemap:: -get_parameter_name(int n) const { - ostringstream str; - str << "param" << n; - return str.str(); -} - -/** - * Writes a sequence of commands to the given output stream to call the - * wrapped function. The parameter values are assumed to be simply the names - * of the parameters. - * - * The return value is the expression to return, if we are returning a value, - * or the empty string if we return nothing. - */ -string FunctionRemap:: -call_function(ostream &out, int indent_level, bool convert_result, - const string &container) const { - vector_string pexprs; - for (size_t i = 0; i < _parameters.size(); ++i) { - pexprs.push_back(get_parameter_name(i)); - } - return call_function(out, indent_level, convert_result, container, pexprs); -} - -/** - * Writes a sequence of commands to the given output stream to call the - * wrapped function. The parameter values are taken from pexprs. - * - * The return value is the expression to return, if we are returning a value, - * or the empty string if we return nothing. - */ -string FunctionRemap:: -call_function(ostream &out, int indent_level, bool convert_result, - const string &container, const vector_string &pexprs) const { - string return_expr; - - if (_type == T_destructor) { - // A destructor wrapper is just a wrapper around the delete operator. - assert(!container.empty()); - assert(_cpptype != nullptr); - - if (TypeManager::is_reference_count(_cpptype)) { - // Except for a reference-count type object, in which case the - // destructor is a wrapper around unref_delete(). - InterfaceMaker::indent(out, indent_level) - << "unref_delete(" << container << ");\n"; - } else { - InterfaceMaker::indent(out, indent_level) << "delete " << container << ";\n"; - } - - } else if (_type == T_typecast_method) { - // A typecast method can be invoked implicitly. - ostringstream cast_expr; - cast_expr << "(" - << _return_type->get_orig_type()->get_local_name(&parser) << ")"; - - _parameters[0]._remap->pass_parameter(cast_expr, container); - - if (!convert_result) { - return_expr = cast_expr.str(); - } else { - string new_str = - _return_type->prepare_return_expr(out, indent_level, cast_expr.str()); - return_expr = _return_type->get_return_expr(new_str); - } - - } else if (_type == T_typecast) { - // A regular typecast converts from a pointer type to another pointer - // type. (This is different from the typecast method, above, which - // converts from the concrete type to some other type.) - assert(!container.empty()); - string cast_expr = - "(" + _return_type->get_orig_type()->get_local_name(&parser) + - ")" + container; - - if (!convert_result) { - return_expr = cast_expr; - } else { - string new_str = - _return_type->prepare_return_expr(out, indent_level, cast_expr); - return_expr = _return_type->get_return_expr(new_str); - } - - } else if (_type == T_constructor) { - // A special case for constructors. - if (_extension) { - // Extension constructors are a special case. We assume there is a - // default constructor for the class, and the actual construction is - // done by an __init__ method. - InterfaceMaker::indent(out, indent_level); - _return_type->get_new_type()->output_instance(out, "result", &parser); - out << " = new " << _cpptype->get_local_name(&parser) << ";\n"; - - InterfaceMaker::indent(out, indent_level) - << get_call_str("result", pexprs) << ";\n"; - - return_expr = "result"; - - } else { - string defconstruct = builder.in_defconstruct(_cpptype->get_local_name(&parser)); - string call_expr; - - if (pexprs.empty() && !defconstruct.empty()) { - call_expr = defconstruct; - } else { - call_expr = get_call_str(container, pexprs); - } - - if (!_return_type->return_value_needs_management()) { - return_expr = _return_type->get_return_expr(call_expr); - } else { - return_expr = "new " + call_expr; - } - } - if (_void_return) { - nout << "Error, constructor for " << *_cpptype << " returning void.\n"; - return_expr = ""; - } - - } else if (_type == T_assignment_method) { - // Another special case for assignment operators. - assert(!container.empty()); - InterfaceMaker::indent(out, indent_level) - << get_call_str(container, pexprs) << ";\n"; - - string this_expr = container; - string ref_expr = "*" + this_expr; - - if (!convert_result) { - return_expr = ref_expr; - } else { - string new_str = - _return_type->prepare_return_expr(out, indent_level, ref_expr); - return_expr = _return_type->get_return_expr(new_str); - - // Now a simple special-case test. Often, we will have converted the - // reference-returning assignment operator to a pointer. In this case, - // we might inadvertently generate code like "return &(*this)", when - // "return this" would do. We check for this here and undo it as a - // special case. - - // There's no real good reason to do this, other than that it feels more - // satisfying to a casual perusal of the generated code. It *is* - // conceivable that some broken compilers wouldn't like "&(*this)", - // though. - - if (return_expr == "&(" + ref_expr + ")" || - return_expr == "&" + ref_expr) { - return_expr = this_expr; - } - } - - } else if (_void_return) { - InterfaceMaker::indent(out, indent_level) - << get_call_str(container, pexprs) << ";\n"; - - } else { - string call = get_call_str(container, pexprs); - - if (!convert_result) { - return_expr = call; - - } else { - // if (_return_type->return_value_should_be_simple()) { - if (false) { - // We have to assign the result to a temporary first; this makes it a - // bit easier on poor old VC++. - InterfaceMaker::indent(out, indent_level); - _return_type->get_orig_type()->output_instance(out, "result", - &parser); - out << " = " << call << ";\n"; - - // Use of the C++11 std::move function basically turns an lvalue into - // an rvalue, allowing a move constructor to be called instead of a - // copy constructor (since we won't be using the return value any - // more), which is usually more efficient if it exists. If it - // doesn't, it shouldn't do any harm. - string new_str = - _return_type->prepare_return_expr(out, indent_level, "std::move(result)"); - return_expr = _return_type->get_return_expr(new_str); - - } else { - // This should be simple enough that we can return it directly. - string new_str = - _return_type->prepare_return_expr(out, indent_level, call); - return_expr = _return_type->get_return_expr(new_str); - } - } - } - - return return_expr; -} - -/** - * Writes a line describing the original C++ method or function. This is - * generally useful only within a comment. - */ -void FunctionRemap:: -write_orig_prototype(ostream &out, int indent_level, bool local, int num_default_args) const { - if (local) { - _cppfunc->output(out, indent_level, nullptr, false, num_default_args); - } else { - _cppfunc->output(out, indent_level, &parser, false, num_default_args); - } -} - -/** - * Creates an InterrogateFunctionWrapper object corresponding to this callable - * instance and stores it in the database. - */ -FunctionWrapperIndex FunctionRemap:: -make_wrapper_entry(FunctionIndex function_index) { - _wrapper_index = - InterrogateDatabase::get_ptr()->get_next_index(); - - InterrogateFunctionWrapper iwrapper; - iwrapper._function = function_index; - iwrapper._name = _wrapper_name; - iwrapper._unique_name = _unique_name; - - if (_cppfunc->_leading_comment != nullptr) { - iwrapper._comment = InterrogateBuilder::trim_blanks(_cppfunc->_leading_comment->_comment); - } - - if (output_function_names) { - // If we're keeping the function names, record that the wrapper is - // callable. - iwrapper._flags |= InterrogateFunctionWrapper::F_callable_by_name; - } - - if (_flags & F_copy_constructor) { - iwrapper._flags |= InterrogateFunctionWrapper::F_copy_constructor; - } - - if (_flags & F_coerce_constructor) { - iwrapper._flags |= InterrogateFunctionWrapper::F_coerce_constructor; - } - - if (_extension) { - iwrapper._flags |= InterrogateFunctionWrapper::F_extension; - } - - if (_cppfunc->_attributes.has_attribute("deprecated")) { - iwrapper._flags |= InterrogateFunctionWrapper::F_deprecated; - } - - Parameters::const_iterator pi; - for (pi = _parameters.begin(); - pi != _parameters.end(); - ++pi) { - InterrogateFunctionWrapper::Parameter param; - param._parameter_flags = 0; - if ((*pi)._remap->new_type_is_atomic_string()) { - param._type = builder.get_atomic_string_type(); - } else { - param._type = builder.get_type((*pi)._remap->get_new_type(), false); - } - param._name = (*pi)._name; - if ((*pi)._has_name) { - param._parameter_flags |= InterrogateFunctionWrapper::PF_has_name; - } - if ((*pi)._remap->has_default_value()) { - param._parameter_flags |= InterrogateFunctionWrapper::PF_is_optional; - } - iwrapper._parameters.push_back(param); - } - - if (_has_this) { - // If one of the parameters is "this", it must be the first one. - assert(!iwrapper._parameters.empty()); - iwrapper._parameters.front()._parameter_flags |= - InterrogateFunctionWrapper::PF_is_this; - } - - if (!_void_return) { - iwrapper._flags |= InterrogateFunctionWrapper::F_has_return; - } - - if (_return_type->new_type_is_atomic_string()) { - iwrapper._return_type = builder.get_atomic_string_type(); - } else { - iwrapper._return_type = - builder.get_type(_return_type->get_new_type(), false); - } - - if (_return_value_needs_management) { - iwrapper._flags |= InterrogateFunctionWrapper::F_caller_manages; - FunctionIndex destructor = _return_value_destructor; - - if (destructor != 0) { - iwrapper._return_value_destructor = destructor; - - } else { - // We don't need to report this warning, since the FFI code understands - // that if the destructor function is zero, it should use the regular - // class destructor. - - // nout << "Warning! Destructor for " << *_return_type->get_orig_type() - // << " is unavailable.\n" << " Cannot manage return value for:\n " << - // description << "\n"; - } - } - - InterrogateDatabase::get_ptr()->add_wrapper(_wrapper_index, iwrapper); - return _wrapper_index; -} - -/** - * Returns a string suitable for calling the wrapped function. If pexprs is - * nonempty, it represents the list of expressions that will evaluate to each - * parameter value. - */ -string FunctionRemap:: -get_call_str(const string &container, const vector_string &pexprs) const { - // Build up the call to the actual function. - ostringstream call; - - // Getters and setters are a special case. - if (_type == T_getter) { - if (_has_this && !container.empty()) { - call << "(" << container << ")->" << _expression; - } else { - call << _expression; - } - - } else if (_type == T_setter) { - string expr; - if (_has_this && !container.empty()) { - expr = "(" + container + ")->" + _expression; - } else { - expr = _expression; - } - - // It's not possible to assign arrays in C++, we have to copy them. - bool paren_close = false; - CPPType *param_type = _parameters[_first_true_parameter]._remap->get_orig_type(); - CPPArrayType *array_type = param_type->as_array_type(); - if (array_type != nullptr) { - call << "std::copy(" << expr << ", " << expr << " + " << *array_type->_bounds << ", "; - paren_close = true; - } - else if (TypeManager::is_pointer_to_PyObject(param_type)) { - call << "Dtool_Assign_PyObject(" << expr << ", "; - paren_close = true; - } - else { - call << expr << " = "; - } - - _parameters[_first_true_parameter]._remap->pass_parameter(call, - get_parameter_expr(_first_true_parameter, pexprs)); - - if (paren_close) { - call << ')'; - } - - } else if (_type == T_item_assignment_operator) { - call << "("; - _parameters[0]._remap->pass_parameter(call, container); - call << ")["; - - size_t pn = _first_true_parameter; - _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs)); - call << "] = "; - ++pn; - _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs)); - - } else { - // If this function is marked as having an extension function, call that - // instead. - if (_extension) { - if (!container.empty()) { - call << "invoke_extension(" << container << ")."; - } else { - call << "Extension<" << _cpptype->get_local_name(&parser) << ">::"; - } - - if (_type == T_constructor) { - // Constructor extensions are named __init__, by convention. - call << "__init__"; - } else { - call << _cppfunc->get_local_name(); - } - } else { - if (_type == T_constructor) { - // Constructors are called differently. - call << _cpptype->get_local_name(&parser); - - } else if (_has_this && !container.empty()) { - // If we have a "this" parameter, the calling convention is also a bit - // different. - call << "(("; - _parameters[0]._remap->pass_parameter(call, container); - call << ")." << _cppfunc->get_local_name() << ")"; - - } else { - call << "("; - if (_cpptype != nullptr) { - call << _cpptype->get_local_name(&parser); - } - call << "::" << _cppfunc->get_local_name() << ")"; - } - } - call << "("; - write_call_args(call, pexprs); - call << ")"; - } - - return call.str(); -} - -/** - * Writes the arguments to pass to the function. - */ -void FunctionRemap:: -write_call_args(std::ostream &call, const vector_string &pexprs) const { - const char *separator = ""; - if (_flags & F_explicit_self) { - // Pass on the PyObject * that we stripped off above. - call << separator << "self"; - separator = ", "; - } - if (_flags & F_explicit_cls) { - call << separator << "cls"; - separator = ", "; - } - - size_t pn; - size_t num_parameters = pexprs.size(); - - for (pn = _first_true_parameter; - pn < num_parameters; ++pn) { - nassertd(pn < _parameters.size()) break; - call << separator; - _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs)); - separator = ", "; - } -} - -/** - * Returns the minimum number of arguments that needs to be passed to this - * function. - */ -int FunctionRemap:: -get_min_num_args() const { - int min_num_args = 0; - Parameters::const_iterator pi; - pi = _parameters.begin(); - if (_has_this && pi != _parameters.end()) { - ++pi; - } - for (; pi != _parameters.end(); ++pi) { - ParameterRemap *param = (*pi)._remap; - if (param->get_default_value() != nullptr) { - // We've reached the first parameter that takes a default value. - break; - } else { - ++min_num_args; - } - } - return min_num_args; -} - -/** - * Returns the maximum number of arguments that can be passed to this - * function. - */ -int FunctionRemap:: -get_max_num_args() const { - int max_num_args = _parameters.size(); - if (_has_this && _type != FunctionRemap::T_constructor) { - --max_num_args; - } - return max_num_args; -} - -/** - * Returns a string that represents the expression associated with the nth - * parameter. This is just the nth element of pexprs if it is nonempty, or - * the name of the nth parameter is it is empty. - */ -string FunctionRemap:: -get_parameter_expr(size_t n, const vector_string &pexprs) const { - if (n < pexprs.size()) { - return pexprs[n]; - } - return get_parameter_name(n); -} - -/** - * Sets up the properties of the function appropriately. Returns true if - * successful, or false if there is something unacceptable about the function. - */ -bool FunctionRemap:: -setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_maker) { - _function_signature = - TypeManager::get_function_signature(_cppfunc, _num_default_parameters); - _expression = ifunc._expression; - - if ((_ftype->_flags & CPPFunctionType::F_constructor) != 0) { - _type = T_constructor; - - } else if ((_ftype->_flags & CPPFunctionType::F_destructor) != 0) { - _type = T_destructor; - - } else if ((_ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) { - _type = T_typecast_method; - - } else if ((ifunc._flags & InterrogateFunction::F_typecast) != 0) { - _type = T_typecast; - - } else if ((ifunc._flags & InterrogateFunction::F_getter) != 0) { - _type = T_getter; - - } else if ((ifunc._flags & InterrogateFunction::F_setter) != 0) { - _type = T_setter; - - } else if ((ifunc._flags & InterrogateFunction::F_item_assignment) != 0) { - _type = T_item_assignment_operator; - } - - if ((_cppfunc->_storage_class & CPPInstance::SC_blocking) != 0) { - // If it's marked as a "blocking" method or function, record that. - _blocking = true; - } - if ((_cppfunc->_storage_class & CPPInstance::SC_extension) != 0) { - // Same with functions or methods marked with "extension". - _extension = true; - } - - string fname = _cppfunc->get_simple_name(); - CPPType *rtype = _ftype->_return_type->resolve_type(&parser, _cppscope); - - if (_cpptype != nullptr && - ((_cppfunc->_storage_class & CPPInstance::SC_static) == 0) && - _type != T_constructor) { - - // If this is a method, but not a static method, and not a constructor, - // then we need a "this" parameter. - _has_this = true; - _const_method = (_ftype->_flags & CPPFunctionType::F_const_method) != 0; - - if (interface_maker->synthesize_this_parameter()) { - // If the interface_maker demands it, the "this" parameter is treated as - // any other parameter, and inserted at the beginning of the parameter - // list. - Parameter param; - param._name = "this"; - param._has_name = true; - if (_const_method) { - CPPType *const_type = CPPType::new_type(new CPPConstType(_cpptype)); - param._remap = interface_maker->remap_parameter(_cpptype, const_type); - } else { - param._remap = interface_maker->remap_parameter(_cpptype, _cpptype); - } - // param._remap = new ParameterRemapThis(_cpptype, _const_method); - _parameters.push_back(param); - _first_true_parameter = 1; - } - - // Also check the name of the function. If it's one of the assignment- - // style operators, flag it as such. - if (fname == "operator =" || - fname == "operator *=" || - fname == "operator /=" || - fname == "operator %=" || - fname == "operator +=" || - fname == "operator -=" || - fname == "operator |=" || - fname == "operator &=" || - fname == "operator ^=" || - fname == "operator <<=" || - fname == "operator >>=") { - _type = T_assignment_method; - } - } - - const CPPParameterList::Parameters ¶ms = - _ftype->_parameters->_parameters; - for (int i = 0; i < (int)params.size() - _num_default_parameters; i++) { - // CPPType *type = params[i]->_type->resolve_type(&parser, _cppscope); - CPPType *type = params[i]->_type; - Parameter param; - param._has_name = true; - param._name = params[i]->get_simple_name(); - - if (param._name.empty()) { - // If the parameter has no name, record it as being nameless, but also - // synthesize one in case someone asks anyway. - param._has_name = false; - ostringstream param_name; - param_name << "param" << i; - param._name = param_name.str(); - } - - param._remap = interface_maker->remap_parameter(_cpptype, type); - if (param._remap == nullptr) { - // If we can't handle one of the parameter types, we can't call the - // function. - if (fname == "__traverse__") { - // Hack to record this even though we can't wrap visitproc. - param._remap = new ParameterRemapUnchanged(type); - } else { - // nout << "Can't handle parameter " << i << " of method " << - // *_cppfunc << "\n"; - return false; - } - } else { - param._remap->set_default_value(params[i]->_initializer); - } - - if (!param._remap->is_valid()) { - nout << "Invalid remap for parameter " << i << " of method " << *_cppfunc << "\n"; - return false; - } - - _parameters.push_back(param); - } - - if (_type == T_constructor) { - // Constructors are a special case. These appear to return void as seen - // by the parser, but we know they actually return a new concrete - // instance. - - if (_cpptype == nullptr) { - nout << "Method " << *_cppfunc << " has no struct type\n"; - return false; - } - - _return_type = interface_maker->remap_parameter(_cpptype, _cpptype); - if (_return_type != nullptr) { - _void_return = false; - } - - } else if (_type == T_assignment_method) { - // Assignment-type methods are also a special case. We munge these to - // return *this, which is a semi-standard C++ convention anyway. We just - // enforce it. - - if (_cpptype == nullptr) { - nout << "Method " << *_cppfunc << " has no struct type\n"; - return false; - } else { - CPPType *ref_type = CPPType::new_type(new CPPReferenceType(_cpptype)); - _return_type = interface_maker->remap_parameter(_cpptype, ref_type); - if (_return_type != nullptr) { - _void_return = false; - } - } - - } else if (fname == "operator <=>") { - // This returns an opaque object that we must leave unchanged. - _return_type = new ParameterRemapUnchanged(rtype); - _void_return = false; - - } else { - // The normal case. - _return_type = interface_maker->remap_parameter(_cpptype, rtype); - if (_return_type != nullptr) { - _void_return = TypeManager::is_void(rtype); - } - } - - if (_return_type == nullptr || - !_return_type->is_valid()) { - // If our return type isn't something we can deal with, treat the function - // as if it returns NULL. - _void_return = true; - _ForcedVoidReturn = true; - CPPType *void_type = TypeManager::get_void_type(); - _return_type = interface_maker->remap_parameter(_cpptype, void_type); - assert(_return_type != nullptr); - } - - // Do we need to manage the return value? - _return_value_needs_management = - _return_type->return_value_needs_management(); - _return_value_destructor = - _return_type->get_return_value_destructor(); - - // Should we manage a reference count? - CPPType *return_type = _return_type->get_new_type(); - return_type = TypeManager::resolve_type(return_type, _cppscope); - CPPType *return_meat_type = TypeManager::unwrap_pointer(return_type); - - if (manage_reference_counts && - TypeManager::is_reference_count_pointer(return_type) && - !TypeManager::has_protected_destructor(return_meat_type)) { - // Yes! - _manage_reference_count = true; - _return_value_needs_management = true; - - // This is problematic, because we might not have the class in question - // fully defined here, particularly if the class is defined in some other - // library. - _return_value_destructor = builder.get_destructor_for(return_meat_type); - } - - if (_type == T_getter && TypeManager::is_pointer_to_PyObject(return_type)) { - _manage_reference_count = true; - _return_value_needs_management = true; - } - - // Check for a special meaning by name and signature. - size_t first_param = 0; - if (_has_this) { - first_param = 1; - } - - if (_parameters.size() > first_param && - TypeManager::is_pointer_to_PyObject(_parameters[first_param]._remap->get_orig_type())) { - // Here's a special case. If the first parameter of a nonstatic method - // is a PyObject * called "self", then we will automatically fill it in - // from the this pointer, and remove it from the generated parameter list. - // For static methods, we offer "cls" instead, containing the type object. - if (_parameters[first_param]._name == "self") { - _parameters.erase(_parameters.begin() + first_param); - _flags |= F_explicit_self; - } - else if (!_has_this && _parameters[first_param]._name == "cls") { - _parameters.erase(_parameters.begin() + first_param); - _flags |= F_explicit_cls; - } - } - - if (_parameters.size() == first_param) { - _args_type = InterfaceMaker::AT_no_args; - } else if (_parameters.size() == first_param + 1 && - _parameters[first_param]._remap->get_default_value() == nullptr) { - _args_type = InterfaceMaker::AT_single_arg; - } else { - _args_type = InterfaceMaker::AT_varargs; - - // If the arguments are named "args" and "kwargs", we will be directly - // passing the argument tuples to the function. - if (_parameters.size() == first_param + 2 && - _parameters[first_param]._name == "args" && - (_parameters[first_param + 1]._name == "kwargs" || - _parameters[first_param + 1]._name == "kwds")) { - _flags |= F_explicit_args; - _args_type = InterfaceMaker::AT_keyword_args; - } - } - - switch (_type) { - case T_normal: - if (fname == "operator []" || fname == "__getitem__") { - _flags |= F_getitem; - if (_has_this && _parameters.size() == 2) { - if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) { - // It receives a single int parameter. - _flags |= F_getitem_int; - } - } - - } else if (fname == "__setitem__") { - if (_has_this && _parameters.size() > 2) { - _flags |= F_setitem; - if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) { - // Its first parameter is an int parameter, presumably an index. - _flags |= F_setitem_int; - _args_type = InterfaceMaker::AT_varargs; - } - } - - } else if (fname == "__delitem__") { - if (_has_this && _parameters.size() == 2) { - _flags |= F_delitem; - if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) { - // Its first parameter is an int parameter, presumably an index. - _flags |= F_delitem_int; - _args_type = InterfaceMaker::AT_single_arg; - } - } - - } else if (fname == "size" || fname == "__len__") { - if (_parameters.size() == first_param && - TypeManager::is_integer(_return_type->get_new_type())) { - // It receives no parameters, and returns an integer. - _flags |= F_size; - } - - } else if (fname == "make_copy") { - if (_has_this && _parameters.size() == 1 && - TypeManager::is_pointer(_return_type->get_new_type())) { - // It receives no parameters, and returns a pointer. - _flags |= F_make_copy; - } - - } else if (fname == "__iter__") { - if (_parameters.size() == first_param && - TypeManager::is_pointer(_return_type->get_new_type())) { - // It receives no parameters, and returns a pointer. - _flags |= F_iter; - } - - } else if (fname == "compare_to") { - if (_has_this && _parameters.size() == 2 && - TypeManager::is_integer(_return_type->get_new_type())) { - // It receives one parameter, and returns an integer. - _flags |= F_compare_to; - } - - } else if (fname == "make") { - if (!_has_this && _parameters.size() >= 1 && - TypeManager::is_pointer(_return_type->get_new_type())) { - // We can use this for coercion, except if this is a kwargs param that - // does not have a default value. - if ((_flags & F_explicit_args) == 0 || - _parameters.size() != first_param + 2 || - _parameters[first_param + 1]._remap->has_default_value()) { - _flags |= F_coerce_constructor; - } - } - - if (_args_type == InterfaceMaker::AT_varargs) { - // Of course methods named "make" can still take kwargs, if they are - // named. - for (size_t i = first_param; i < _parameters.size(); ++i) { - if (_parameters[i]._has_name) { - _args_type = InterfaceMaker::AT_keyword_args; - break; - } - } - } - - } else if (fname == "operator /") { - if (_has_this && _parameters.size() == 2 && - TypeManager::is_integer(_parameters[1]._remap->get_new_type())) { - // This division operator takes a single integer argument. - _flags |= F_divide_integer; - } - - } else if (fname == "get_key" || fname == "get_hash") { - if (_has_this && _parameters.size() == 1 && - TypeManager::is_integer(_return_type->get_new_type())) { - _flags |= F_hash; - } - - } else if (fname == "operator ()" || fname == "__call__") { - // Call operators always take keyword arguments. - _args_type = InterfaceMaker::AT_keyword_args; - - } else if (fname == "__setattr__" - || fname == "__getattr__" - || fname == "__delattr__") { - // Just to prevent these from getting keyword arguments. - - } else if (fname == "__setstate__") { - _args_type = InterfaceMaker::AT_single_arg; - - } else { - if (_args_type == InterfaceMaker::AT_varargs) { - // Every other method can take keyword arguments, if they take more - // than one argument, and the arguments are named. - for (size_t i = first_param; i < _parameters.size(); ++i) { - if (_parameters[i]._has_name) { - _args_type |= InterfaceMaker::AT_keyword_args; - break; - } - } - } else if (_args_type == InterfaceMaker::AT_single_arg) { - // If it takes an argument named "args", we are directly passing the - // "args" tuple to the function. - if (_parameters[first_param]._name == "args") { - _flags |= F_explicit_args; - _args_type = InterfaceMaker::AT_varargs; - } - } - } - break; - - case T_assignment_method: - if (fname == "operator /=") { - if (_has_this && _parameters.size() == 2 && - TypeManager::is_integer(_parameters[1]._remap->get_new_type())) { - // This division operator takes a single integer argument. - _flags |= F_divide_integer; - } - } - break; - - case T_item_assignment_operator: - // The concept of "item assignment operator" doesn't really exist in C++, - // but it does in scripting languages, and this allows us to wrap cases - // where the C++ getitem returns an assignable reference. - _flags |= F_setitem; - if (_has_this && _parameters.size() > 2) { - if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) { - // Its first parameter is an int parameter, presumably an index. - _flags |= F_setitem_int; - } - } - _args_type = InterfaceMaker::AT_varargs; - break; - - case T_constructor: - if (_ftype->_flags & CPPFunctionType::F_copy_constructor) { - // It's a copy constructor. - _flags |= F_copy_constructor; - - } else if (_ftype->_flags & CPPFunctionType::F_move_constructor) { - - } else if (!_has_this && _parameters.size() > 0 && - (_cppfunc->_storage_class & CPPInstance::SC_explicit) == 0) { - // A non-explicit non-copy constructor might be eligible for coercion, - // as long as it does not require explicit keyword args. - if ((_flags & F_explicit_args) == 0 || - _args_type != InterfaceMaker::AT_keyword_args) { - - _flags |= F_coerce_constructor; - } - } - - // Constructors always take varargs, and possibly keyword args. - _args_type = InterfaceMaker::AT_varargs; - for (size_t i = first_param; i < _parameters.size(); ++i) { - if (_parameters[i]._has_name) { - _args_type = InterfaceMaker::AT_keyword_args; - break; - } - } - break; - - default: - break; - } - - return true; -} - -std::string make_safe_name(const std::string &name) { - return InterrogateBuilder::clean_identifier(name); - /* - static const char safe_chars2[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; - std::string result = name; - - size_t pos = result.find_first_not_of(safe_chars2); - while (pos != std::string::npos) { - result[pos] = '_'; - pos = result.find_first_not_of(safe_chars2); - } - - return result; - */ -} diff --git a/dtool/src/interrogate/functionRemap.h b/dtool/src/interrogate/functionRemap.h deleted file mode 100644 index e662e40b759..00000000000 --- a/dtool/src/interrogate/functionRemap.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionRemap.h - * @author drose - * @date 2001-09-19 - */ - -#ifndef FUNCTIONREMAP_H -#define FUNCTIONREMAP_H - -#include "dtoolbase.h" - -#include "interrogate_interface.h" -#include "vector_string.h" - -#include - -class InterrogateBuilder; -class InterrogateType; -class InterrogateFunction; -class ParameterRemap; -class CPPType; -class CPPInstance; -class CPPStructType; -class CPPScope; -class CPPFunctionType; -class InterfaceMaker; - -/** - * This class describes how to remap a C++ function (and its list of - * parameters and return type) to a wrapped function, for a particular - * scripting language. - * - * The InterfaceMaker class will create one of these for each function, - * including one for each instance of an overloaded function. - */ -class FunctionRemap { -public: - FunctionRemap(const InterrogateType &itype, - const InterrogateFunction &ifunc, - CPPInstance *cppfunc, int num_default_parameters, - InterfaceMaker *interface_maker); - ~FunctionRemap(); - - std::string get_parameter_name(int n) const; - std::string call_function(std::ostream &out, int indent_level, - bool convert_result, const std::string &container) const; - std::string call_function(std::ostream &out, int indent_level, - bool convert_result, const std::string &container, - const vector_string &pexprs) const; - - void write_orig_prototype(std::ostream &out, int indent_level, bool local=false, - int num_default_args=0) const; - - FunctionWrapperIndex make_wrapper_entry(FunctionIndex function_index); - - std::string get_call_str(const std::string &container, const vector_string &pexprs) const; - void write_call_args(std::ostream &out, const vector_string &pexprs) const; - - int get_min_num_args() const; - int get_max_num_args() const; - - class Parameter { - public: - bool _has_name; - std::string _name; - ParameterRemap *_remap; - }; - - enum Type { - T_normal, - T_constructor, - T_destructor, - T_typecast_method, - T_assignment_method, - T_typecast, - T_getter, - T_setter, - T_item_assignment_operator, - }; - - enum Flags { - F_getitem = 0x0001, - F_getitem_int = 0x0002, - F_size = 0x0004, - F_setitem = 0x0008, - F_setitem_int = 0x0010, - F_delitem = 0x0020, - F_delitem_int = 0x0040, - F_make_copy = 0x0080, - F_copy_constructor = 0x0100, - F_explicit_self = 0x0200, - F_iter = 0x0400, - F_compare_to = 0x0800, - F_coerce_constructor = 0x1000, - F_divide_integer = 0x2000, - F_hash = 0x4000, - F_explicit_args = 0x8000, - F_explicit_cls =0x10000, - }; - - typedef std::vector Parameters; - - Parameters _parameters; - ParameterRemap *_return_type; - bool _void_return; - bool _ForcedVoidReturn; - bool _has_this; - bool _blocking; - bool _extension; - bool _const_method; - size_t _first_true_parameter; - int _num_default_parameters; - Type _type; - int _flags; - int _args_type; - std::string _expression; - std::string _function_signature; - std::string _hash; - std::string _unique_name; - std::string _reported_name; - std::string _wrapper_name; - FunctionWrapperIndex _wrapper_index; - - bool _return_value_needs_management; - FunctionIndex _return_value_destructor; - bool _manage_reference_count; - - CPPType *_cpptype; - CPPScope *_cppscope; - CPPInstance *_cppfunc; - CPPFunctionType *_ftype; - - bool _is_valid; - -private: - std::string get_parameter_expr(size_t n, const vector_string &pexprs) const; - bool setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_maker); -}; - -std::string make_safe_name(const std::string & name); - - -#endif diff --git a/dtool/src/interrogate/functionWriter.cxx b/dtool/src/interrogate/functionWriter.cxx deleted file mode 100644 index 58937d3f3d0..00000000000 --- a/dtool/src/interrogate/functionWriter.cxx +++ /dev/null @@ -1,76 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriter.cxx - * @author drose - * @date 2001-09-14 - */ - -#include "functionWriter.h" - -/** - * - */ -FunctionWriter:: -FunctionWriter() { -} - -/** - * - */ -FunctionWriter:: -~FunctionWriter() { -} - -/** - * - */ -const std::string &FunctionWriter:: -get_name() const { - return _name; -} - -/** - * - */ -int FunctionWriter:: -compare_to(const FunctionWriter &other) const { - // Lexicographical string comparison. - - std::string::const_iterator n1, n2; - n1 = _name.begin(); - n2 = other._name.begin(); - while (n1 != _name.end() && n2 != other._name.end()) { - if (*n1 != *n2) { - return *n1 - *n2; - } - ++n1; - ++n2; - } - if (n1 != _name.end()) { - return -1; - } - if (n2 != other._name.end()) { - return 1; - } - return 0; -} - -/** - * Outputs the prototype for the function. - */ -void FunctionWriter:: -write_prototype(std::ostream &) { -} - -/** - * Outputs the code for the function. - */ -void FunctionWriter:: -write_code(std::ostream &) { -} diff --git a/dtool/src/interrogate/functionWriter.h b/dtool/src/interrogate/functionWriter.h deleted file mode 100644 index da2930ae0ec..00000000000 --- a/dtool/src/interrogate/functionWriter.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriter.h - * @author drose - * @date 2001-09-14 - */ - -#ifndef FUNCTIONWRITER_H -#define FUNCTIONWRITER_H - -#include "dtoolbase.h" - -/** - * This is an abstract class that can be used by the various InterfaceMakers - * to indicate a generic helper function or variable that needs to be written - * to the generated source file. - */ -class FunctionWriter { -public: - FunctionWriter(); - virtual ~FunctionWriter(); - - const std::string &get_name() const; - virtual int compare_to(const FunctionWriter &other) const; - - virtual void write_prototype(std::ostream &out); - virtual void write_code(std::ostream &out); - -protected: - std::string _name; -}; - -#endif diff --git a/dtool/src/interrogate/functionWriterPtrFromPython.cxx b/dtool/src/interrogate/functionWriterPtrFromPython.cxx deleted file mode 100644 index 016d79cff72..00000000000 --- a/dtool/src/interrogate/functionWriterPtrFromPython.cxx +++ /dev/null @@ -1,100 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriterPtrFromPython.cxx - * @author drose - * @date 2001-09-14 - */ - -#include "functionWriterPtrFromPython.h" -#include "typeManager.h" -#include "interrogateBuilder.h" -#include "interrogate.h" - -#include "cppPointerType.h" - -/** - * - */ -FunctionWriterPtrFromPython:: -FunctionWriterPtrFromPython(CPPType *type) { - _type = TypeManager::unwrap_const(TypeManager::unwrap_pointer(type)); - _name = - "from_python_" + - InterrogateBuilder::clean_identifier(_type->get_local_name(&parser)); - - _pointer_type = new CPPPointerType(_type); -} - -/** - * - */ -FunctionWriterPtrFromPython:: -~FunctionWriterPtrFromPython() { - delete _pointer_type; -} - -/** - * Outputs the prototype for the function. - */ -void FunctionWriterPtrFromPython:: -write_prototype(std::ostream &out) { - CPPType *ppointer = new CPPPointerType(_pointer_type); - - out << "static int " << _name << "(PyObject *obj, "; - ppointer->output_instance(out, "addr", &parser); - out << ");\n"; - - delete ppointer; -} - -/** - * Outputs the code for the function. - */ -void FunctionWriterPtrFromPython:: -write_code(std::ostream &out) { - CPPType *ppointer = new CPPPointerType(_pointer_type); - - out << "static int\n" - << _name << "(PyObject *obj, "; - ppointer->output_instance(out, "addr", &parser); - out << ") {\n" - << " if (obj != nullptr && PyInstance_Check(obj)) {\n" - // << " PyClassObject *in_class = ((PyInstanceObject - // *)obj)->in_class;\n" - << " PyObject *in_dict = ((PyInstanceObject *)obj)->in_dict;\n" - << " if (in_dict != nullptr && PyDict_Check(in_dict)) {\n" - << " PyObject *thisobj = PyDict_GetItemString(in_dict, \"this\");\n" - << " if (thisobj != nullptr && PyLong_Check(thisobj)) {\n" - << " (*addr) = (" - << _pointer_type->get_local_name(&parser) << ")PyLong_AsVoidPtr(thisobj);\n" - << " return 1;\n" - << " }\n" - << " }\n" - << " }\n" - << " return 0;\n" - << "}\n\n"; - - delete ppointer; -} - -/** - * Returns the type that represents the actual data type. - */ -CPPType *FunctionWriterPtrFromPython:: -get_type() const { - return _type; -} - -/** - * Returns the type that represents a pointer to the data type. - */ -CPPType *FunctionWriterPtrFromPython:: -get_pointer_type() const { - return _pointer_type; -} diff --git a/dtool/src/interrogate/functionWriterPtrFromPython.h b/dtool/src/interrogate/functionWriterPtrFromPython.h deleted file mode 100644 index ca74f1dfdcd..00000000000 --- a/dtool/src/interrogate/functionWriterPtrFromPython.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriterPtrFromPython.h - * @author drose - * @date 2001-09-14 - */ - -#ifndef FUNCTIONWRITERPTRFROMPYTHON_H -#define FUNCTIONWRITERPTRFROMPYTHON_H - -#include "functionWriter.h" - -class CPPType; - -/** - * This specialization of FunctionWriter generates a function that converts a - * PyObject pointer representing a class wrapper object to the corresponding - * C++ pointer. - */ -class FunctionWriterPtrFromPython : public FunctionWriter { -public: - FunctionWriterPtrFromPython(CPPType *type); - virtual ~FunctionWriterPtrFromPython(); - - virtual void write_prototype(std::ostream &out); - virtual void write_code(std::ostream &out); - CPPType *get_type() const; - CPPType *get_pointer_type() const; - -private: - CPPType *_type; - CPPType *_pointer_type; -}; - -#endif diff --git a/dtool/src/interrogate/functionWriterPtrToPython.cxx b/dtool/src/interrogate/functionWriterPtrToPython.cxx deleted file mode 100644 index e2486dae7c2..00000000000 --- a/dtool/src/interrogate/functionWriterPtrToPython.cxx +++ /dev/null @@ -1,80 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriterPtrToPython.cxx - * @author drose - * @date 2001-09-14 - */ - -#include "functionWriterPtrToPython.h" -#include "typeManager.h" -#include "interrogateBuilder.h" -#include "interrogate.h" -#include "interfaceMakerPythonObj.h" - -#include "cppPointerType.h" - -/** - * - */ -FunctionWriterPtrToPython:: -FunctionWriterPtrToPython(CPPType *type) { - _type = TypeManager::unwrap_const(TypeManager::unwrap_pointer(type)); - _name = - "to_python_" + - InterrogateBuilder::clean_identifier(_type->get_local_name(&parser)); - - _pointer_type = new CPPPointerType(_type); -} - -/** - * - */ -FunctionWriterPtrToPython:: -~FunctionWriterPtrToPython() { - delete _pointer_type; -} - -/** - * Outputs the prototype for the function. - */ -void FunctionWriterPtrToPython:: -write_prototype(std::ostream &out) { - out << "static PyObject *" << _name << "("; - _pointer_type->output_instance(out, "addr", &parser); - out << ", int caller_manages);\n"; -} - -/** - * Outputs the code for the function. - */ -void FunctionWriterPtrToPython:: -write_code(std::ostream &out) { - std::string classobj_func = InterfaceMakerPythonObj::get_builder_name(_type); - out << "static PyObject *\n" - << _name << "("; - _pointer_type->output_instance(out, "addr", &parser); - out << ", int caller_manages) {\n" - << " PyObject *" << classobj_func << "();\n" - << " PyObject *classobj = " << classobj_func << "();\n" - << " PyInstanceObject *instance = (PyInstanceObject *)PyInstance_New(classobj, nullptr, nullptr);\n" - << " if (instance != nullptr) {\n" - << " PyObject *thisptr = PyLong_FromVoidPtr((void*)addr);\n" - << " PyDict_SetItemString(instance->in_dict, \"this\", thisptr);\n" - << " }\n" - << " return (PyObject *)instance;\n" - << "}\n\n"; -} - -/** - * Returns the type that represents a pointer to the data type. - */ -CPPType *FunctionWriterPtrToPython:: -get_pointer_type() const { - return _pointer_type; -} diff --git a/dtool/src/interrogate/functionWriterPtrToPython.h b/dtool/src/interrogate/functionWriterPtrToPython.h deleted file mode 100644 index f563d4fccbf..00000000000 --- a/dtool/src/interrogate/functionWriterPtrToPython.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriterPtrToPython.h - * @author drose - * @date 2001-09-14 - */ - -#ifndef FUNCTIONWRITERPTRTOPYTHON_H -#define FUNCTIONWRITERPTRTOPYTHON_H - -#include "functionWriter.h" - -class CPPType; - -/** - * This specialization of FunctionWriter generates a function that generates a - * PyObject class wrapper object around the corresponding C++ pointer. - */ -class FunctionWriterPtrToPython : public FunctionWriter { -public: - FunctionWriterPtrToPython(CPPType *type); - virtual ~FunctionWriterPtrToPython(); - - virtual void write_prototype(std::ostream &out); - virtual void write_code(std::ostream &out); - CPPType *get_pointer_type() const; - -private: - CPPType *_type; - CPPType *_pointer_type; -}; - -#endif diff --git a/dtool/src/interrogate/functionWriters.cxx b/dtool/src/interrogate/functionWriters.cxx deleted file mode 100644 index 2d1d167b2df..00000000000 --- a/dtool/src/interrogate/functionWriters.cxx +++ /dev/null @@ -1,76 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriters.cxx - * @author drose - * @date 2001-09-14 - */ - -#include "functionWriters.h" - -/** - * - */ -FunctionWriters:: -FunctionWriters() { -} - -/** - * - */ -FunctionWriters:: -~FunctionWriters() { - Writers::iterator wi; - for (wi = _writers.begin(); wi != _writers.end(); ++wi) { - delete (*wi); - } -} - -/** - * Adds the indicated FunctionWriter to the set of functions to be written, - * unless there is already a matching FunctionWriter. - * - * The return value is the FunctionWriter pointer that was added to the set, - * which may be the same pointer or a previously-allocated (but equivalent) - * pointer. - */ -FunctionWriter *FunctionWriters:: -add_writer(FunctionWriter *writer) { - std::pair result = _writers.insert(writer); - if (!result.second) { - // Already there; delete the pointer. - delete writer; - } - - // Return the pointer that is in the set. - return *result.first; -} - -/** - * Generates prototypes for all of the functions. - */ -void FunctionWriters:: -write_prototypes(std::ostream &out) { - Writers::iterator wi; - for (wi = _writers.begin(); wi != _writers.end(); ++wi) { - FunctionWriter *writer = (*wi); - writer->write_prototype(out); - } -} - -/** - * Generates all of the functions. - */ -void FunctionWriters:: -write_code(std::ostream &out) { - Writers::iterator wi; - for (wi = _writers.begin(); wi != _writers.end(); ++wi) { - FunctionWriter *writer = (*wi); - writer->write_code(out); - } -} diff --git a/dtool/src/interrogate/functionWriters.h b/dtool/src/interrogate/functionWriters.h deleted file mode 100644 index 2da07ecd9c5..00000000000 --- a/dtool/src/interrogate/functionWriters.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file functionWriters.h - * @author drose - * @date 2001-09-14 - */ - -#ifndef FUNCTIONWRITERS_H -#define FUNCTIONWRITERS_H - -#include "dtoolbase.h" -#include "functionWriter.h" - -#include - -/** - * A set of zero or more FunctionWriter pointers accumulated by the various - * InterfaceMaker objects that are generating code for one particular output - * source file. - */ -class FunctionWriters { -public: - FunctionWriters(); - ~FunctionWriters(); - - FunctionWriter *add_writer(FunctionWriter *writer); - - void write_prototypes(std::ostream &out); - void write_code(std::ostream &out); - -protected: - class IndirectCompareTo { - public: - bool operator () (const FunctionWriter *a, const FunctionWriter *b) const { - return a->compare_to(*b) < 0; - } - }; - - typedef std::set Writers; - Writers _writers; -}; - -#endif diff --git a/dtool/src/interrogate/interfaceMaker.cxx b/dtool/src/interrogate/interfaceMaker.cxx deleted file mode 100644 index 3c5d7f6b579..00000000000 --- a/dtool/src/interrogate/interfaceMaker.cxx +++ /dev/null @@ -1,968 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMaker.cxx - * @author drose - * @date 2001-09-19 - */ - -#include "interfaceMaker.h" -#include "interrogateBuilder.h" -#include "typeManager.h" -#include "interrogate.h" -#include "functionRemap.h" -#include "parameterRemap.h" -#include "parameterRemapThis.h" -#include "parameterRemapUnchanged.h" -#include "parameterRemapReferenceToPointer.h" -#include "parameterRemapConcreteToPointer.h" -#include "parameterRemapEnumToInt.h" -#include "parameterRemapConstToNonConst.h" -#include "parameterRemapReferenceToConcrete.h" -#include "parameterRemapCharStarToString.h" -#include "parameterRemapBasicStringToString.h" -#include "parameterRemapBasicStringRefToString.h" -#include "parameterRemapBasicStringPtrToString.h" -#include "parameterRemapPTToPointer.h" - -#include "interrogateDatabase.h" -#include "interrogateManifest.h" -#include "interrogateElement.h" -#include "cppFunctionType.h" -#include "cppParameterList.h" -#include "cppMakeSeq.h" -#include "cppStructType.h" -#include "pnotify.h" - -using std::ostream; -using std::ostringstream; -using std::string; - -InterrogateType dummy_type; - -/** - * - */ -InterfaceMaker::Function:: -Function(const string &name, - const InterrogateType &itype, - const InterrogateFunction &ifunc) : - _name(name), - _itype(itype), - _ifunc(ifunc) -{ - _has_this = false; - _flags = 0; - _args_type = AT_unknown; -} - -/** - * - */ -InterfaceMaker::Function:: -~Function() { - Remaps::iterator ri; - for (ri = _remaps.begin(); ri != _remaps.end(); ++ri) { - delete (*ri); - } -} - -/** - * - */ -InterfaceMaker::MakeSeq:: -MakeSeq(const string &name, const InterrogateMakeSeq &imake_seq) : - _imake_seq(imake_seq), - _name(name), - _length_getter(nullptr), - _element_getter(nullptr) -{ -} - -/** - * - */ -InterfaceMaker::Property:: -Property(const InterrogateElement &ielement) : - _ielement(ielement), - _length_function(nullptr), - _has_function(nullptr), - _clear_function(nullptr), - _deleter(nullptr), - _inserter(nullptr), - _getkey_function(nullptr), - _has_this(false) -{ -} - -/** - * - */ -InterfaceMaker::Object:: -Object(const InterrogateType &itype) : - _itype(itype), - _protocol_types(0) -{ -} - -/** - * - */ -InterfaceMaker::Object:: -~Object() { -} - -/** - * To be called after all of the methods have been added, this checks which - * protocols this object appears to support (based on the methods it - * provides). - */ -void InterfaceMaker::Object:: -check_protocols() { - int flags = 0; - - Functions::const_iterator fi; - for (fi = _constructors.begin(); fi != _constructors.end(); ++fi) { - Function *func = (*fi); - flags |= func->_flags; - } - for (fi = _methods.begin(); fi != _methods.end(); ++fi) { - Function *func = (*fi); - flags |= func->_flags; - - if (func->_ifunc.get_name() == "__traverse__") { - // If we have a method named __traverse__, we implement Python's cyclic - // garbage collection protocol. - //XXX disabled for now because it's too unstable. - //_protocol_types |= PT_python_gc; - } - } - - if ((flags & (FunctionRemap::F_getitem_int | FunctionRemap::F_size)) == - (FunctionRemap::F_getitem_int | FunctionRemap::F_size)) { - // If we have both a getitem that receives an int, and a size, then we - // implement the sequence protocol: you can iterate through the elements - // of this object. - _protocol_types |= PT_sequence; - - } else if (flags & FunctionRemap::F_getitem) { - // If we have any getitem, then we implement the mapping protocol. - _protocol_types |= PT_mapping; - } - - if (flags & FunctionRemap::F_make_copy) { - // It's not exactly a protocol, but if we have a make_copy() method, we - // can use it to synthesize a __copy__ and __deepcopy__ Python method to - // support the copy module. - _protocol_types |= PT_make_copy; - } else if (flags & FunctionRemap::F_copy_constructor) { - // Ditto for the copy constructor. - _protocol_types |= PT_copy_constructor; - } - - if (flags & FunctionRemap::F_iter) { - _protocol_types |= PT_iter; - } -} - -/** - * Returns true if the first method found with the indicated name is a static - * method, false if it is an instance method. This does not test all - * overloads of the indicated name, merely the first one found. - */ -bool InterfaceMaker::Object:: -is_static_method(const string &name) { - Functions::const_iterator fi; - for (fi = _methods.begin(); fi != _methods.end(); ++fi) { - Function *func = (*fi); - if (!func->_remaps.empty()) { - FunctionRemap *remap = func->_remaps.front(); - string method_name = remap->_cppfunc->get_simple_name(); - if (method_name == name) { - return !func->_has_this; - } - } - } - - // Didn't find the requested function. - return false; -} - -/** - * - */ -InterfaceMaker:: -InterfaceMaker(InterrogateModuleDef *def) : - _def(def) -{ -} - -/** - * - */ -InterfaceMaker:: -~InterfaceMaker() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - delete object; - } - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - delete (*fi).second; - } -} - -/** - * Walks through the set of functions in the database and generates wrappers - * for each function, storing these in the database. No actual code should be - * output yet; this just updates the database with the wrapper information. - */ -void InterfaceMaker:: -generate_wrappers() { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - // We use a while loop rather than a simple for loop, because we might - // increase the number of types recursively during the traversal. - int ti = 0; - while (ti < idb->get_num_all_types()) { - TypeIndex type_index = idb->get_all_type(ti++); - record_object(type_index); - } - - int num_global_elements = idb->get_num_global_elements(); - for (int gi = 0; gi < num_global_elements; ++gi) { - //printf(" Global Type = %d", gi); - TypeIndex type_index = idb->get_global_element(gi); - record_object(type_index); - } - - int num_functions = idb->get_num_global_functions(); - for (int fi = 0; fi < num_functions; fi++) { - FunctionIndex func_index = idb->get_global_function(fi); - record_function(dummy_type, func_index); - } - - int num_manifests = idb->get_num_global_manifests(); - for (int mi = 0; mi < num_manifests; mi++) { - ManifestIndex manifest_index = idb->get_global_manifest(mi); - const InterrogateManifest &iman = idb->get_manifest(manifest_index); - if (iman.has_getter()) { - FunctionIndex func_index = iman.get_getter(); - record_function(dummy_type, func_index); - } - //printf(" Manifests %d\n", mi); - } - - int num_elements = idb->get_num_global_elements(); - for (int ei = 0; ei < num_elements; ei++) { - //printf(" Element %d\n", ei); - - ElementIndex element_index = idb->get_global_element(ei); - const InterrogateElement &ielement = idb->get_element(element_index); - if (ielement.has_getter()) { - FunctionIndex func_index = ielement.get_getter(); - record_function(dummy_type, func_index); - } - if (ielement.has_setter()) { - FunctionIndex func_index = ielement.get_setter(); - record_function(dummy_type, func_index); - } - } -} - -/** - * Generates the list of #include ... whatever that's required by this - * particular interface to the indicated output stream. - */ -void InterfaceMaker:: -write_includes(ostream &) { -} - -/** - * Generates the list of function prototypes corresponding to the functions - * that will be output in write_functions(). - */ -void InterfaceMaker:: -write_prototypes(ostream &out,ostream *out_h) { - _function_writers.write_prototypes(out); -} - -/** - * Generates the list of functions that are appropriate for this interface. - */ -void InterfaceMaker:: -write_functions(ostream &out) { - _function_writers.write_code(out); -} - -/** - * Generates whatever additional code is required to support a module file. - */ -void InterfaceMaker:: -write_module(ostream &, ostream *out_h, InterrogateModuleDef *) { -} - -/** - * Allocates a new ParameterRemap object suitable to the indicated parameter - * type. If struct_type is non-NULL, it is the type of the enclosing class - * for the function (method) in question. - * - * The return value is a newly-allocated ParameterRemap object, if the - * parameter type is acceptable, or NULL if the parameter type cannot be - * handled. - */ -ParameterRemap *InterfaceMaker:: -remap_parameter(CPPType *struct_type, CPPType *param_type) { - nassertr(param_type != nullptr, nullptr); - - if (convert_strings) { - if (TypeManager::is_char_pointer(param_type)) { - return new ParameterRemapCharStarToString(param_type); - } - if (TypeManager::is_wchar_pointer(param_type)) { - return new ParameterRemapWCharStarToWString(param_type); - } - - // If we're exporting a method of basic_string itself, don't convert - // basic_string's to atomic strings. - - if (struct_type == nullptr || - !(TypeManager::is_basic_string_char(struct_type) || - TypeManager::is_basic_string_wchar(struct_type))) { - if (TypeManager::is_basic_string_char(param_type)) { - return new ParameterRemapBasicStringToString(param_type); - - } else if (TypeManager::is_const_ref_to_basic_string_char(param_type)) { - return new ParameterRemapBasicStringRefToString(param_type); - - } else if (TypeManager::is_const_ptr_to_basic_string_char(param_type)) { - return new ParameterRemapBasicStringPtrToString(param_type); - - } else if (TypeManager::is_basic_string_wchar(param_type)) { - return new ParameterRemapBasicWStringToWString(param_type); - - } else if (TypeManager::is_const_ref_to_basic_string_wchar(param_type)) { - return new ParameterRemapBasicWStringRefToWString(param_type); - - } else if (TypeManager::is_const_ptr_to_basic_string_char(param_type)) { - return new ParameterRemapBasicStringPtrToString(param_type); - - } else if (TypeManager::is_const_ptr_to_basic_string_wchar(param_type)) { - return new ParameterRemapBasicWStringPtrToWString(param_type); - - } else if (TypeManager::is_reference(param_type) || - TypeManager::is_pointer(param_type)) { - // Python strings are immutable, so we can't wrap a non-const pointer - // or reference to a string. - CPPType *pt_type = TypeManager::unwrap(param_type); - if (TypeManager::is_basic_string_char(pt_type) || - TypeManager::is_basic_string_wchar(pt_type)) { - return nullptr; - } - } - } - if (struct_type == nullptr || - !TypeManager::is_vector_unsigned_char(struct_type)) { - if (TypeManager::is_vector_unsigned_char(param_type)) { - if (TypeManager::is_reference(param_type)) { - return new ParameterRemapReferenceToConcrete(param_type); - } else if (TypeManager::is_const(param_type)) { - return new ParameterRemapConstToNonConst(param_type); - } else { - return new ParameterRemapUnchanged(param_type); - } - } - } - } - - if (manage_reference_counts) { - if (TypeManager::is_pointer_to_base(param_type) || - TypeManager::is_const_ref_to_pointer_to_base(param_type)) - { - CPPType *pt_type = TypeManager::unwrap_reference(param_type); - - // Don't convert PointerTo<>'s to pointers for methods of the PointerTo - // itself! - if (struct_type == nullptr || - !(pt_type->get_local_name(&parser) == struct_type->get_local_name(&parser))) { - return new ParameterRemapPTToPointer(param_type); - } - } - } - - if (TypeManager::is_reference(param_type)) { - return new ParameterRemapReferenceToPointer(param_type); - - } else if (TypeManager::is_struct(param_type)) { - return new ParameterRemapConcreteToPointer(param_type); - - /* - } else if (TypeManager::is_enum(param_type) || TypeManager::is_const_ref_to_enum(param_type)) { - return new ParameterRemapEnumToInt(param_type); - */ - - // } else if (TypeManager::is_const_simple(param_type)) { return new - // ParameterRemapConstToNonConst(param_type); - - } else if (TypeManager::is_const_ref_to_simple(param_type)) { - return new ParameterRemapReferenceToConcrete(param_type); - - } else if (TypeManager::is_pointer(param_type) || - TypeManager::is_void(param_type) || - TypeManager::is_simple(param_type) || - TypeManager::is_simple_array(param_type)) { - return new ParameterRemapUnchanged(param_type); - - } else { - // Here's something we have a problem with. - return nullptr; - } -} - -/** - * This method should be overridden and redefined to return true for - * interfaces that require the implicit "this" parameter, if present, to be - * passed as the first parameter to any wrapper functions. - */ -bool InterfaceMaker:: -synthesize_this_parameter() { - return false; -} - -/** - * This method should be overridden and redefined to return true for - * interfaces that require overloaded instances of a function to be defined as - * separate functions (each with its own hashed name), or false for interfaces - * that can support overloading natively, and thus only require one wrapper - * function per each overloaded input function. - */ -bool InterfaceMaker:: -separate_overloading() { - return true; -} - -/** - * This method should be overridden and redefined to return false for - * interfaces that don't support global functions and should therefore will - * only accept function remaps that have a class associated. - */ -bool InterfaceMaker:: -wrap_global_functions() { - return true; -} - -/** - * Fills up the indicated vector with all of the FunctionRemap pointers - * created by this InterfaceMaker. It is the user's responsibility to empty - * the vector before calling this function; the new pointers will simply be - * added to the end. - */ -void InterfaceMaker:: -get_function_remaps(std::vector &remaps) { - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - Function::Remaps::const_iterator ri; - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - remaps.push_back(remap); - } - } -} - -/** - * - */ -ostream &InterfaceMaker:: -indent(ostream &out, int indent_level) { - for (int i = 0; i < indent_level; i++) { - out << ' '; - } - return out; -} - -/** - * Creates a FunctionRemap object corresponding to the particular function - * wrapper. - */ -FunctionRemap *InterfaceMaker:: -make_function_remap(const InterrogateType &itype, - const InterrogateFunction &ifunc, - CPPInstance *cppfunc, int num_default_parameters) { - FunctionRemap *remap = - new FunctionRemap(itype, ifunc, cppfunc, num_default_parameters, this); - if (remap->_is_valid) { - if (separate_overloading()) { - hash_function_signature(remap); - remap->_unique_name = - get_unique_prefix() + _def->library_hash_name + remap->_hash; - remap->_wrapper_name = - get_wrapper_prefix() + _def->library_hash_name + remap->_hash; - remap->_reported_name = remap->_wrapper_name; - - if (true_wrapper_names) { - remap->_reported_name = - InterrogateBuilder::clean_identifier(remap->_cppfunc->get_local_name(&parser)); - } - } - return remap; - } - - // No such FunctionRemap is valid. Return NULL. - delete remap; - return nullptr; -} - -/** - * Returns the function name that will be used to wrap the indicated function. - * - * This is the name for the overall wrapper function, including all of the - * overloaded instances. Interfaces that must define a different wrapper for - * each FunctionRemap object (i.e. for each instance of an overloaded - * function) need not define a name here. - */ -string InterfaceMaker:: -get_wrapper_name(const InterrogateType &itype, - const InterrogateFunction &ifunc, - FunctionIndex func_index) { - string func_name = ifunc.get_scoped_name(); - string clean_name = InterrogateBuilder::clean_identifier(func_name); - - ostringstream new_name; - new_name << get_wrapper_prefix() << clean_name << "_" << func_index; - return new_name.str(); -} - -/** - * Returns the prefix string used to generate wrapper function names. - */ -string InterfaceMaker:: -get_wrapper_prefix() { - return "xx_"; -} - -/** - * Returns the prefix string used to generate unique symbolic names, which are - * not necessarily C-callable function names. - */ -string InterfaceMaker:: -get_unique_prefix() { - return "x"; -} - -/** - * Records the indicated function, along with all of its FunctionRemap flavors - * and FunctionWriter helpers, for future output. Returns the new Function - * pointer. - */ -InterfaceMaker::Function *InterfaceMaker:: -record_function(const InterrogateType &itype, FunctionIndex func_index) { - assert(func_index != 0); - - if (_functions.count(func_index)) { - // Already exists. - return _functions[func_index]; - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - const InterrogateFunction &ifunc = idb->get_function(func_index); - - string wrapper_name = get_wrapper_name(itype, ifunc, func_index); - Function *func = new Function(wrapper_name, itype, ifunc); - _functions[func_index] = func; - -// printf(" Function Name = %s\n", ifunc.get_name().c_str()); - - // Now get all the valid FunctionRemaps for the function. - if (ifunc._instances != nullptr) { - InterrogateFunction::Instances::const_iterator ii; - for (ii = ifunc._instances->begin(); ii != ifunc._instances->end(); ++ii) { - CPPInstance *cppfunc = (*ii).second; - CPPFunctionType *ftype = cppfunc->_type->as_function_type(); - int max_default_parameters = 0; - - if (separate_overloading()) { - // Count up the number of default parameters this function might take. - CPPParameterList *parameters = ftype->_parameters; - CPPParameterList::Parameters::reverse_iterator pi; - for (pi = parameters->_parameters.rbegin(); - pi != parameters->_parameters.rend(); - ++pi) { - CPPInstance *param = (*pi); - if (param->_initializer != nullptr) { - // This parameter has a default value. - max_default_parameters++; - } else { - // The first parameter without a default value ends the search. - break; - } - } - } - - // Now make a different wrapper for each combination of default - // parameters. This will happen only if separate_overloading(), tested - // above, returned true; otherwise, max_default_parameters will be 0 and - // the loop will only be traversed once. - for (int num_default_parameters = 0; - num_default_parameters <= max_default_parameters; - num_default_parameters++) { - FunctionRemap *remap = - make_function_remap(itype, ifunc, cppfunc, num_default_parameters); - if (remap != nullptr) { - - func->_remaps.push_back(remap); - - // If *any* of the variants of this function has a "this" pointer, - // the entire set of functions is deemed to have a "this" pointer. - if (remap->_has_this || (remap->_flags & FunctionRemap::F_explicit_self) != 0) { - func->_has_this = true; - } - - func->_flags |= remap->_flags; - func->_args_type = (ArgsType)((int)func->_args_type | (int)remap->_args_type); - - // Make a wrapper for the function. - FunctionWrapperIndex wrapper_index = - remap->make_wrapper_entry(func_index); - if (wrapper_index != 0) { - InterrogateFunction &mod_ifunc = idb->update_function(func_index); - record_function_wrapper(mod_ifunc, wrapper_index); - } - } - } - } - } - - return func; -} - -/** - * Associates the function wrapper with its function in the appropriate - * structures in the database. - */ -void InterfaceMaker:: -record_function_wrapper(InterrogateFunction &, FunctionWrapperIndex) { -} - -/** - * Records the indicated type, which may be a struct type, along with all of - * its associated methods, if any. - */ -InterfaceMaker::Object *InterfaceMaker:: -record_object(TypeIndex type_index) { - if (type_index == 0) { - // An invalid type. - return nullptr; - } - - Objects::iterator oi = _objects.find(type_index); - if (oi != _objects.end()) { - // The object has previously been recorded. - return (*oi).second; - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - const InterrogateType &itype = idb->get_type(type_index); - - Object *object = new Object(itype); - bool inserted = _objects.insert(Objects::value_type(type_index, object)).second; - assert(inserted); - - Function *function; - - int num_constructors = itype.number_of_constructors(); - for (int ci = 0; ci < num_constructors; ci++) { - function = record_function(itype, itype.get_constructor(ci)); - object->_constructors.push_back(function); - } - - int num_methods = itype.number_of_methods(); - int mi; - for (mi = 0; mi < num_methods; mi++) { - function = record_function(itype, itype.get_method(mi)); - object->_methods.push_back(function); - } - - int num_casts = itype.number_of_casts(); - for (mi = 0; mi < num_casts; mi++) { - function = record_function(itype, itype.get_cast(mi)); - object->_methods.push_back(function); - } - - int num_derivations = itype.number_of_derivations(); - for (int di = 0; di < num_derivations; di++) { - if (itype.derivation_has_upcast(di)) { - record_function(itype, itype.derivation_get_upcast(di)); - } - if (itype.derivation_has_downcast(di)) { - // Downcasts are methods of the base class, not the child class. - TypeIndex base_type_index = itype.get_derivation(di); - const InterrogateType &base_type = idb->get_type(base_type_index); - record_function(base_type, itype.derivation_get_downcast(di)); - } - } - - int num_elements = itype.number_of_elements(); - for (int ei = 0; ei < num_elements; ei++) { - ElementIndex element_index = itype.get_element(ei); - const InterrogateElement &ielement = idb->get_element(element_index); - if (ielement.has_getter()) { - FunctionIndex func_index = ielement.get_getter(); - record_function(itype, func_index); - } - if (ielement.has_setter()) { - FunctionIndex func_index = ielement.get_setter(); - record_function(itype, func_index); - } - } - - object->check_protocols(); - - int num_nested = itype.number_of_nested_types(); - for (int ni = 0; ni < num_nested; ni++) { - TypeIndex nested_index = itype.get_nested_type(ni); - record_object(nested_index); - } - - return object; -} - -/** - * Does any additional processing that we might want to do on the return value - * for the function, just before we return it. Returns the string - * representing the new return value after processing. - */ -string InterfaceMaker:: -manage_return_value(ostream &out, int indent_level, - FunctionRemap *remap, const string &return_expr) const { - if (remap->_manage_reference_count) { - // If we're managing reference counts, and we're about to return a - // reference countable object, then increment its count. - if (return_expr == "return_value") { - // If the expression is just a variable name, we can just ref it - // directly. - output_ref(out, indent_level, remap, return_expr); - return return_expr; - - } else { - // Otherwise, we should probably assign it to a temporary first, so we - // don't invoke the function twice or something. - CPPType *type = remap->_return_type->get_temporary_type(); - indent(out, indent_level); - type->output_instance(out, "refcount", &parser); - out << " = " << return_expr << ";\n"; - - indent(out, indent_level) - << "if (" << return_expr << " != nullptr) {\n"; - indent(out, indent_level + 2) - << "(" << return_expr << ")->ref();\n"; - indent(out, indent_level) - << "}\n"; - output_ref(out, indent_level, remap, "refcount"); - return remap->_return_type->temporary_to_return("refcount"); - } - } - - // Otherwise, just return the expression unchanged. - return return_expr; -} - -/** - * Cleans up the given return value by deleting it or decrementing its - * reference count or whatever is appropriate. - */ -void InterfaceMaker:: -delete_return_value(ostream &out, int indent_level, - FunctionRemap *remap, const string &return_expr) const { - if (remap->_manage_reference_count) { - // If we're managing reference counts, and we're about to return a - // reference countable object, then decrement its count. - output_unref(out, indent_level, remap, return_expr); - - } else if (remap->_return_value_needs_management) { - // We should just delete it directly. - indent(out, indent_level) << "delete " << return_expr << ";\n"; - } -} - -/** - * Outputs the code to increment the reference count for the indicated - * variable name. - */ -void InterfaceMaker:: -output_ref(ostream &out, int indent_level, FunctionRemap *remap, - const string &varname) const { - - if (TypeManager::is_pointer_to_base(remap->_return_type->get_temporary_type())) { - // Actually, we have it stored in a PointerTo. No need to do anything. - return; - } - - if (remap->_type == FunctionRemap::T_constructor || - remap->_type == FunctionRemap::T_typecast) { - // In either of these cases, we can safely assume the pointer will never - // be NULL. - indent(out, indent_level) - << varname << "->ref();\n"; - - } else { - // However, in the general case, we have to check for that before we - // attempt to ref it. - - indent(out, indent_level) - << "if (" << varname << " != nullptr) {\n"; - indent(out, indent_level + 2) - << varname << "->ref();\n"; - indent(out, indent_level) - << "}\n"; - } -} - -/** - * Outputs the code to decrement the reference count for the indicated - * variable name. - */ -void InterfaceMaker:: -output_unref(ostream &out, int indent_level, FunctionRemap *remap, - const string &varname) const { - - if (TypeManager::is_pointer_to_base(remap->_return_type->get_temporary_type())) { - // Actually, we have it stored in a PointerTo. No need to do anything. - return; - } - - if (remap->_type == FunctionRemap::T_constructor || - remap->_type == FunctionRemap::T_typecast) { - // In either of these cases, we can safely assume the pointer will never - // be NULL. - indent(out, indent_level) - << "unref_delete(" << varname << ");\n"; - - } else { - // However, in the general case, we have to check for that before we - // attempt to ref it. - - indent(out, indent_level) - << "if (" << varname << " != nullptr) {\n"; - - if (TypeManager::is_pointer_to_base(remap->_return_type->get_temporary_type())) { - // We're sure the reference count won't reach zero since we have it - // stored in a PointerTo, so call the unref() method directly. - indent(out, indent_level + 2) - << varname << "->unref();\n"; - } else { - indent(out, indent_level + 2) - << "unref_delete(" << varname << ");\n"; - } - - indent(out, indent_level) - << "}\n"; - } -} - -/** - * Generates a unique string that corresponds to the function signature for - * the indicated FunctionRemap object, and stores the generated string in the - * _hash member of the FunctionRemap. - */ -void InterfaceMaker:: -hash_function_signature(FunctionRemap *remap) { - string hash = InterrogateBuilder::hash_string(remap->_function_signature, 5); - - // Now make sure we don't have another function with the same hash. - WrappersByHash::iterator hi; - hi = _wrappers_by_hash.find(hash); - if (hi == _wrappers_by_hash.end()) { - // No other name; we're in the clear. - _wrappers_by_hash[hash] = remap; - remap->_hash = hash; - return; - } - - if ((*hi).second != nullptr && - (*hi).second->_function_signature == remap->_function_signature) { - // The same function signature has already appeared. This shouldn't - // happen. - nout << "Internal error! Function signature " - << remap->_function_signature << " repeated!\n"; - remap->_hash = hash; - abort(); - return; - } - - // We have a conflict. Extend both strings to resolve the ambiguity. - if ((*hi).second != nullptr) { - FunctionRemap *other_remap = (*hi).second; - (*hi).second = nullptr; - other_remap->_hash += - InterrogateBuilder::hash_string(other_remap->_function_signature, 11); - bool inserted = _wrappers_by_hash.insert - (WrappersByHash::value_type(other_remap->_hash, other_remap)).second; - if (!inserted) { - nout << "Internal error! Hash " << other_remap->_hash - << " already appears!\n"; - } - } - - hash += InterrogateBuilder::hash_string(remap->_function_signature, 11); - bool inserted = _wrappers_by_hash.insert - (WrappersByHash::value_type(hash, remap)).second; - - if (!inserted) { - // Huh. We still have a conflict. This should be extremely rare. Well, - // just tack on a letter until it's resolved. - string old_hash = hash; - for (char ch = 'a'; ch <= 'z' && !inserted; ch++) { - hash = old_hash + ch; - inserted = _wrappers_by_hash.insert - (WrappersByHash::value_type(hash, remap)).second; - } - if (!inserted) { - nout << "Internal error! Too many conflicts with hash " - << hash << "\n"; - } - } - - remap->_hash = hash; -} - -/** - * Generates a string to output a spammy message to notify indicating we have - * just called this function. - */ -void InterfaceMaker:: -write_spam_message(ostream &out, FunctionRemap *remap) const { - ostringstream strm; - remap->write_orig_prototype(strm, 0); - string prototype = strm.str(); - - out << - " if (interrogatedb_cat.is_spam()) {\n" - " interrogatedb_cat.spam() << \""; - - for (string::const_iterator si = prototype.begin(); - si != prototype.end(); - ++si) { - switch (*si) { - case '"': - out << "\\\""; - break; - - case '\\': - out << "\\\\"; - break; - - default: - out << *si; - } - } - - out << "\\n\";\n" - " }\n"; -} diff --git a/dtool/src/interrogate/interfaceMaker.h b/dtool/src/interrogate/interfaceMaker.h deleted file mode 100644 index e439105ea1c..00000000000 --- a/dtool/src/interrogate/interfaceMaker.h +++ /dev/null @@ -1,215 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMaker.h - * @author drose - * @date 2001-09-19 - */ - -#ifndef INTERFACEMAKER_H -#define INTERFACEMAKER_H - -#include "dtoolbase.h" - -#include "cppMakeSeq.h" - -#include "interrogate_interface.h" -#include "interrogate_request.h" -#include "functionWriters.h" - -#include -#include - -class FunctionRemap; -class ParameterRemap; -class CPPType; -class CPPInstance; -class InterrogateBuilder; -class InterrogateElement; -class InterrogateFunction; -class InterrogateMakeSeq; -class InterrogateType; - -/** - * This is an abstract base class that defines how to generate code that can - * be called from an external language (like Python or Squeak) and that can - * call into Panda. - * - * The specializations of this class like InterfaceMakerPython and - * InterfaceMakerC will generate the actual wrappers for the various language - * calling conventions. - */ -class InterfaceMaker { -public: - InterfaceMaker(InterrogateModuleDef *def); - virtual ~InterfaceMaker(); - - virtual void generate_wrappers(); - - virtual void write_includes(std::ostream &out); - virtual void write_prototypes(std::ostream &out, std::ostream *out_h); - virtual void write_functions(std::ostream &out); - virtual void write_module_support(std::ostream &out, std::ostream *out_h, InterrogateModuleDef *def) {}; - - virtual void write_module(std::ostream &out, std::ostream *out_h, InterrogateModuleDef *def); - - virtual ParameterRemap *remap_parameter(CPPType *struct_type, CPPType *param_type); - - virtual bool synthesize_this_parameter(); - virtual bool separate_overloading(); - virtual bool wrap_global_functions(); - - void get_function_remaps(std::vector &remaps); - - static std::ostream &indent(std::ostream &out, int indent_level); - -public: - // This contains information about the number of arguments that the wrapping - // function should take. - enum ArgsType { - // This is deliberately engineered such that these values can be OR'ed - // together to produce another valid enum value. - AT_unknown = 0x00, - - // The method or function takes no arguments. - AT_no_args = 0x01, - - // There is only a single argument. - AT_single_arg = 0x02, - - // The method takes a variable number of arguments. - AT_varargs = 0x03, - - // The method may take keyword arguments, if appropriate in the scripting - // language. Implies AT_varargs. - AT_keyword_args = 0x07, - }; - - class Function { - public: - Function(const std::string &name, - const InterrogateType &itype, - const InterrogateFunction &ifunc); - ~Function(); - - std::string _name; - const InterrogateType &_itype; - const InterrogateFunction &_ifunc; - typedef std::vector Remaps; - Remaps _remaps; - bool _has_this; - int _flags; - ArgsType _args_type; - }; - typedef std::map FunctionsByIndex; - typedef std::vector Functions; - FunctionsByIndex _functions; - - class MakeSeq { - public: - MakeSeq(const std::string &name, const InterrogateMakeSeq &imake_seq); - - const InterrogateMakeSeq &_imake_seq; - std::string _name; - Function *_length_getter; - Function *_element_getter; - }; - typedef std::vector MakeSeqs; - - class Property { - public: - Property(const InterrogateElement &ielement); - - const InterrogateElement &_ielement; - std::vector _getter_remaps; - std::vector _setter_remaps; - Function *_length_function; - Function *_has_function; - Function *_clear_function; - Function *_deleter; - Function *_inserter; - Function *_getkey_function; - bool _has_this; - }; - typedef std::vector Properties; - - class Object { - public: - Object(const InterrogateType &itype); - ~Object(); - - void check_protocols(); - bool is_static_method(const std::string &name); - - const InterrogateType &_itype; - Functions _constructors; - Functions _methods; - MakeSeqs _make_seqs; - Properties _properties; - - enum ProtocolTypes { - PT_sequence = 0x0001, - PT_mapping = 0x0002, - PT_make_copy = 0x0004, - PT_copy_constructor = 0x0008, - PT_iter = 0x0010, - PT_python_gc = 0x0020, - }; - int _protocol_types; - }; - typedef std::map Objects; - Objects _objects; - - typedef std::map WrappersByHash; - WrappersByHash _wrappers_by_hash; - - virtual FunctionRemap * - make_function_remap(const InterrogateType &itype, - const InterrogateFunction &ifunc, - CPPInstance *cppfunc, int num_default_parameters); - - virtual std::string - get_wrapper_name(const InterrogateType &itype, - const InterrogateFunction &ifunc, - FunctionIndex func_index); - virtual std::string get_wrapper_prefix(); - virtual std::string get_unique_prefix(); - - Function * - record_function(const InterrogateType &itype, FunctionIndex func_index); - - virtual void - record_function_wrapper(InterrogateFunction &ifunc, - FunctionWrapperIndex wrapper_index); - - virtual Object *record_object(TypeIndex type_index); - - void hash_function_signature(FunctionRemap *remap); - - - std::string - manage_return_value(std::ostream &out, int indent_level, - FunctionRemap *remap, const std::string &return_expr) const; - - void - delete_return_value(std::ostream &out, int indent_level, - FunctionRemap *remap, const std::string &return_expr) const; - - void output_ref(std::ostream &out, int indent_level, FunctionRemap *remap, - const std::string &varname) const; - void output_unref(std::ostream &out, int indent_level, FunctionRemap *remap, - const std::string &varname) const; - void write_spam_message(std::ostream &out, FunctionRemap *remap) const; - -protected: - InterrogateModuleDef *_def; - - FunctionWriters _function_writers; -}; - -#endif diff --git a/dtool/src/interrogate/interfaceMakerC.cxx b/dtool/src/interrogate/interfaceMakerC.cxx deleted file mode 100644 index 0deaa685be6..00000000000 --- a/dtool/src/interrogate/interfaceMakerC.cxx +++ /dev/null @@ -1,253 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerC.cxx - * @author drose - * @date 2001-09-25 - */ - -#include "interfaceMakerC.h" -#include "interrogateBuilder.h" -#include "interrogate.h" -#include "functionRemap.h" -#include "parameterRemapHandleToInt.h" -#include "parameterRemapUnchanged.h" -#include "typeManager.h" - -#include "interrogateDatabase.h" -#include "interrogateType.h" -#include "interrogateFunction.h" -#include "cppFunctionType.h" - -using std::ostream; - -/** - * - */ -InterfaceMakerC:: -InterfaceMakerC(InterrogateModuleDef *def) : - InterfaceMaker(def) -{ -} - -/** - * - */ -InterfaceMakerC:: -~InterfaceMakerC() { -} - -/** - * Generates the list of function prototypes corresponding to the functions - * that will be output in write_functions(). - */ -void InterfaceMakerC:: -write_prototypes(ostream &out,ostream *out_h) { - // The 'used' attribute prevents emscripten from optimizing it out. - out << - "#if __GNUC__ >= 4\n" - "#define EXPORT_FUNC extern \"C\" __attribute__((used, visibility(\"default\")))\n" - "#else\n" - "#define EXPORT_FUNC extern \"C\"\n" - "#endif\n\n"; - - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - write_prototype_for(out, func); - } - - out << "\n"; - InterfaceMaker::write_prototypes(out,out_h); -} - -/** - * Generates the list of functions that are appropriate for this interface. - * This function is called *before* write_prototypes(), above. - */ -void InterfaceMakerC:: -write_functions(ostream &out) { - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - write_function_for(out, func); - } - - InterfaceMaker::write_functions(out); -} - -/** - * Allocates a new ParameterRemap object suitable to the indicated parameter - * type. If struct_type is non-NULL, it is the type of the enclosing class - * for the function (method) in question. - * - * The return value is a newly-allocated ParameterRemap object, if the - * parameter type is acceptable, or NULL if the parameter type cannot be - * handled. - */ -ParameterRemap *InterfaceMakerC:: -remap_parameter(CPPType *struct_type, CPPType *param_type) { - // Wrap TypeHandle and ButtonHandle, which are practically just ints, as an - // integer instead of a pointer. It makes things easier on the scripting - // language, especially if there has to be a dynamic downcasting system on - // the scripting language side. - if (TypeManager::is_handle(param_type)) { - return new ParameterRemapHandleToInt(param_type); - - } else { - return InterfaceMaker::remap_parameter(struct_type, param_type); - } -} - -/** - * This method should be overridden and redefined to return true for - * interfaces that require the implicit "this" parameter, if present, to be - * passed as the first parameter to any wrapper functions. - */ -bool InterfaceMakerC:: -synthesize_this_parameter() { - return true; -} - -/** - * Returns the prefix string used to generate wrapper function names. - */ -std::string InterfaceMakerC:: -get_wrapper_prefix() { - return "_inC"; -} - -/** - * Returns the prefix string used to generate unique symbolic names, which are - * not necessarily C-callable function names. - */ -std::string InterfaceMakerC:: -get_unique_prefix() { - return "c"; -} - -/** - * Associates the function wrapper with its function in the appropriate - * structures in the database. - */ -void InterfaceMakerC:: -record_function_wrapper(InterrogateFunction &ifunc, - FunctionWrapperIndex wrapper_index) { - ifunc._c_wrappers.push_back(wrapper_index); -} - -/** - * Writes the prototype for the indicated function. - */ -void InterfaceMakerC:: -write_prototype_for(ostream &out, InterfaceMaker::Function *func) { - Function::Remaps::const_iterator ri; - - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - - if (remap->_extension || (remap->_flags & FunctionRemap::F_explicit_self)) { - continue; - } - - if (output_function_names) { - out << "EXPORT_FUNC "; - } - write_function_header(out, func, remap, false); - out << ";\n"; - } -} - -/** - * Writes the definition for a function that will call the indicated C++ - * function or method. - */ -void InterfaceMakerC:: -write_function_for(ostream &out, InterfaceMaker::Function *func) { - Function::Remaps::const_iterator ri; - - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - write_function_instance(out, func, remap); - } -} - -/** - * Writes out the particular function that handles a single instance of an - * overloaded function. - */ -void InterfaceMakerC:: -write_function_instance(ostream &out, InterfaceMaker::Function *func, - FunctionRemap *remap) { - if (remap->_extension || (remap->_flags & FunctionRemap::F_explicit_self)) { - return; - } - - out << "/*\n" - << " * C wrapper for\n" - << " * "; - remap->write_orig_prototype(out, 0, false, remap->_num_default_parameters); - out << "\n" - << " */\n"; - - if (!output_function_names) { - // If we're not saving the function names, don't export it from the - // library. - out << "static "; - } - - write_function_header(out, func, remap, true); - out << " {\n"; - - if (generate_spam) { - write_spam_message(out, remap); - } - - std::string return_expr = - remap->call_function(out, 2, true, "param0"); - return_expr = manage_return_value(out, 2, remap, return_expr); - if (!return_expr.empty()) { - out << " return " << return_expr << ";\n"; - } - - out << "}\n\n"; -} - -/** - * Writes the first line of a function definition, either for a prototype or a - * function body. - */ -void InterfaceMakerC:: -write_function_header(ostream &out, InterfaceMaker::Function *func, - FunctionRemap *remap, bool newline) { - if (remap->_void_return) { - out << "void"; - } else { - out << remap->_return_type->get_new_type()->get_local_name(&parser); - } - if (newline) { - out << "\n"; - } else { - out << " "; - } - - out << remap->_wrapper_name << "("; - int pn = 0; - if (pn < (int)remap->_parameters.size()) { - remap->_parameters[pn]._remap->get_new_type()-> - output_instance(out, remap->get_parameter_name(pn), &parser); - pn++; - while (pn < (int)remap->_parameters.size()) { - out << ", "; - remap->_parameters[pn]._remap->get_new_type()-> - output_instance(out, remap->get_parameter_name(pn), &parser); - pn++; - } - } - out << ")"; -} diff --git a/dtool/src/interrogate/interfaceMakerC.h b/dtool/src/interrogate/interfaceMakerC.h deleted file mode 100644 index 91c8ef68bf5..00000000000 --- a/dtool/src/interrogate/interfaceMakerC.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerC.h - * @author drose - * @date 2001-09-25 - */ - -#ifndef INTERFACEMAKERC_H -#define INTERFACEMAKERC_H - -#include "dtoolbase.h" - -#include "interfaceMaker.h" -#include "interrogate_interface.h" - -class FunctionRemap; - -/** - * An InteraceMaker suitable for generating a series of C-calling-convention - * functions for Panda class objects. - */ -class InterfaceMakerC : public InterfaceMaker { -public: - InterfaceMakerC(InterrogateModuleDef *def); - virtual ~InterfaceMakerC(); - - virtual void write_prototypes(std::ostream &out,std::ostream *out_h); - virtual void write_functions(std::ostream &out); - - virtual ParameterRemap *remap_parameter(CPPType *struct_type, CPPType *param_type); - - virtual bool synthesize_this_parameter(); - -protected: - virtual std::string get_wrapper_prefix(); - virtual std::string get_unique_prefix(); - - virtual void - record_function_wrapper(InterrogateFunction &ifunc, - FunctionWrapperIndex wrapper_index); - -private: - void write_prototype_for(std::ostream &out, Function *func); - void write_function_for(std::ostream &out, Function *func); - void write_function_instance(std::ostream &out, Function *func, - FunctionRemap *remap); - void write_function_header(std::ostream &out, Function *func, - FunctionRemap *remap, bool newline); -}; - -#endif diff --git a/dtool/src/interrogate/interfaceMakerPython.cxx b/dtool/src/interrogate/interfaceMakerPython.cxx deleted file mode 100644 index cfd82edf191..00000000000 --- a/dtool/src/interrogate/interfaceMakerPython.cxx +++ /dev/null @@ -1,71 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPython.cxx - * @author drose - * @date 2001-09-21 - */ - -#include "interfaceMakerPython.h" -#include "interrogate.h" - -/** - * - */ -InterfaceMakerPython:: -InterfaceMakerPython(InterrogateModuleDef *def) : - InterfaceMaker(def) -{ -} - -/** - * Generates the list of #include ... whatever that's required by this - * particular interface to the indicated output stream. - */ -void InterfaceMakerPython:: -write_includes(std::ostream &out) { - InterfaceMaker::write_includes(out); - out << "#undef _POSIX_C_SOURCE\n" - << "#undef _XOPEN_SOURCE\n" - << "#define PY_SSIZE_T_CLEAN 1\n\n" - << "#if PYTHON_FRAMEWORK\n" - << " #include \n" - << "#else\n" - << " #include \"Python.h\"\n" - << "#endif\n"; -} - -/** - * Outputs code to check to see if an assertion has failed while the C++ code - * was executing, and report this failure back to Python. - */ -void InterfaceMakerPython:: -test_assert(std::ostream &out, int indent_level) const { - if (watch_asserts) { - out << "#ifndef NDEBUG\n"; - indent(out, indent_level) - << "Notify *notify = Notify::ptr();\n"; - indent(out, indent_level) - << "if (UNLIKELY(notify->has_assert_failed())) {\n"; - indent(out, indent_level + 2) - << "PyErr_SetString(PyExc_AssertionError, notify->get_assert_error_message().c_str());\n"; - indent(out, indent_level + 2) - << "notify->clear_assert_failed();\n"; - indent(out, indent_level + 2) - << "return nullptr;\n"; - indent(out, indent_level) - << "}\n"; - indent(out, indent_level) - << "if (PyErr_Occurred()) {\n"; - indent(out, indent_level + 2) - << "return nullptr;\n"; - indent(out, indent_level) - << "}\n"; - out << "#endif\n"; - } -} diff --git a/dtool/src/interrogate/interfaceMakerPython.h b/dtool/src/interrogate/interfaceMakerPython.h deleted file mode 100644 index 612e9ced177..00000000000 --- a/dtool/src/interrogate/interfaceMakerPython.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPython.h - * @author drose - * @date 2001-09-21 - */ - -#ifndef INTERFACEMAKERPYTHON_H -#define INTERFACEMAKERPYTHON_H - -#include "dtoolbase.h" - -#include "interfaceMaker.h" - -class FunctionRemap; - -/** - * The base class for InteraceMakerPythonSimple and InterfaceMakerPythonObj, - * this includes a few functions that both have in common for formatting - * Python objects. - */ -class InterfaceMakerPython : public InterfaceMaker { -protected: - InterfaceMakerPython(InterrogateModuleDef *def); - -public: - virtual void write_includes(std::ostream &out); - -protected: - virtual void test_assert(std::ostream &out, int indent_level) const; -}; - -#endif diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx deleted file mode 100644 index 632e49c1258..00000000000 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ /dev/null @@ -1,8731 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPythonNative.cxx - */ - -#include "interfaceMakerPythonNative.h" -#include "interrogateBuilder.h" -#include "interrogate.h" -#include "functionRemap.h" -#include "parameterRemapUnchanged.h" -#include "typeManager.h" - -#include "pnotify.h" // For nout -#include "interrogateDatabase.h" -#include "interrogateType.h" -#include "interrogateFunction.h" -#include "cppArrayType.h" -#include "cppConstType.h" -#include "cppEnumType.h" -#include "cppFunctionType.h" -#include "cppFunctionGroup.h" -#include "cppPointerType.h" -#include "cppTypeDeclaration.h" -#include "cppTypedefType.h" -#include "cppSimpleType.h" -#include "cppStructType.h" -#include "cppExpression.h" -#include "cppParameterList.h" -#include "cppReferenceType.h" -#include "lineStream.h" - -#include -#include -#include -#include - -using std::dec; -using std::hex; -using std::max; -using std::min; -using std::oct; -using std::ostream; -using std::ostringstream; -using std::set; -using std::string; - -extern InterrogateType dummy_type; -extern std::string EXPORT_IMPORT_PREFIX; - -#define CLASS_PREFIX "Dtool_" - -// Name Remapper... Snagged from ffi py code.... -struct RenameSet { - const char *_from; - const char *_to; - int function_type; -}; - -RenameSet methodRenameDictionary[] = { - { "operator ==" , "__eq__", 0 }, - { "operator !=" , "__ne__", 0 }, - { "operator << " , "__lshift__", 0 }, - { "operator >>" , "__rshift__", 0 }, - { "operator <" , "__lt__", 0 }, - { "operator >" , "__gt__", 0 }, - { "operator <=" , "__le__", 0 }, - { "operator >=" , "__ge__", 0 }, - { "operator <=>" , "__cmp__", 0 }, - { "operator =" , "assign", 0 }, - { "operator ()" , "__call__", 0 }, - { "operator []" , "__getitem__", 0 }, - { "operator []=" , "__setitem__", 0 }, - { "operator ++unary", "increment", 0 }, - { "operator ++" , "increment", 0 }, - { "operator --unary", "decrement", 0 }, - { "operator --" , "decrement", 0 }, - { "operator ^" , "__xor__", 0 }, - { "operator %" , "__mod__", 0 }, - { "operator !" , "logicalNot", 0 }, - { "operator ~unary", "__invert__", 0 }, - { "operator &" , "__and__", 0 }, - { "operator &&" , "logicalAnd", 0 }, - { "operator |" , "__or__", 0 }, - { "operator ||" , "logicalOr", 0 }, - { "operator +" , "__add__", 0 }, - { "operator -" , "__sub__", 0 }, - { "operator -unary", "__neg__", 0 }, - { "operator *" , "__mul__", 0 }, - { "operator /" , "__div__", 0 }, - { "operator +=" , "__iadd__", 1 }, - { "operator -=" , "__isub__", 1 }, - { "operator *=" , "__imul__", 1 }, - { "operator /=" , "__idiv__", 1 }, - { "operator ," , "concatenate", 0 }, - { "operator |=" , "__ior__", 1 }, - { "operator &=" , "__iand__", 1 }, - { "operator ^=" , "__ixor__", 1 }, - { "operator ~=" , "bitwiseNotEqual", 0 }, - { "operator ->" , "dereference", 0 }, - { "operator <<=" , "__ilshift__", 1 }, - { "operator >>=" , "__irshift__", 1 }, - { "operator typecast bool", "__bool__", 0 }, - { "__bool__" , "__bool__", 0 }, - { "__nonzero__" , "__nonzero__", 0 }, - { "__int__" , "__int__", 0 }, - { "__reduce__" , "__reduce__", 0 }, - { "__reduce_ex__" , "__reduce_ex__", 0 }, - { "__reduce_persist__", "__reduce_persist__", 0 }, - { "__copy__" , "__copy__", 0 }, - { "__deepcopy__" , "__deepcopy__", 0 }, - { "__getstate__" , "__getstate__", 0 }, - { "__setstate__" , "__setstate__", 0 }, - { "__new__" , "__new__", 0 }, - { "print" , "Cprint", 0 }, - { "CInterval.set_t", "_priv__cSetT", 0 }, - { nullptr, nullptr, -1 } -}; - -const char *pythonKeywords[] = { - "and", - "as", - "assert", - "async", - "await", - "break", - "class", - "continue", - "def", - "del", - "elif", - "else", - "except", - "exec", - "finally", - "for", - "from", - "global", - "if", - "import", - "in", - "is", - "lambda", - "nonlocal", - "not", - "or", - "pass", - "print", - "raise", - "return", - "try", - "while", - "with", - "yield", - nullptr -}; - -std::string -checkKeyword(std::string &cppName) { - for (int x = 0; pythonKeywords[x] != nullptr; x++) { - if (cppName == pythonKeywords[x]) { - return std::string("_") + cppName; - } - } - return cppName; -} - -std::string -classNameFromCppName(const std::string &cppName, bool mangle) { - if (!mangle_names) { - mangle = false; - } - - // # initialize to empty string - std::string className = ""; - - // # These are the characters we want to strip out of the name - const std::string badChars("!@#$%^&*()<>,.-=+~{}? "); - - bool nextCap = false; - bool nextUscore = false; - bool firstChar = true && mangle; - - for (std::string::const_iterator chr = cppName.begin(); - chr != cppName.end(); ++chr) { - if ((*chr == '_' || *chr == ' ') && mangle) { - nextCap = true; - - } else if (badChars.find(*chr) != std::string::npos) { - nextUscore = !mangle; - - } else if (nextCap || firstChar) { - className += toupper(*chr); - nextCap = false; - firstChar = false; - - } else if (nextUscore) { - className += '_'; - nextUscore = false; - className += *chr; - - } else { - className += *chr; - } - } - - if (className.empty()) { - std::string text = "** ERROR ** Renaming class: " + cppName + " to empty string"; - printf("%s", text.c_str()); - } - - className = checkKeyword(className); - // # FFIConstants.notify.debug('Renaming class: ' + cppName + ' to: ' + - // className) - return className; -} - -std::string -methodNameFromCppName(const std::string &cppName, const std::string &className, bool mangle) { - if (!mangle_names) { - mangle = false; - } - - std::string origName = cppName; - - if (origName.substr(0, 6) == "__py__") { - // By convention, a leading prefix of "__py__" is stripped. This - // indicates a Python-specific variant of a particular method. - origName = origName.substr(6); - } - - std::string methodName; - const std::string badChars("!@#$%^&*()<>,.-=+~{}? "); - bool nextCap = false; - for (std::string::const_iterator chr = origName.begin(); - chr != origName.end(); - chr++) { - if ((*chr == '_' || *chr == ' ') && mangle) { - nextCap = true; - - } else if (badChars.find(*chr) != std::string::npos) { - if (!mangle) { - methodName += '_'; - } - - } else if (nextCap) { - methodName += toupper(*chr); - nextCap = false; - - } else { - methodName += *chr; - } - } - - for (int x = 0; methodRenameDictionary[x]._from != nullptr; x++) { - if (origName == methodRenameDictionary[x]._from) { - methodName = methodRenameDictionary[x]._to; - } - } - - // # Mangle names that happen to be python keywords so they are not anymore - methodName = checkKeyword(methodName); - return methodName; -} - -std::string methodNameFromCppName(InterfaceMaker::Function *func, const std::string &className, bool mangle) { - std::string cppName = func->_ifunc.get_name(); - if (func->_ifunc.is_unary_op()) { - cppName += "unary"; - } - return methodNameFromCppName(cppName, className, mangle); -} - -std::string methodNameFromCppName(FunctionRemap *remap, const std::string &className, bool mangle) { - std::string cppName = remap->_cppfunc->get_local_name(); - if (remap->_ftype->_flags & CPPFunctionType::F_unary_op) { - cppName += "unary"; - } - return methodNameFromCppName(cppName, className, mangle); -} - -/** - * Determines whether this method should be mapped to one of Python's special - * slotted functions, those hard-coded functions that are assigned to - * particular function pointers within the object structure, for special - * functions like __getitem__ and __len__. - * - * Returns true if it has such a mapping, false if it is just a normal method. - * If it returns true, the SlottedFunctionDef structure is filled in with the - * important details. - */ -bool InterfaceMakerPythonNative:: -get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap, - SlottedFunctionDef &def) { - if (obj == nullptr) { - // Only methods may be slotted. - return false; - } - - def._answer_location = string(); - def._wrapper_type = WT_none; - def._min_version = 0; - def._keep_method = false; - - string method_name = func->_ifunc.get_name(); - bool is_unary_op = func->_ifunc.is_unary_op(); - - if (method_name == "operator +" || - method_name == "__add__" || - method_name == "__radd__") { - def._answer_location = "nb_add"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator -" && is_unary_op) { - def._answer_location = "nb_negative"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "operator -" || - method_name == "__sub__" || - method_name == "__rsub__") { - def._answer_location = "nb_subtract"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator *" || - method_name == "__mul__" || - method_name == "__rmul__") { - def._answer_location = "nb_multiply"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator /") { - def._answer_location = "nb_divide"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "__truediv__" || - method_name == "__rtruediv__") { - def._answer_location = "nb_true_divide"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "__floordiv__" || - method_name == "__rfloordiv__") { - def._answer_location = "nb_floor_divide"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator %" || - method_name == "__mod__" || - method_name == "__rmod__") { - def._answer_location = "nb_remainder"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator <<" || - method_name == "__lshift__" || - method_name == "__rlshift__") { - def._answer_location = "nb_lshift"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator >>" || - method_name == "__rshift__" || - method_name == "__rrshift__") { - def._answer_location = "nb_rshift"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator ^" || - method_name == "__xor__" || - method_name == "__rxor__") { - def._answer_location = "nb_xor"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator ~" && is_unary_op) { - def._answer_location = "nb_invert"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "operator &" || - method_name == "__and__" || - method_name == "__rand__") { - def._answer_location = "nb_and"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator |" || - method_name == "__or__" || - method_name == "__ror__") { - def._answer_location = "nb_or"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "__pow__") { - def._answer_location = "nb_power"; - def._wrapper_type = WT_ternary_operator; - return true; - } - - if (method_name == "operator +=") { - def._answer_location = "nb_inplace_add"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator -=") { - def._answer_location = "nb_inplace_subtract"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator *=") { - def._answer_location = "nb_inplace_multiply"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator /=") { - def._answer_location = "nb_inplace_divide"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "__itruediv__") { - def._answer_location = "nb_inplace_true_divide"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "__ifloordiv__") { - def._answer_location = "nb_inplace_floor_divide"; - def._wrapper_type = WT_binary_operator; - return true; - } - - if (method_name == "operator %=") { - def._answer_location = "nb_inplace_remainder"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator <<=") { - def._answer_location = "nb_inplace_lshift"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator >>=") { - def._answer_location = "nb_inplace_rshift"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator &=") { - def._answer_location = "nb_inplace_and"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator ^=") { - def._answer_location = "nb_inplace_xor"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "operator |=") { - def._answer_location = "nb_inplace_or"; - def._wrapper_type = WT_inplace_binary_operator; - return true; - } - - if (method_name == "__ipow__") { - def._answer_location = "nb_inplace_power"; - def._wrapper_type = WT_inplace_ternary_operator; - return true; - } - - if (obj->_protocol_types & Object::PT_sequence) { - if (remap->_flags & FunctionRemap::F_getitem_int) { - def._answer_location = "sq_item"; - def._wrapper_type = WT_sequence_getitem; - return true; - } - if (remap->_flags & FunctionRemap::F_setitem_int || - remap->_flags & FunctionRemap::F_delitem_int) { - def._answer_location = "sq_ass_item"; - def._wrapper_type = WT_sequence_setitem; - return true; - } - if (remap->_flags & FunctionRemap::F_size) { - def._answer_location = "sq_length"; - def._wrapper_type = WT_sequence_size; - return true; - } - } - - if (obj->_protocol_types & Object::PT_mapping) { - if (remap->_flags & FunctionRemap::F_getitem) { - def._answer_location = "mp_subscript"; - def._wrapper_type = WT_one_param; - return true; - } - if (remap->_flags & FunctionRemap::F_setitem || - remap->_flags & FunctionRemap::F_delitem) { - def._answer_location = "mp_ass_subscript"; - def._wrapper_type = WT_mapping_setitem; - return true; - } - if (remap->_flags & FunctionRemap::F_size) { - def._answer_location = "mp_length"; - def._wrapper_type = WT_sequence_size; - return true; - } - } - - if (obj->_protocol_types & Object::PT_iter) { - if (method_name == "__iter__") { - def._answer_location = "tp_iter"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "next" || method_name == "__next__") { - def._answer_location = "tp_iternext"; - def._wrapper_type = WT_iter_next; - return true; - } - } - - if (method_name == "__await__") { - def._answer_location = "am_await"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "__aiter__") { - def._answer_location = "am_aiter"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "__anext__") { - def._answer_location = "am_anext"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "operator ()") { - def._answer_location = "tp_call"; - def._wrapper_type = WT_none; - return true; - } - - if (method_name == "__getattribute__") { - // Like __getattr__, but is called unconditionally, ie. does not try - // PyObject_GenericGetAttr first. - def._answer_location = "tp_getattro"; - def._wrapper_type = WT_one_param; - return true; - } - - if (method_name == "__getattr__") { - def._answer_location = "tp_getattro"; - def._wrapper_type = WT_getattr; - return true; - } - - if (method_name == "__setattr__") { - def._answer_location = "tp_setattro"; - def._wrapper_type = WT_setattr; - return true; - } - - if (method_name == "__delattr__") { - // __delattr__ shares the slot with __setattr__, except that it takes only - // one argument. - def._answer_location = "tp_setattro"; - def._wrapper_type = WT_setattr; - return true; - } - - if (method_name == "__nonzero__" || method_name == "__bool__") { - // Python 2 named it nb_nonzero, Python 3 nb_bool. We refer to it just as - // nb_bool. - def._answer_location = "nb_bool"; - def._wrapper_type = WT_inquiry; - return true; - } - - if (method_name == "__int__") { - def._answer_location = "nb_int"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "__getbuffer__") { - def._answer_location = "bf_getbuffer"; - def._wrapper_type = WT_getbuffer; - return true; - } - - if (method_name == "__releasebuffer__") { - def._answer_location = "bf_releasebuffer"; - def._wrapper_type = WT_releasebuffer; - return true; - } - - if (method_name == "__traverse__") { - def._answer_location = "tp_traverse"; - def._wrapper_type = WT_traverse; - return true; - } - - if (method_name == "__clear__") { - def._answer_location = "tp_clear"; - def._wrapper_type = WT_inquiry; - return true; - } - - if (method_name == "__repr__") { - def._answer_location = "tp_repr"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "__str__") { - def._answer_location = "tp_str"; - def._wrapper_type = WT_no_params; - return true; - } - - if (method_name == "__cmp__" || (remap->_flags & FunctionRemap::F_compare_to) != 0) { - def._answer_location = "tp_compare"; - def._wrapper_type = WT_compare; - def._keep_method = (method_name != "__cmp__"); - return true; - } - - if (method_name == "__hash__" || (remap->_flags & FunctionRemap::F_hash) != 0) { - def._answer_location = "tp_hash"; - def._wrapper_type = WT_hash; - def._keep_method = (method_name != "__hash__"); - return true; - } - - if (method_name == "__new__") { - def._answer_location = "tp_new"; - def._wrapper_type = WT_new; - return true; - } - - if (remap->_type == FunctionRemap::T_typecast_method) { - // A typecast operator. Check for a supported low-level typecast type. - if (TypeManager::is_bool(remap->_return_type->get_orig_type())) { - // If it's a bool type, then we wrap it with the __nonzero__ slot - // method. - def._answer_location = "nb_bool"; - def._wrapper_type = WT_inquiry; - return true; - - } else if (TypeManager::is_integer(remap->_return_type->get_orig_type())) { - // An integer type. - def._answer_location = "nb_int"; - def._wrapper_type = WT_no_params; - return true; - - } else if (TypeManager::is_float(remap->_return_type->get_orig_type())) { - // A floating-point (or double) type. - def._answer_location = "nb_float"; - def._wrapper_type = WT_no_params; - return true; - - } else if (remap->_return_type->new_type_is_atomic_string()) { - // A string type. - def._answer_location = "tp_str"; - def._wrapper_type = WT_no_params; - return true; - } - } - - return false; -} - -/** - * Determines whether the slot occurs in the map of slotted functions, and if - * so, writes out a pointer to its wrapper. If not, writes out def (usually - * 0). - */ -void InterfaceMakerPythonNative:: -write_function_slot(ostream &out, int indent_level, const SlottedFunctions &slots, - const string &slot, const string &default_) { - - SlottedFunctions::const_iterator rfi = slots.find(slot); - if (rfi == slots.end()) { - indent(out, indent_level) << default_ << ","; - if (default_ == "0") { - out << " // " << slot; - } - out << "\n"; - return; - } - - const SlottedFunctionDef &def = rfi->second; - - // Add an #ifdef if there is a specific version requirement on this - // function. - if (def._min_version > 0) { - out << "#if PY_VERSION_HEX >= 0x" << hex << def._min_version << dec << "\n"; - } - - indent(out, indent_level) << "&" << def._wrapper_name << ",\n"; - - if (def._min_version > 0) { - out << "#else\n"; - indent(out, indent_level) << default_ << ",\n"; - out << "#endif\n"; - } -} - -void InterfaceMakerPythonNative:: -get_valid_child_classes(std::map &answer, CPPStructType *inclass, const std::string &upcast_seed, bool can_downcast) { - if (inclass == nullptr) { - return; - } - - for (const CPPStructType::Base &base : inclass->_derivation) { -// if (base._vis <= V_public) can_downcast = false; - CPPStructType *base_type = TypeManager::resolve_type(base._base)->as_struct_type(); - if (base_type != nullptr) { - std::string scoped_name = base_type->get_local_name(&parser); - - if (answer.find(scoped_name) == answer.end()) { - answer[scoped_name]._can_downcast = can_downcast; - answer[scoped_name]._to_class_name = scoped_name; - answer[scoped_name]._structType = base_type; - - if (base._is_virtual) { - answer[scoped_name]._can_downcast = false; - } - - std::string local_upcast("("); - local_upcast += scoped_name + " *)"+ upcast_seed +""; - answer[scoped_name]._up_cast_string = local_upcast; - answer[scoped_name]._is_legal_py_class = is_cpp_type_legal(base_type); - } else { - answer[scoped_name]._can_downcast = false; - } - - get_valid_child_classes(answer, base_type, answer[scoped_name]._up_cast_string, answer[scoped_name]._can_downcast); - } - } -} - -/** - - */ -void InterfaceMakerPythonNative:: -write_python_instance(ostream &out, int indent_level, const string &return_expr, - bool owns_memory, const InterrogateType &itype, bool is_const) { - out << std::boolalpha; - - if (!isExportThisRun(itype._cpptype)) { - _external_imports.insert(TypeManager::resolve_type(itype._cpptype)); - } - - string class_name = itype.get_scoped_name(); - - // We don't handle final classes via DTool_CreatePyInstanceTyped since we - // know it can't be of a subclass type, so we don't need to do the downcast. - CPPStructType *struct_type = itype._cpptype->as_struct_type(); - if (IsPandaTypedObject(struct_type) && !struct_type->is_final()) { - // We can't let DTool_CreatePyInstanceTyped do the NULL check since we - // will be grabbing the type index (which would obviously crash when - // called on a NULL pointer), so we do it here. - indent(out, indent_level) - << "if (" << return_expr << " == nullptr) {\n"; - indent(out, indent_level) - << " return Py_NewRef(Py_None);\n"; - indent(out, indent_level) - << "} else {\n"; - // Special exception if we are returning TypedWritable, which might - // actually be a derived class that inherits from ReferenceCount. - if (!owns_memory && !is_const && class_name == "TypedWritable") { - indent(out, indent_level) - << " ReferenceCount *rc = " << return_expr << "->as_reference_count();\n"; - indent(out, indent_level) - << " bool is_refcount = (rc != nullptr);\n"; - indent(out, indent_level) - << " if (is_refcount) {\n"; - indent(out, indent_level) - << " rc->ref();\n"; - indent(out, indent_level) - << " }\n"; - indent(out, indent_level) - << " return DTool_CreatePyInstanceTyped((void *)" << return_expr - << ", *Dtool_Ptr_" << make_safe_name(class_name) << ", is_refcount, " - << is_const << ", " << return_expr - << "->get_type_index());\n"; - } else { - indent(out, indent_level) - << " return DTool_CreatePyInstanceTyped((void *)" << return_expr - << ", *Dtool_Ptr_" << make_safe_name(class_name) << ", " - << owns_memory << ", " << is_const << ", " - << return_expr << "->as_typed_object()->get_type_index());\n"; - } - indent(out, indent_level) - << "}\n"; - } else { - // DTool_CreatePyInstance will do the NULL check. - indent(out, indent_level) - << "return " - << "DTool_CreatePyInstance((void *)" << return_expr << ", " - << "*Dtool_Ptr_" << make_safe_name(class_name) << ", " - << owns_memory << ", " << is_const << ");\n"; - } -} - -/** - * - */ -InterfaceMakerPythonNative:: -InterfaceMakerPythonNative(InterrogateModuleDef *def) : - InterfaceMakerPython(def) -{ -} - -/** - * - */ -InterfaceMakerPythonNative:: -~InterfaceMakerPythonNative() { -} - -/** - * Generates the list of function prototypes corresponding to the functions - * that will be output in write_functions(). - */ -void InterfaceMakerPythonNative:: -write_prototypes(ostream &out_code, ostream *out_h) { - if (out_h != nullptr) { - *out_h << "#include \"py_panda.h\"\n\n"; - } - - /* - for (Function *func : _functions) { - if (!func->_itype.is_global() && is_function_legal(func)) { - write_prototype_for(out_code, func); - } - } - */ - - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - if (object->_itype.is_class() || object->_itype.is_struct()) { - if (is_cpp_type_legal(object->_itype._cpptype)) { - if (isExportThisRun(object->_itype._cpptype)) { - write_prototypes_class(out_code, out_h, object); - } else { - // write_prototypes_class_external(out_code, object); - // _external_imports.insert(object->_itype._cpptype); - } - } - } else if (object->_itype.is_scoped_enum() && isExportThisRun(object->_itype._cpptype)) { - // Forward declare where we will put the scoped enum type. - string class_name = object->_itype._cpptype->get_local_name(&parser); - string safe_name = make_safe_name(class_name); - out_code << "static PyTypeObject *Dtool_Ptr_" << safe_name << " = nullptr;\n"; - } - } - - out_code << "/**\n"; - out_code << " * Declarations for exported classes\n"; - out_code << " */\n"; - - out_code << "static const Dtool_TypeDef exports[] = {\n"; - - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - - if (object->_itype.is_class() || object->_itype.is_struct()) { - CPPType *type = object->_itype._cpptype; - - if (isExportThisRun(type) && is_cpp_type_legal(type)) { - string class_name = type->get_local_name(&parser); - string safe_name = make_safe_name(class_name); - - out_code << " {\"" << class_name << "\", &Dtool_" << safe_name << "},\n"; - } - } - } - - out_code << " {nullptr, nullptr},\n"; - out_code << "};\n\n"; - - out_code << "/**\n"; - out_code << " * Extern declarations for imported classes\n"; - out_code << " */\n"; - - // Write out a table of the externally imported types that will be filled in - // upon module initialization. - if (!_external_imports.empty()) { - out_code << "#ifndef LINK_ALL_STATIC\n"; - out_code << "static Dtool_TypeDef imports[] = {\n"; - - int idx = 0; - for (CPPType *type : _external_imports) { - string class_name = type->get_local_name(&parser); - string safe_name = make_safe_name(class_name); - - out_code << " {\"" << class_name << "\", nullptr},\n"; - out_code << "#define Dtool_Ptr_" << safe_name << " (imports[" << idx << "].type)\n"; - ++idx; - } - out_code << " {nullptr, nullptr},\n"; - out_code << "};\n"; - out_code << "#endif\n\n"; - } - - for (CPPType *type : _external_imports) { - string class_name = type->get_local_name(&parser); - string safe_name = make_safe_name(class_name); - - out_code << "// " << class_name << "\n"; - - out_code << "#ifndef LINK_ALL_STATIC\n"; - // out_code << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << - // safe_name << ";\n"; - //if (has_get_class_type_function(type)) { - // out_code << "static struct Dtool_PyTypedObject *Dtool_Ptr_" << safe_name << ";\n"; - //} - // out_code << "#define Dtool_Ptr_" << safe_name << " &Dtool_" << - // safe_name << "\n"; out_code << "IMPORT_THIS void - // Dtool_PyModuleClassInit_" << safe_name << "(PyObject *module);\n"; - - // This is some really ugly code, because we have to store a pointer with - // a function of a signature that differs from class to class. If someone - // can think of an elegant way to do this without sacrificing perf, let me - // know. - int has_coerce = has_coerce_constructor(type->as_struct_type()); - if (has_coerce > 0) { - if (TypeManager::is_reference_count(type)) { - out_code - << "inline static bool Dtool_ConstCoerce_" << safe_name << "(PyObject *args, CPT(" << class_name << ") &coerced) {\n" - << " nassertr(Dtool_Ptr_" << safe_name << " != nullptr, false);\n" - << " nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce != nullptr, false);\n" - << " return ((bool (*)(PyObject *, CPT(" << class_name << ") &))Dtool_Ptr_" << safe_name << "->_Dtool_ConstCoerce)(args, coerced);\n" - << "}\n"; - - if (has_coerce > 1) { - out_code - << "inline static bool Dtool_Coerce_" << safe_name << "(PyObject *args, PT(" << class_name << ") &coerced) {\n" - << " nassertr(Dtool_Ptr_" << safe_name << " != nullptr, false);\n" - << " nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_Coerce != nullptr, false);\n" - << " return ((bool (*)(PyObject *, PT(" << class_name << ") &))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced);\n" - << "}\n"; - } - } else { - out_code - << "inline static " << class_name << " *Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " &coerced) {\n" - << " nassertr(Dtool_Ptr_" << safe_name << " != nullptr, nullptr);\n" - << " nassertr(Dtool_Ptr_" << safe_name << "->_Dtool_Coerce != nullptr, nullptr);\n" - << " return ((" << class_name << " *(*)(PyObject *, " << class_name << " &))Dtool_Ptr_" << safe_name << "->_Dtool_Coerce)(args, coerced);\n" - << "}\n"; - } - } - out_code << "#else\n"; - out_code << "extern struct Dtool_PyTypedObject Dtool_" << safe_name << ";\n"; - out_code << "static struct Dtool_PyTypedObject *const Dtool_Ptr_" << safe_name << " = &Dtool_" << safe_name << ";\n"; - - if (has_coerce > 0) { - if (TypeManager::is_reference_count(type)) { - out_code << "extern bool Dtool_ConstCoerce_" << safe_name << "(PyObject *args, CPT(" << class_name << ") &coerced);\n"; - if (has_coerce > 1) { - out_code << "extern bool Dtool_Coerce_" << safe_name << "(PyObject *args, PT(" << class_name << ") &coerced);\n"; - } - } else { - out_code << "extern " << class_name << " *Dtool_Coerce_" << safe_name << "(PyObject *args, " << class_name << " &coerced);\n"; - } - } - out_code << "#endif\n"; - } -} - -/** - * Output enough enformation to a declartion of a externally generated dtool - * type object - */ -void InterfaceMakerPythonNative:: -write_prototypes_class_external(ostream &out, Object *obj) { - std::string class_name = make_safe_name(obj->_itype.get_scoped_name()); - std::string c_class_name = obj->_itype.get_true_name(); - std::string preferred_name = obj->_itype.get_name(); - - - out << "/**\n"; - out << " * Forward declaration of class " << class_name << "\n"; - out << " */\n"; - - // This typedef is necessary for class templates since we can't pass a comma - // to a macro function. - out << "typedef " << c_class_name << " " << class_name << "_localtype;\n"; - out << "Define_Module_Class_Forward(" << _def->module_name << ", " << class_name << ", " << class_name << "_localtype, " << classNameFromCppName(preferred_name, false) << ");\n"; -} - -/** - - */ -void InterfaceMakerPythonNative:: -write_prototypes_class(ostream &out_code, ostream *out_h, Object *obj) { - std::string ClassName = make_safe_name(obj->_itype.get_scoped_name()); - - out_code << "/**\n"; - out_code << " * Forward declarations for top-level class " << ClassName << "\n"; - out_code << " */\n"; - - /* - for (Function *func : obj->_methods) { - write_prototype_for(out_code, func); - } - */ - - /* - for (Function *func : obj->_constructors) { - std::string fname = "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)"; - write_prototype_for_name(out_code, obj, func, fname); - } - */ - - write_class_declarations(out_code, out_h, obj); -} - -/** - * Generates the list of functions that are appropriate for this interface. - * This function is called *before* write_prototypes(), above. - */ -void InterfaceMakerPythonNative:: -write_functions(ostream &out) { - out << "/**\n"; - out << " * Python wrappers for global functions\n" ; - out << " */\n"; - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - if (!func->_itype.is_global() && is_function_legal(func)) { - write_function_for_top(out, nullptr, func); - } - } - - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - if (object->_itype.is_class() || object->_itype.is_struct()) { - if (is_cpp_type_legal(object->_itype._cpptype)) { - if (isExportThisRun(object->_itype._cpptype)) { - write_class_details(out, object); - } - } - } - } - - // Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - if (!object->_itype.get_outer_class()) { - if (object->_itype.is_class() || object->_itype.is_struct()) { - if (is_cpp_type_legal(object->_itype._cpptype)) { - if (isExportThisRun(object->_itype._cpptype)) { - write_module_class(out, object); - } - } - } - } - } -} - -/** - * Writes out all of the wrapper methods necessary to export the given object. - * This is called by write_functions. - */ -void InterfaceMakerPythonNative:: -write_class_details(ostream &out, Object *obj) { - // std::string cClassName = obj->_itype.get_scoped_name(); - std::string ClassName = make_safe_name(obj->_itype.get_scoped_name()); - std::string cClassName = obj->_itype.get_true_name(); - - CPPType *cpptype = TypeManager::resolve_type(obj->_itype._cpptype); - CPPStructType *struct_type = cpptype->as_struct_type(); - - // Determine which external imports we will need. - std::map details; - std::map::iterator di; - builder.get_type(TypeManager::unwrap(cpptype), false); - get_valid_child_classes(details, cpptype->as_struct_type()); - for (di = details.begin(); di != details.end(); di++) { - // InterrogateType ptype =idb->get_type(di->first); - if (di->second._is_legal_py_class && !isExportThisRun(di->second._structType)) { - _external_imports.insert(TypeManager::resolve_type(di->second._structType)); - } - // out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << - // make_safe_name(di->second._to_class_name) << ";\n"; - } - - bool py_subclassable = is_python_subclassable(struct_type); - if (py_subclassable) { - assert(!obj->_constructors.empty()); - out << "/**\n"; - out << " * Proxy class for " << cClassName << "\n"; - out << " */\n"; - out << "class DtoolProxy_" << ClassName << " final : public " << cClassName << ", public DtoolProxy {\n"; - out << "public:\n"; - // I'd love just to use "using" to inherit the constructors from the base. - // However, MSVC seems to have a bug inheriting constructors with default - // arguments. - if (struct_type->is_default_constructible()) { - out << " DtoolProxy_" << ClassName << "() = default;\n"; - } - for (Function *func : obj->_constructors) { - for (FunctionRemap *remap : func->_remaps) { - CPPParameterList::Parameters ¶ms = remap->_ftype->_parameters->_parameters; - if (params.empty()) { - continue; - } - out << " DtoolProxy_" << ClassName << "("; - for (size_t i = 0; i < params.size(); ++i) { - if (i > 0) { - out << ", "; - } - params[i]->_type->output_instance(out, remap->get_parameter_name(i), &parser); - if (i > 0 && params[i]->_initializer != nullptr) { - out << " = " << *params[i]->_initializer; - } - } - out << ")"; - if (remap->_ftype->_flags & CPPFunctionType::F_noexcept) { - out << " noexcept"; - } - out << " : " << cClassName << "("; - for (size_t i = 0; i < params.size(); ++i) { - if (i > 0) { - out << ", "; - } - // Determine whether to pass with move semantics or not. - CPPType *param_type = params[i]->_type; - CPPType::SubType subtype = param_type->get_subtype(); - while (subtype == CPPDeclaration::ST_typedef) { - param_type = param_type->as_typedef_type()->_type; - subtype = param_type->get_subtype(); - } - if (subtype == CPPType::ST_pointer || - subtype == CPPType::ST_const || - subtype == CPPType::ST_enum || - subtype == CPPType::ST_simple || - (subtype == CPPType::ST_reference && param_type->as_reference_type()->_value_category == CPPReferenceType::VC_lvalue)) { - out << remap->get_parameter_name(i); - } else { - out << "std::move(" << remap->get_parameter_name(i) << ")"; - } - } - out << ") {}\n"; - } - } - - // Move constructor is never listed above, but we do use it. - if (struct_type->is_move_constructible()) { - out << " DtoolProxy_" << ClassName << "(" << cClassName << " &&from)"; - CPPInstance *ctor = struct_type->get_move_constructor(); - if (ctor != nullptr) { - CPPFunctionType *ftype = ctor->_type->as_function_type(); - if (ftype != nullptr && (ftype->_flags & CPPFunctionType::F_noexcept) != 0) { - out << " noexcept"; - } - } - out << " : " << cClassName << "(std::move(from)) {}\n"; - } - out << "\n"; - out << " virtual bool unref() const override {\n"; - out << " if (!(" << cClassName << "::unref())) {\n"; - out << " // It was cleaned up by the Python garbage collector.\n"; - out << " return false;\n"; - out << " }\n"; - out << " nassertr(DtoolProxy::_self != nullptr, true);\n"; - out << "\n"; - out << " // If the last reference to the object is the one being held by Python,\n"; - out << " // check whether the Python wrapper itself is also at a refcount of 1.\n"; - out << " bool result = true;\n"; - out << " if (get_ref_count() == 1) {\n"; - out << " PyGILState_STATE gstate = PyGILState_Ensure();\n"; - out << " int ref_count = Py_REFCNT(DtoolProxy::_self);\n"; - out << " assert(ref_count > 0);\n"; - out << " if (ref_count == 1) {\n"; - out << " // The last reference to the Python wrapper is being held by us.\n"; - out << " // Break the reference cycle and allow the object to go away.\n"; - out << " if (!" << cClassName << "::unref()) {\n"; - out << " PyObject_GC_UnTrack(DtoolProxy::_self);\n"; - out << " ((Dtool_PyInstDef *)DtoolProxy::_self)->_memory_rules = false;\n"; - out << " Py_CLEAR(DtoolProxy::_self);\n"; - out << "\n"; - out << " // Let the caller destroy the object.\n"; - out << " result = false;\n"; - out << " }\n"; - out << " }\n"; - //out << " else {\n"; - //out << " // There is still a Python reference. Make sure it can be cleaned up\n"; - //out << " // by the garbage collector when it gets to it.\n"; - //out << " if (!PyObject_GC_IsTracked(DtoolProxy::_self)) {\n"; - //out << " PyObject_GC_Track(DtoolProxy::_self);\n"; - //out << " }\n"; - //out << " }\n"; - out << " PyGILState_Release(gstate);\n"; - out << " }\n"; - out << " return result;\n"; - out << " }\n"; - out << "\n"; - out << " virtual TypeHandle get_type() const override {\n"; - out << " return DtoolProxy::_type;\n"; - out << " }\n"; - out << "\n"; - out << " virtual TypeHandle force_init_type() override {\n"; - out << " return DtoolProxy::_type;\n"; - out << " }\n"; - out << "};\n"; - out << "\n"; - - out << "static PyObject *Dtool_WrapProxy_" << ClassName << "(void *from_this, PyTypeObject *from_type) {\n"; - out << " DtoolProxy_" << ClassName << " *to_this;\n"; - out << " if (from_type == nullptr || from_type == &Dtool_" << ClassName << "._PyType) {\n"; - out << " to_this = (DtoolProxy_" << ClassName << " *)(" << cClassName << "*)from_this;\n"; - out << " }\n"; - for (di = details.begin(); di != details.end(); di++) { - if (di->second._can_downcast && di->second._is_legal_py_class) { - out << " else if (from_type == (PyTypeObject *)Dtool_Ptr_" << make_safe_name(di->second._to_class_name) << ") {\n"; - out << " " << di->second._to_class_name << " *other_this = (" << di->second._to_class_name << " *)from_this;\n" ; - out << " to_this = (DtoolProxy_" << ClassName << " *)(" << cClassName << " *)other_this;\n"; - out << " }\n"; - } - } - out << " else {\n"; - out << " return nullptr;\n"; - out << " }\n"; - out << " nassertr(to_this->DtoolProxy::_self != nullptr, nullptr);\n"; - out << " PyObject *result = Py_NewRef(to_this->DtoolProxy::_self);\n"; - // Directly call the parent class' unref(), because we know our version - // would only find that the Python refcount > 1 and do nothing else - out << " bool nonzero = to_this->" << cClassName << "::unref();\n"; - out << " nassertr(nonzero, result);\n"; - out << " return result;\n"; - out << "}\n\n"; - } - - out << "/**\n"; - out << " * Python wrappers for functions of class " << cClassName << "\n" ; - out << " */\n"; - - // First write out all the wrapper functions for the methods. - bool have_new = false; - for (Function *func : obj->_methods) { - if (func) { - // Write the definition of the generic wrapper function for this - // function. - if (func->_ifunc.get_name() == "__new__") { - have_new = true; - } - write_function_for_top(out, obj, func); - } - } - - // Now write out generated getters and setters for the properties. - for (Property *property : obj->_properties) { - write_getset(out, obj, property); - } - - // Write the constructors. - std::string fname = "static int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)"; - for (Function *func : obj->_constructors) { - string expected_params; - write_function_for_name(out, obj, func->_remaps, fname, expected_params, true, AT_keyword_args, RF_int); - } - if (obj->_constructors.size() == 0) { - // We still need to write a dummy constructor to prevent inheriting the - // constructor from a base class. - if (have_new) { - out << fname << " {\n" - " return 0;\n" - "}\n\n"; - } else { - out << fname << " {\n" - " Dtool_Raise_TypeError(\"cannot init abstract class\");\n" - " return -1;\n" - "}\n\n"; - } - } - - // If we have "coercion constructors", write a single wrapper to consolidate - // those. - int has_coerce = has_coerce_constructor(struct_type); - if (has_coerce > 0) { - write_coerce_constructor(out, obj, true); - if (has_coerce > 1 && TypeManager::is_reference_count(obj->_itype._cpptype)) { - write_coerce_constructor(out, obj, false); - } - } - - // Write make seqs: generated methods that return a sequence of items. - for (MakeSeq *make_seq : obj->_make_seqs) { - if (is_function_legal(make_seq->_length_getter) && - is_function_legal(make_seq->_element_getter)) { - write_make_seq(out, obj, ClassName, cClassName, make_seq); - } else { - if (!is_function_legal(make_seq->_length_getter)) { - std::cerr << "illegal length function for MAKE_SEQ: " << make_seq->_length_getter->_name << "\n"; - } - if (!is_function_legal(make_seq->_element_getter)) { - std::cerr << "illegal element function for MAKE_SEQ: " << make_seq->_element_getter->_name << "\n"; - } - } - } - - // Write support methods to cast from and to pointers of this type. - { - out << "static void *Dtool_UpcastInterface_" << ClassName << "(PyObject *self, Dtool_PyTypedObject *requested_type) {\n"; - out << " Dtool_PyTypedObject *type = DtoolInstance_TYPE(self);\n"; - out << " if (type != &Dtool_" << ClassName << ") {\n"; - out << " printf(\"%s ** Bad Source Type-- Requesting Conversion from %s to %s\\n\", \"" << ClassName << "\", Py_TYPE(self)->tp_name, requested_type->_PyType.tp_name); fflush(nullptr);\n"; - out << " return nullptr;\n"; - out << " }\n"; - out << "\n"; - out << " " << cClassName << " *local_this = (" << cClassName << " *)DtoolInstance_VOID_PTR(self);\n"; - out << " if (requested_type == &Dtool_" << ClassName << ") {\n"; - out << " return local_this;\n"; - out << " }\n"; - - for (di = details.begin(); di != details.end(); di++) { - if (di->second._is_legal_py_class) { - out << " if (requested_type == Dtool_Ptr_" << make_safe_name(di->second._to_class_name) << ") {\n"; - out << " return " << di->second._up_cast_string << " local_this;\n"; - out << " }\n"; - } - } - - // Are there any implicit cast operators that can cast this object to our - // desired pointer? - for (Function *func : obj->_methods) { - for (FunctionRemap *remap : func->_remaps) { - if (remap->_type == FunctionRemap::T_typecast_method && - is_remap_legal(remap) && - !remap->_return_type->return_value_needs_management() && - (remap->_cppfunc->_storage_class & CPPInstance::SC_explicit) == 0 && - TypeManager::is_pointer(remap->_return_type->get_new_type())) { - - CPPType *cast_type = remap->_return_type->get_orig_type(); - CPPType *obj_type = TypeManager::unwrap(TypeManager::resolve_type(remap->_return_type->get_new_type())); - string return_expr = "(" + cast_type->get_local_name(&parser) + ")*local_this"; - out << " // " << *remap->_cppfunc << "\n"; - out << " if (requested_type == Dtool_Ptr_" << make_safe_name(obj_type->get_local_name(&parser)) << ") {\n"; - out << " return (void *)(" << remap->_return_type->get_return_expr(return_expr) << ");\n"; - out << " }\n"; - } - } - } - - out << " return nullptr;\n"; - out << "}\n\n"; - - //NB. This may be called with nullptr in either argument and should produce - // a valid wrapper object even with a null pointer. - out << "static PyObject *Dtool_Wrap_" << ClassName << "(void *from_this, PyTypeObject *from_type) {\n"; - out << " " << cClassName << " *to_this;\n"; - out << " if (from_type == nullptr || from_type == &Dtool_" << ClassName << "._PyType) {\n"; - out << " to_this = (" << cClassName << " *)from_this;\n"; - out << " }\n"; - for (di = details.begin(); di != details.end(); di++) { - if (di->second._can_downcast && di->second._is_legal_py_class) { - out << " else if (from_type == (PyTypeObject *)Dtool_Ptr_" << make_safe_name(di->second._to_class_name) << ") {\n"; - out << " " << di->second._to_class_name << " *other_this = (" << di->second._to_class_name << " *)from_this;\n" ; - out << " to_this = (" << cClassName << " *)other_this;\n"; - out << " }\n"; - } - } - out << " else {\n"; - out << " return nullptr;\n"; - out << " }\n"; - if (has_self_member(struct_type)) { - out << " PyObject *stored_self = to_this->__self__;\n"; - out << " if (stored_self == nullptr) {\n"; - out << " // Allocate a new Python instance\n"; - out << " Dtool_PyInstDef *self = (Dtool_PyInstDef *)PyType_GenericAlloc(&Dtool_" << ClassName << "._PyType, 0);\n"; - out << " self->_signature = PY_PANDA_SIGNATURE;\n"; - out << " self->_My_Type = &Dtool_" << ClassName << ";\n"; - out << " self->_ptr_to_object = to_this;\n"; - out << " self->_memory_rules = true;\n"; - out << " self->_is_const = false;\n"; - out << " to_this->__self__ = Py_NewRef((PyObject *)self);\n"; - out << " return Py_NewRef((PyObject *)self);\n"; - out << " }\n"; - out << " PyObject *result = Py_NewRef(stored_self);\n"; - out << " bool nonzero = to_this->unref();\n"; - out << " nassertr(nonzero, result);\n"; - out << " return result;\n"; - } else { - out << " // Allocate a new Python instance\n"; - out << " Dtool_PyInstDef *self = (Dtool_PyInstDef *)PyType_GenericAlloc(&Dtool_" << ClassName << "._PyType, 0);\n"; - out << " self->_signature = PY_PANDA_SIGNATURE;\n"; - out << " self->_My_Type = &Dtool_" << ClassName << ";\n"; - out << " self->_ptr_to_object = to_this;\n"; - out << " self->_memory_rules = false;\n"; - out << " self->_is_const = false;\n"; - out << " return (PyObject *)self;\n"; - } - out << "}\n\n"; - } -} - -/** - - */ -void InterfaceMakerPythonNative:: -write_class_declarations(ostream &out, ostream *out_h, Object *obj) { - const InterrogateType &itype = obj->_itype; - std::string class_name = make_safe_name(obj->_itype.get_scoped_name()); - std::string c_class_name = obj->_itype.get_true_name(); - std::string preferred_name = itype.get_name(); - std::string class_struct_name = std::string(CLASS_PREFIX) + class_name; - - CPPType *type = obj->_itype._cpptype; - - // This typedef is necessary for class templates since we can't pass a comma - // to a macro function. - out << "typedef " << c_class_name << " " << class_name << "_localtype;\n"; - if (obj->_itype.has_destructor() || - obj->_itype.destructor_is_inherited() || - obj->_itype.destructor_is_implicit()) { - - if (TypeManager::is_reference_count(type)) { - out << "Define_Module_ClassRef"; - } else { - out << "Define_Module_Class"; - } - } else { - if (TypeManager::is_reference_count(type)) { - out << "Define_Module_ClassRef_Private"; - } else { - out << "Define_Module_Class_Private"; - } - } - out << "(" << _def->module_name << ", " << class_name << ", " << class_name << "_localtype, " << classNameFromCppName(preferred_name, false) << ");\n"; - - out << "static struct Dtool_PyTypedObject *const Dtool_Ptr_" << class_name << " = &Dtool_" << class_name << ";\n"; - out << "static void Dtool_PyModuleClassInit_" << class_name << "(PyObject *module);\n"; - - int has_coerce = has_coerce_constructor(type->as_struct_type()); - if (has_coerce > 0) { - if (TypeManager::is_reference_count(type)) { - out << "bool Dtool_ConstCoerce_" << class_name << "(PyObject *args, CPT(" << c_class_name << ") &coerced);\n"; - if (has_coerce > 1) { - out << "bool Dtool_Coerce_" << class_name << "(PyObject *args, PT(" << c_class_name << ") &coerced);\n"; - } - } else { - out << "" << c_class_name << " *Dtool_Coerce_" << class_name << "(PyObject *args, " << c_class_name << " &coerced);\n"; - } - } - - out << "\n"; - - if (out_h != nullptr) { - *out_h << "extern \"C\" " << EXPORT_IMPORT_PREFIX << " struct Dtool_PyTypedObject Dtool_" << class_name << ";\n"; - } -} - -/** - * Generates whatever additional code is required to support a module file. - */ -void InterfaceMakerPythonNative:: -write_sub_module(ostream &out, Object *obj) { - // Object * obj = _objects[_embeded_index] ; - string class_name = make_safe_name(obj->_itype.get_scoped_name()); - string class_ptr; - - if (!obj->_itype.is_typedef()) { - out << " // " << *(obj->_itype._cpptype) << "\n"; - out << " Dtool_PyModuleClassInit_" << class_name << "(module);\n"; - class_ptr = "&Dtool_" + class_name; - - } else { - // Unwrap typedefs. - TypeIndex wrapped = obj->_itype._wrapped_type; - while (interrogate_type_is_typedef(wrapped)) { - wrapped = interrogate_type_wrapped_type(wrapped); - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - const InterrogateType &wrapped_itype = idb->get_type(wrapped); - - class_name = make_safe_name(wrapped_itype.get_scoped_name()); - - out << " // typedef " << wrapped_itype.get_scoped_name() - << " " << *(obj->_itype._cpptype) << "\n"; - - if (!isExportThisRun(wrapped_itype._cpptype)) { - _external_imports.insert(TypeManager::resolve_type(wrapped_itype._cpptype)); - - class_ptr = "Dtool_Ptr_" + class_name; - out << " assert(" << class_ptr << " != nullptr);\n"; - } else { - class_ptr = "&Dtool_" + class_name; - - // If this is a typedef to a class defined in the same module, make sure - // that the class is initialized before we try to define the typedef. - out << " Dtool_PyModuleClassInit_" << class_name << "(module);\n"; - } - } - - std::string export_class_name = classNameFromCppName(obj->_itype.get_name(), false); - std::string export_class_name2 = classNameFromCppName(obj->_itype.get_name(), true); - - class_ptr = "(PyObject *)" + class_ptr; - - // The first time we add something to a module, we use PyModule_AddObject, - // which steals a reference. This saves a call to Py_DECREF. - if (!obj->_itype.is_typedef()) { - out << " PyModule_AddObject(module, \"" << export_class_name << "\", " << class_ptr << ");\n"; - } else { - out << " PyModule_AddObjectRef(module, \"" << export_class_name << "\", " << class_ptr << ");\n"; - } - if (export_class_name != export_class_name2) { - out << " PyModule_AddObjectRef(module, \"" << export_class_name2 << "\", " << class_ptr << ");\n"; - } -} - -/** - - */ -void InterfaceMakerPythonNative:: -write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) { - out << "/**\n"; - out << " * Module Object Linker ..\n"; - out << " */\n"; - - Objects::iterator oi; - - out << "void Dtool_" << def->library_name << "_RegisterTypes() {\n" - " TypeRegistry *registry = TypeRegistry::ptr();\n" - " nassertv(registry != nullptr);\n"; - - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - if (object->_itype.is_class() || object->_itype.is_struct()) { - CPPType *type = object->_itype._cpptype; - if (is_cpp_type_legal(type) && isExportThisRun(type)) { - string class_name = object->_itype.get_scoped_name(); - string safe_name = make_safe_name(class_name); - bool is_typed = has_get_class_type_function(type); - - if (is_typed) { - out << " {\n"; - if (has_init_type_function(type)) { - // Call the init_type function. This isn't necessary for all - // types as many of them are automatically initialized at static - // init type, but for some extension classes it's useful. - out << " " << type->get_local_name(&parser) - << "::init_type();\n"; - } - out << " TypeHandle handle = " << type->get_local_name(&parser) - << "::get_class_type();\n"; - out << " Dtool_" << safe_name << "._type = handle;\n"; - out << " registry->record_python_type(handle," - " &Dtool_" << safe_name << "._PyType," - " Dtool_Wrap_" << safe_name << ");\n"; - out << " }\n"; - } else { - if (IsPandaTypedObject(type->as_struct_type())) { - nout << object->_itype.get_scoped_name() << " derives from TypedObject, " - << "but does not define a get_class_type() function.\n"; - } - } - } - } - } - out << "}\n\n"; - - out << "void Dtool_" << def->library_name << "_BuildInstants(PyObject *module) {\n"; - out << " (void) module;\n"; - - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - if (object->_itype.is_enum() && !object->_itype.is_nested() && - isExportThisRun(object->_itype._cpptype)) { - int enum_count = object->_itype.number_of_enum_values(); - - if (object->_itype.is_scoped_enum()) { - // Convert as Python 3.4-style enum. - string class_name = object->_itype._cpptype->get_local_name(&parser); - string safe_name = make_safe_name(class_name); - - CPPType *underlying_type = TypeManager::unwrap_const(object->_itype._cpptype->as_enum_type()->get_underlying_type()); - string cast_to = underlying_type->get_local_name(&parser); - out << " // enum class " << object->_itype.get_scoped_name() << "\n"; - out << " {\n"; - out << " PyObject *members = PyTuple_New(" << enum_count << ");\n"; - out << " PyObject *member;\n"; - for (int xx = 0; xx < enum_count; xx++) { - out << " member = PyTuple_New(2);\n" - "#if PY_MAJOR_VERSION >= 3\n" - " PyTuple_SET_ITEM(member, 0, PyUnicode_FromString(\"" - << object->_itype.get_enum_value_name(xx) << "\"));\n" - "#else\n" - " PyTuple_SET_ITEM(member, 0, PyString_FromString(\"" - << object->_itype.get_enum_value_name(xx) << "\"));\n" - "#endif\n" - " PyTuple_SET_ITEM(member, 1, Dtool_WrapValue((" - << cast_to << ")" << object->_itype.get_scoped_name() << "::" - << object->_itype.get_enum_value_name(xx) << "));\n" - " PyTuple_SET_ITEM(members, " << xx << ", member);\n"; - } - out << " Dtool_Ptr_" << safe_name << " = Dtool_EnumType_Create(\"" - << object->_itype.get_name() << "\", members, \"" - << _def->module_name << "\");\n"; - out << " PyModule_AddObject(module, \"" << object->_itype.get_name() - << "\", (PyObject *)Dtool_Ptr_" << safe_name << ");\n"; - out << " }\n"; - } else { - out << " // enum " << object->_itype.get_scoped_name() << "\n"; - for (int xx = 0; xx < enum_count; xx++) { - string name1 = classNameFromCppName(object->_itype.get_enum_value_name(xx), false); - string name2 = classNameFromCppName(object->_itype.get_enum_value_name(xx), true); - string enum_value = "::" + object->_itype.get_enum_value_name(xx); - out << " PyModule_AddObject(module, \"" << name1 << "\", Dtool_WrapValue(" << enum_value << "));\n"; - if (name1 != name2) { - // Also write the mangled name, for historical purposes. - out << " PyModule_AddObject(module, \"" << name2 << "\", Dtool_WrapValue(" << enum_value << "));\n"; - } - } - } - } - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - int num_manifests = idb->get_num_global_manifests(); - for (int mi = 0; mi < num_manifests; mi++) { - ManifestIndex manifest_index = idb->get_global_manifest(mi); - const InterrogateManifest &iman = idb->get_manifest(manifest_index); - if (iman.has_getter()) { - FunctionIndex func_index = iman.get_getter(); - record_function(dummy_type, func_index); - } - - string name1 = classNameFromCppName(iman.get_name(), false); - string name2 = classNameFromCppName(iman.get_name(), true); - if (iman.has_int_value()) { - int value = iman.get_int_value(); - out << " PyModule_AddIntConstant(module, \"" << name1 << "\", " << value << ");\n"; - if (name1 != name2) { - // Also write the mangled name, for historical purposes. - out << " PyModule_AddIntConstant(module, \"" << name2 << "\", " << value << ");\n"; - } - } else { - string value = iman.get_definition(); - out << " PyModule_AddStringConstant(module, \"" << name1 << "\", \"" << value << "\");\n"; - if (name1 != name2) { - out << " PyModule_AddStringConstant(module, \"" << name2 << "\", \"" << value << "\");\n"; - } - } - } - - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - if (!object->_itype.get_outer_class()) { - if (object->_itype.is_class() || - object->_itype.is_struct() || - object->_itype.is_typedef()) { - if (is_cpp_type_legal(object->_itype._cpptype)) { - if (isExportThisRun(object->_itype._cpptype)) { - write_sub_module(out, object); - } - } - } - } - } - - out << "}\n\n"; - - bool force_base_functions = true; - - out << "static PyMethodDef python_simple_funcs[] = {\n"; - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - if (!func->_itype.is_global() && is_function_legal(func)) { - string name1 = methodNameFromCppName(func, "", false); - string name2 = methodNameFromCppName(func, "", true); - - string flags; - string fptr = "&" + func->_name; - switch (func->_args_type) { - case AT_keyword_args: - flags = "METH_VARARGS | METH_KEYWORDS"; - fptr = "(PyCFunction) " + fptr; - break; - - case AT_varargs: - flags = "METH_VARARGS"; - break; - - case AT_single_arg: - flags = "METH_O"; - break; - - default: - flags = "METH_NOARGS"; - break; - } - - // Note: we shouldn't add METH_STATIC here, since both METH_STATIC and - // METH_CLASS are illegal for module-level functions. - - out << " {\"" << name1 << "\", " << fptr - << ", " << flags << ", (const char *)" << func->_name << "_comment},\n"; - if (name1 != name2) { - out << " {\"" << name2 << "\", " << fptr - << ", " << flags << ", (const char *)" << func->_name << "_comment},\n"; - } - } - } - - if (force_base_functions) { - out << " // Support Function For Dtool_types ... for now in each module ??\n"; - out << " {\"Dtool_BorrowThisReference\", &Dtool_BorrowThisReference, METH_VARARGS, \"Used to borrow 'this' pointer (to, from)\\nAssumes no ownership.\"},\n"; - //out << " {\"Dtool_AddToDictionary\", &Dtool_AddToDictionary, METH_VARARGS, \"Used to add items into a tp_dict\"},\n"; - } - - out << " {nullptr, nullptr, 0, nullptr}\n" << "};\n\n"; - - if (_external_imports.empty()) { - out << "extern const struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs, exports, nullptr};\n"; - } else { - out << - "#ifdef LINK_ALL_STATIC\n" - "extern const struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs, exports, nullptr};\n" - "#else\n" - "extern const struct LibraryDef " << def->library_name << "_moddef = {python_simple_funcs, exports, imports};\n" - "#endif\n"; - } - if (out_h != nullptr) { - *out_h << "extern const struct LibraryDef " << def->library_name << "_moddef;\n"; - } -} - -/** - - */ -void InterfaceMakerPythonNative:: -write_module(ostream &out, ostream *out_h, InterrogateModuleDef *def) { - InterfaceMakerPython::write_module(out, out_h, def); - Objects::iterator oi; - - out << "/**\n"; - out << " * Module initialization functions for Python module \"" << def->module_name << "\"\n"; - out << " */\n"; - - out << "#if PY_MAJOR_VERSION >= 3\n" - << "static struct PyModuleDef python_native_module = {\n" - << " PyModuleDef_HEAD_INIT,\n" - << " \"" << def->module_name << "\",\n" - << " nullptr,\n" - << " -1,\n" - << " nullptr,\n" - << " nullptr, nullptr, nullptr, nullptr\n" - << "};\n" - << "\n" - << "extern \"C\" EXPORT_CLASS PyObject *PyInit_" << def->module_name << "();\n" - << "\n" - << "PyObject *PyInit_" << def->module_name << "() {\n" - << " LibraryDef *refs[] = {&" << def->library_name << "_moddef, nullptr};\n" - << " PyObject *module = Dtool_PyModuleInitHelper(refs, &python_native_module);\n" - << " Dtool_" << def->library_name << "_BuildInstants(module);\n" - << " return module;\n" - << "}\n" - << "\n" - << "#else // Python 2 case\n" - << "\n" - << "extern \"C\" EXPORT_CLASS void init" << def->module_name << "();\n" - << "\n" - << "void init" << def->module_name << "() {\n" - << " LibraryDef *refs[] = {&" << def->library_name << "_moddef, nullptr};\n" - << " PyObject *module = Dtool_PyModuleInitHelper(refs, \"" << def->module_name << "\");\n" - << " Dtool_" << def->library_name << "_BuildInstants(module);\n" - << "}\n" - << "\n" - << "#endif\n" - << "\n"; -} -/** - - */ -void InterfaceMakerPythonNative:: -write_module_class(ostream &out, Object *obj) { - bool has_local_repr = false; - bool has_local_str = false; - bool has_local_richcompare = false; - bool has_local_getbuffer = false; - - { - int num_nested = obj->_itype.number_of_nested_types(); - for (int ni = 0; ni < num_nested; ni++) { - TypeIndex nested_index = obj->_itype.get_nested_type(ni); - if (_objects.count(nested_index) == 0) { - // Illegal type. - continue; - } - - Object *nested_obj = _objects[nested_index]; - assert(nested_obj != nullptr); - - if (nested_obj->_itype.is_class() || nested_obj->_itype.is_struct()) { - write_module_class(out, nested_obj); - } - } - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - std::string ClassName = make_safe_name(obj->_itype.get_scoped_name()); - std::string cClassName = obj->_itype.get_true_name(); - std::string export_class_name = classNameFromCppName(obj->_itype.get_name(), false); - - CPPStructType *struct_type = obj->_itype._cpptype->as_struct_type(); - bool py_subclassable = is_python_subclassable(struct_type); - - out << "/**\n"; - out << " * Python method tables for " << ClassName << " (" << export_class_name << ")\n" ; - out << " */\n"; - out << "static PyMethodDef Dtool_Methods_" << ClassName << "[] = {\n"; - - SlottedFunctions slots; - // function Table - bool got_copy = false; - bool got_deepcopy = false; - - for (Function *func : obj->_methods) { - if (func->_name == "__copy__") { - got_copy = true; - } else if (func->_name == "__deepcopy__") { - got_deepcopy = true; - } - - string name1 = methodNameFromCppName(func, export_class_name, false); - string name2 = methodNameFromCppName(func, export_class_name, true); - - string flags; - string fptr = "&" + func->_name; - switch (func->_args_type) { - case AT_keyword_args: - flags = "METH_VARARGS | METH_KEYWORDS"; - fptr = "(PyCFunction) " + fptr; - break; - - case AT_varargs: - flags = "METH_VARARGS"; - break; - - case AT_single_arg: - flags = "METH_O"; - break; - - default: - flags = "METH_NOARGS"; - break; - } - - if (!func->_has_this) { - if (func->_flags & FunctionRemap::F_explicit_cls) { - flags += " | METH_CLASS"; - } else { - flags += " | METH_STATIC"; - } - - // Skip adding this entry if we also have a property with the same name. - // In that case, we will use a Dtool_StaticProperty to disambiguate - // access to this method. See GitHub issue #444. - for (const Property *property : obj->_properties) { - if (property->_has_this && - property->_ielement.get_name() == func->_ifunc.get_name()) { - continue; - } - } - } - - bool has_nonslotted = false; - - for (FunctionRemap *remap : func->_remaps) { - if (!is_remap_legal(remap)) { - continue; - } - - SlottedFunctionDef slotted_def; - - if (get_slotted_function_def(obj, func, remap, slotted_def)) { - const string &key = slotted_def._answer_location; - if (slotted_def._wrapper_type == WT_none) { - slotted_def._wrapper_name = func->_name; - } else { - slotted_def._wrapper_name = func->_name + "_" + key; - } - if (slots.count(key)) { - slots[key]._remaps.insert(remap); - } else { - slots[key] = slotted_def; - slots[key]._remaps.insert(remap); - } - if (slotted_def._keep_method) { - has_nonslotted = true; - } - - // Python 3 doesn't support nb_divide. It has nb_true_divide and also - // nb_floor_divide, but they have different semantics than in C++. - // Ugh. Make special slots to store the nb_divide members that don't - // take an int. We'll use this to build up nb_true_divide, in the - // absence of a custom __truediv__, so that we can still properly divide - // float vector types. - if ((key == "nb_divide" || key == "nb_inplace_divide") && - (remap->_flags & FunctionRemap::F_divide_integer) == 0) { - string true_key; - if (key == "nb_inplace_divide") { - true_key = "nb_inplace_true_divide"; - } else { - true_key = "nb_true_divide"; - } - if (slots.count(true_key) == 0) { - SlottedFunctionDef def; - def._answer_location = true_key; - def._wrapper_type = slotted_def._wrapper_type; - def._wrapper_name = func->_name + "_" + true_key; - slots[true_key] = def; - } - slots[true_key]._remaps.insert(remap); - } - } else { - has_nonslotted = true; - } - } - - if (has_nonslotted) { - // This is a bit of a hack, as these methods should probably be going - // through the slotted function system. But it's kind of pointless to - // write these out, and a waste of space. - string fname = func->_ifunc.get_name(); - if (fname == "operator <" || - fname == "operator <=" || - fname == "operator ==" || - fname == "operator !=" || - fname == "operator >" || - fname == "operator >=" || - fname == "operator <=>") { - continue; - } - - // This method has non-slotted remaps, so write it out into the function - // table. - out << " {\"" << name1 << "\", " << fptr - << ", " << flags << ", (const char *)" << func->_name << "_comment},\n"; - if (name1 != name2) { - out << " {\"" << name2 << "\", " << fptr - << ", " << flags << ", (const char *)" << func->_name << "_comment},\n"; - } - } - } - - if (obj->_protocol_types & Object::PT_make_copy) { - if (!got_copy) { - out << " {\"__copy__\", ©_from_make_copy, METH_NOARGS, nullptr},\n"; - got_copy = true; - } - } else if (obj->_protocol_types & Object::PT_copy_constructor) { - if (!got_copy) { - out << " {\"__copy__\", ©_from_copy_constructor, METH_NOARGS, nullptr},\n"; - got_copy = true; - } - } - - if (got_copy && !got_deepcopy) { - out << " {\"__deepcopy__\", &map_deepcopy_to_copy, METH_VARARGS, nullptr},\n"; - } - - for (MakeSeq *make_seq : obj->_make_seqs) { - if (!is_function_legal(make_seq->_length_getter) || - !is_function_legal(make_seq->_element_getter)) { - continue; - } - - string seq_name = make_seq->_imake_seq.get_name(); - - string flags = "METH_NOARGS"; - if (!make_seq->_length_getter->_has_this && - !make_seq->_element_getter->_has_this) { - flags += " | METH_STATIC"; - } - - string name1 = methodNameFromCppName(seq_name, export_class_name, false); - string name2 = methodNameFromCppName(seq_name, export_class_name, true); - out << " {\"" << name1 - << "\", (PyCFunction) &" << make_seq->_name << ", " << flags << ", nullptr},\n"; - if (name1 != name2) { - out << " { \"" << name2 - << "\", (PyCFunction) &" << make_seq->_name << ", " << flags << ", nullptr},\n"; - } - } - - out << " {nullptr, nullptr, 0, nullptr}\n" - << "};\n\n"; - - int num_derivations = obj->_itype.number_of_derivations(); - int di; - for (di = 0; di < num_derivations; di++) { - TypeIndex d_type_Index = obj->_itype.get_derivation(di); - if (!interrogate_type_is_unpublished(d_type_Index)) { - const InterrogateType &d_itype = idb->get_type(d_type_Index); - if (is_cpp_type_legal(d_itype._cpptype)) { - if (!isExportThisRun(d_itype._cpptype)) { - _external_imports.insert(TypeManager::resolve_type(d_itype._cpptype)); - - // out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << - // make_safe_name(d_itype.get_scoped_name().c_str()) << ";\n"; - } - } - } - } - - std::vector bases; - for (di = 0; di < num_derivations; di++) { - TypeIndex d_type_Index = obj->_itype.get_derivation(di); - if (!interrogate_type_is_unpublished(d_type_Index)) { - const InterrogateType &d_itype = idb->get_type(d_type_Index); - if (is_cpp_type_legal(d_itype._cpptype)) { - bases.push_back(d_itype._cpptype); - } - } - } - - { - SlottedFunctions::iterator rfi; - for (rfi = slots.begin(); rfi != slots.end(); rfi++) { - const SlottedFunctionDef &def = rfi->second; - - // This is just for reporting. There might be remaps from multiple - // functions with different names mapped to the same slot. - string fname; - if (def._remaps.size() > 0) { - const FunctionRemap *first_remap = *def._remaps.begin(); - fname = first_remap->_cppfunc->get_simple_name(); - } - - if (def._min_version > 0) { - out << "#if PY_VERSION_HEX >= 0x" << hex << def._min_version << dec << "\n"; - } - - switch (rfi->second._wrapper_type) { - case WT_no_params: - case WT_iter_next: - // PyObject *func(PyObject *self) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static PyObject *" << def._wrapper_name << "(PyObject *self) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return nullptr;\n"; - out << " }\n\n"; - - int return_flags = RF_pyobject | RF_err_null; - if (rfi->second._wrapper_type == WT_iter_next) { - // If the function returns NULL, we should return NULL to indicate - // a StopIteration, rather than returning None. - return_flags |= RF_preserve_null; - } - string expected_params; - if (!write_function_forset(out, def._remaps, 0, 0, expected_params, 2, true, true, - AT_no_args, return_flags, false)) { - error_bad_args_return(out, 2, return_flags, expected_params); - } - out << "}\n\n"; - } - break; - - case WT_one_param: - // PyObject *func(PyObject *self, PyObject *one) - { - bool all_nonconst = true; - for (FunctionRemap *remap : def._remaps) { - if (remap->_const_method) { - all_nonconst = false; - } - } - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - if (all_nonconst) { - out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" - << ClassName << ", (void **)&local_this, \"" << ClassName - << "." << methodNameFromCppName(fname, "", false) << "\")) {\n"; - out << " return nullptr;\n"; - } else { - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return nullptr;\n"; - } - out << " }\n"; - - string expected_params; - write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true, - AT_single_arg, RF_err_null | RF_pyobject, false, !all_nonconst); - - error_bad_args_return(out, 2, RF_pyobject | RF_err_null, expected_params); - out << "}\n\n"; - } - break; - - case WT_binary_operator: - case WT_inplace_binary_operator: - // PyObject *func(PyObject *self, PyObject *one) - { - int return_flags = RF_err_null; - if (rfi->second._wrapper_type == WT_inplace_binary_operator) { - return_flags |= RF_self; - } else { - return_flags |= RF_pyobject; - } - bool forward_all_nonconst = true; - bool reverse_all_nonconst = true; - set forward_remaps; - set reverse_remaps; - for (FunctionRemap *remap : def._remaps) { - std::string fname = remap->_cppfunc->get_simple_name(); - if (fname.compare(0, 3, "__r") == 0 && fname != "__rshift__") { - reverse_remaps.insert(remap); - if (remap->_const_method) { - reverse_all_nonconst = false; - } - } else { - forward_remaps.insert(remap); - if (remap->_const_method) { - forward_all_nonconst = false; - } - } - } - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - // WT_binary_operator means we must return NotImplemented, instead - // of raising an exception, if the this pointer doesn't match. - // This is for things like __sub__, which Python likes to call on - // the wrong-type objects. - if (!forward_remaps.empty()) { - out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n"; - if (forward_all_nonconst) { - out << " if (local_this != nullptr && !DtoolInstance_IS_CONST(self)) {\n"; - } else { - out << " if (local_this != nullptr) {\n"; - } - string expected_params; - write_function_forset(out, forward_remaps, 1, 1, expected_params, 4, true, true, - AT_single_arg, return_flags, false, !forward_all_nonconst); - out << " }\n"; - } - - if (!reverse_remaps.empty()) { - out << " std::swap(self, arg);\n"; - out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n"; - if (reverse_all_nonconst) { - out << " if (local_this != nullptr && !DtoolInstance_IS_CONST(self)) {\n"; - } else { - out << " if (local_this != nullptr) {\n"; - } - string expected_params; - write_function_forset(out, reverse_remaps, 1, 1, expected_params, 4, true, true, - AT_single_arg, return_flags, false, !reverse_all_nonconst); - out << " }\n"; - } - - out << " return Py_NewRef(Py_NotImplemented);\n"; - out << "}\n\n"; - } - break; - - case WT_setattr: - // int func(PyObject *self, PyObject *one, PyObject *two = NULL) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static int " << def._wrapper_name << "(PyObject *self, PyObject *arg, PyObject *arg2) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - - set setattr_remaps; - set delattr_remaps; - - // This function handles both delattr and setattr. Fish out the - // remaps for both types. - for (FunctionRemap *remap : def._remaps) { - if (remap->_cppfunc->get_simple_name() == "__delattr__" && remap->_parameters.size() == 2) { - delattr_remaps.insert(remap); - - } else if (remap->_cppfunc->get_simple_name() == "__setattr__" && remap->_parameters.size() == 3) { - setattr_remaps.insert(remap); - } - } - - out << " // Determine whether to call __setattr__ or __delattr__.\n"; - out << " if (arg2 != nullptr) { // __setattr__\n"; - - if (!setattr_remaps.empty()) { - out << " PyObject *args = PyTuple_Pack(2, arg, arg2);\n"; - string expected_params; - if (!write_function_forset(out, setattr_remaps, 2, 2, expected_params, 4, - true, true, AT_varargs, RF_int | RF_decref_args, true)) { - error_bad_args_return(out, 4, RF_int | RF_decref_args, expected_params); - } - } else { - out << " PyErr_Format(PyExc_TypeError,\n"; - out << " \"can't set attributes of built-in/extension type '%s'\",\n"; - out << " Py_TYPE(self)->tp_name);\n"; - out << " return -1;\n\n"; - } - - out << " } else { // __delattr__\n"; - - if (!delattr_remaps.empty()) { - string expected_params; - if (!write_function_forset(out, delattr_remaps, 1, 1, expected_params, 4, - true, true, AT_single_arg, RF_int, true)) { - error_bad_args_return(out, 4, RF_int | RF_decref_args, expected_params); - } - } else { - out << " PyErr_Format(PyExc_TypeError,\n"; - out << " \"can't delete attributes of built-in/extension type '%s'\",\n"; - out << " Py_TYPE(self)->tp_name);\n"; - out << " return -1;\n"; - } - out << " }\n"; - - out << "}\n\n"; - } - break; - - case WT_getattr: - // PyObject *func(PyObject *self, PyObject *one) Specifically to - // implement __getattr__. First calls PyObject_GenericGetAttr(), and - // only calls the wrapper if it returns NULL. If one wants to override - // this completely, one should define __getattribute__ instead. - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n"; - out << " PyObject *res = PyObject_GenericGetAttr(self, arg);\n"; - out << " if (res != nullptr) {\n"; - out << " return res;\n"; - out << " }\n"; - out << " if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {\n"; - out << " return nullptr;\n"; - out << " }\n"; - out << " PyErr_Clear();\n\n"; - - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return nullptr;\n"; - out << " }\n\n"; - - string expected_params; - if (!write_function_forset(out, def._remaps, 1, 1, expected_params, 2, - true, true, AT_single_arg, - RF_pyobject | RF_err_null, true)) { - // out << " PyErr_Clear();\n"; - out << " return nullptr;\n"; - } - out << "}\n\n"; - } - break; - - case WT_sequence_getitem: - // PyObject *func(PyObject *self, Py_ssize_t index) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static PyObject *" << def._wrapper_name << "(PyObject *self, Py_ssize_t index) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return nullptr;\n"; - out << " }\n\n"; - - // This is a getitem or setitem of a sequence type. This means we - // *need* to raise IndexError if we're out of bounds. We have to - // assume the bounds are 0 .. this->size() (this is the same - // assumption that Python makes). - out << " if (index < 0 || index >= (Py_ssize_t) local_this->size()) {\n"; - out << "#ifdef NDEBUG\n"; - out << " PyErr_SetString(PyExc_IndexError, \"index out of range\");\n"; - out << "#else\n"; - out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << " index out of range\");\n"; - out << "#endif\n"; - out << " return nullptr;\n"; - out << " }\n"; - - string expected_params; - if (!write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true, - AT_no_args, RF_pyobject | RF_err_null, false, true, "index")) { - error_bad_args_return(out, 2, RF_pyobject | RF_err_null, expected_params); - } - out << "}\n\n"; - } - break; - - case WT_sequence_setitem: - // int_t func(PyObject *self, Py_ssize_t index, PyObject *value) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static int " << def._wrapper_name << "(PyObject *self, Py_ssize_t index, PyObject *arg) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - - out << " if (index < 0 || index >= (Py_ssize_t) local_this->size()) {\n"; - out << "#ifdef NDEBUG\n"; - out << " PyErr_SetString(PyExc_IndexError, \"index out of range\");\n"; - out << "#else\n"; - out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << " index out of range\");\n"; - out << "#endif\n"; - out << " return -1;\n"; - out << " }\n"; - - set setitem_remaps; - set delitem_remaps; - - // This function handles both delitem and setitem. Fish out the - // remaps for either one. - for (FunctionRemap *remap : def._remaps) { - if (remap->_flags & FunctionRemap::F_setitem_int) { - setitem_remaps.insert(remap); - - } else if (remap->_flags & FunctionRemap::F_delitem_int) { - delitem_remaps.insert(remap); - } - } - - string expected_params; - bool always_returns = true; - out << " if (arg != nullptr) { // __setitem__\n"; - if (!write_function_forset(out, setitem_remaps, 2, 2, expected_params, 4, - true, true, AT_single_arg, RF_int, false, true, "index")) { - always_returns = false; - } - out << " } else { // __delitem__\n"; - if (!write_function_forset(out, delitem_remaps, 1, 1, expected_params, 4, - true, true, AT_single_arg, RF_int, false, true, "index")) { - always_returns = false; - } - out << " }\n\n"; - - if (!always_returns) { - error_bad_args_return(out, 2, RF_int, expected_params); - } - out << "}\n\n"; - } - break; - - case WT_sequence_size: - // Py_ssize_t func(PyObject *self) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static Py_ssize_t " << def._wrapper_name << "(PyObject *self) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - - // This is a cheap cheat around all of the overhead of calling the - // wrapper function. - out << " return (Py_ssize_t) local_this->" << fname << "();\n"; - out << "}\n\n"; - } - break; - - case WT_mapping_setitem: - // int func(PyObject *self, PyObject *one, PyObject *two) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static int " << def._wrapper_name << "(PyObject *self, PyObject *arg, PyObject *arg2) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - - set setitem_remaps; - set delitem_remaps; - - // This function handles both delitem and setitem. Fish out the - // remaps for either one. - for (FunctionRemap *remap : def._remaps) { - if (remap->_flags & FunctionRemap::F_setitem) { - setitem_remaps.insert(remap); - - } else if (remap->_flags & FunctionRemap::F_delitem) { - delitem_remaps.insert(remap); - } - } - - string expected_params; - bool always_returns = true; - out << " if (arg2 != nullptr) { // __setitem__\n"; - if (setitem_remaps.empty()) { - always_returns = false; - } else { - out << " PyObject *args = PyTuple_Pack(2, arg, arg2);\n"; - if (!write_function_forset(out, setitem_remaps, 2, 2, expected_params, 4, - true, true, AT_varargs, RF_int | RF_decref_args, false)) { - always_returns = false; - } - out << " Py_DECREF(args);\n"; - } - out << " } else { // __delitem__\n"; - if (!write_function_forset(out, delitem_remaps, 1, 1, expected_params, 4, - true, true, AT_single_arg, RF_int, false)) { - always_returns = false; - } - out << " }\n\n"; - - if (!always_returns) { - error_bad_args_return(out, 2, RF_int, expected_params); - } - out << "}\n\n"; - } - break; - - case WT_inquiry: - // int func(PyObject *self) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static int " << def._wrapper_name << "(PyObject *self) {\n"; - - // Find the remap. There should be only one. - FunctionRemap *remap = *def._remaps.begin(); - const char *container = ""; - - if (remap->_has_this) { - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - container = "local_this"; - } - - vector_string params; - out << " return (int) " << remap->call_function(out, 4, false, container, params) << ";\n"; - out << "}\n\n"; - } - break; - - case WT_getbuffer: - // int __getbuffer__(PyObject *self, Py_buffer *buffer, int flags) We - // map this directly, and assume that the arguments match. The whole - // point of this is to be fast, and we don't want to negate that by - // first wrapping and then unwrapping the arguments again. We also - // want to guarantee const correctness, since that will determine - // whether a read-only buffer is given. - { - has_local_getbuffer = true; - - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static int " << def._wrapper_name << "(PyObject *self, Py_buffer *buffer, int flags) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - - vector_string params_const(1); - vector_string params_nonconst(1); - FunctionRemap *remap_const = nullptr; - FunctionRemap *remap_nonconst = nullptr; - - // Iterate through the remaps to find the one that matches our - // parameters. - for (FunctionRemap *remap : def._remaps) { - if (remap->_const_method) { - if ((remap->_flags & FunctionRemap::F_explicit_self) == 0) { - params_const.push_back("self"); - } - remap_const = remap; - } else { - if ((remap->_flags & FunctionRemap::F_explicit_self) == 0) { - params_nonconst.push_back("self"); - } - remap_nonconst = remap; - } - } - params_const.push_back("buffer"); - params_const.push_back("flags"); - params_nonconst.push_back("buffer"); - params_nonconst.push_back("flags"); - - // We have to distinguish properly between const and nonconst, - // because the function may depend on it to decide whether to - // provide a writable buffer or a readonly buffer. - const string const_this = "(const " + cClassName + " *)local_this"; - if (remap_const != nullptr && remap_nonconst != nullptr) { - out << " if (!DtoolInstance_IS_CONST(self)) {\n"; - out << " return " << remap_nonconst->call_function(out, 4, false, "local_this", params_nonconst) << ";\n"; - out << " } else {\n"; - out << " return " << remap_const->call_function(out, 4, false, const_this, params_const) << ";\n"; - out << " }\n"; - } else if (remap_nonconst != nullptr) { - out << " if (!DtoolInstance_IS_CONST(self)) {\n"; - out << " return " << remap_nonconst->call_function(out, 4, false, "local_this", params_nonconst) << ";\n"; - out << " } else {\n"; - out << " Dtool_Raise_TypeError(\"Cannot call " << ClassName << ".__getbuffer__() on a const object.\");\n"; - out << " return -1;\n"; - out << " }\n"; - } else if (remap_const != nullptr) { - out << " return " << remap_const->call_function(out, 4, false, const_this, params_const) << ";\n"; - } else { - nout << ClassName << "::__getbuffer__ does not match the required signature.\n"; - out << " return -1;\n"; - } - - out << "}\n\n"; - } - break; - - case WT_releasebuffer: - // void __releasebuffer__(PyObject *self, Py_buffer *buffer) Same - // story as __getbuffer__ above. - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static void " << def._wrapper_name << "(PyObject *self, Py_buffer *buffer) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return;\n"; - out << " }\n\n"; - - vector_string params_const(1); - vector_string params_nonconst(1); - FunctionRemap *remap_const = nullptr; - FunctionRemap *remap_nonconst = nullptr; - - // Iterate through the remaps to find the one that matches our - // parameters. - for (FunctionRemap *remap : def._remaps) { - if (remap->_const_method) { - if ((remap->_flags & FunctionRemap::F_explicit_self) == 0) { - params_const.push_back("self"); - } - remap_const = remap; - } else { - if ((remap->_flags & FunctionRemap::F_explicit_self) == 0) { - params_nonconst.push_back("self"); - } - remap_nonconst = remap; - } - } - params_const.push_back("buffer"); - params_nonconst.push_back("buffer"); - - string return_expr; - const string const_this = "(const " + cClassName + " *)local_this"; - if (remap_const != nullptr && remap_nonconst != nullptr) { - out << " if (!DtoolInstance_IS_CONST(self)) {\n"; - return_expr = remap_nonconst->call_function(out, 4, false, "local_this", params_nonconst); - if (!return_expr.empty()) { - out << " " << return_expr << ";\n"; - } - out << " } else {\n"; - return_expr = remap_const->call_function(out, 4, false, const_this, params_const); - - if (!return_expr.empty()) { - out << " " << return_expr << ";\n"; - } - out << " }\n"; - - } else if (remap_nonconst != nullptr) { - // Doesn't matter if there's no const version. We *have* to call - // it or else we could leak memory. - return_expr = remap_nonconst->call_function(out, 2, false, "local_this", params_nonconst); - if (!return_expr.empty()) { - out << " " << return_expr << ";\n"; - } - - } else if (remap_const != nullptr) { - return_expr = remap_const->call_function(out, 2, false, const_this, params_const); - if (!return_expr.empty()) { - out << " " << return_expr << ";\n"; - } - - } else { - nout << ClassName << "::__releasebuffer__ does not match the required signature.\n"; - out << " return;\n"; - } - - out << "}\n\n"; - } - break; - - case WT_ternary_operator: - case WT_inplace_ternary_operator: - // PyObject *func(PyObject *self, PyObject *one, PyObject *two) - { - int return_flags = RF_err_null; - if (rfi->second._wrapper_type == WT_inplace_ternary_operator) { - return_flags |= RF_self; - } else { - return_flags |= RF_pyobject; - } - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static PyObject *" << def._wrapper_name << "(PyObject *self, PyObject *arg, PyObject *arg2) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n"; - out << " if (local_this == nullptr) {\n"; - // WT_ternary_operator means we must return NotImplemented, instead - // of raising an exception, if the this pointer doesn't match. This - // is for things like __pow__, which Python likes to call on the - // wrong-type objects. - out << " return Py_NewRef(Py_NotImplemented);\n"; - out << " }\n"; - - set one_param_remaps; - set two_param_remaps; - - for (FunctionRemap *remap : def._remaps) { - if (remap->_parameters.size() == 2) { - one_param_remaps.insert(remap); - - } else if (remap->_parameters.size() == 3) { - two_param_remaps.insert(remap); - } - } - - string expected_params; - bool always_returns = true; - out << " if (arg2 != nullptr && arg2 != Py_None) {\n"; - if (two_param_remaps.empty()) { - always_returns = false; - } else { - out << " PyObject *args = PyTuple_Pack(2, arg, arg2);\n"; - if (!write_function_forset(out, two_param_remaps, 2, 2, expected_params, 4, - true, true, AT_varargs, return_flags | RF_decref_args, true)) { - always_returns = false; - } - out << " Py_DECREF(args);\n"; - } - out << " } else {\n"; - if (!write_function_forset(out, one_param_remaps, 1, 1, expected_params, 4, - true, true, AT_single_arg, return_flags, true)) { - always_returns = false; - } - out << " }\n\n"; - - if (!always_returns) { - error_bad_args_return(out, 2, return_flags, expected_params); - } - out << "}\n\n"; - } - break; - - case WT_traverse: - // int __traverse__(PyObject *self, visitproc visit, void *arg) This - // is a low-level function. Overloads are not supported. - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static int " << def._wrapper_name << "(PyObject *self, visitproc visit, void *arg) {\n"; - - // Find the remap. There should be only one. - FunctionRemap *remap = *def._remaps.begin(); - - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n"; - out << " if (local_this == nullptr) {\n"; - out << " return 0;\n"; - out << " }\n\n"; - - // Only participate in cycle detection if there are no C++ - // references to this object. - out << " if (local_this->get_ref_count() != (int)((Dtool_PyInstDef *)self)->_memory_rules) {\n"; - out << " return 0;\n"; - out << " }\n\n"; - - if (py_subclassable) { - // Python-subclassable types store a reference to their Python - // wrapper. - if (struct_type->is_final()) { - out << " if (Py_TYPE(self) != &Dtool_" << ClassName << "._PyType) {\n"; - } else { - out << " if (Py_TYPE(self) != &Dtool_" << ClassName << "._PyType && DtoolInstance_TYPE(self) == &Dtool_" << ClassName << ") {\n"; - } - out << " Py_VISIT(self);\n"; - out << " }\n"; - } - - vector_string params((int)remap->_has_this); - params.push_back("visit"); - params.push_back("arg"); - - out << " return " << remap->call_function(out, 2, false, "local_this", params) << ";\n"; - out << "}\n\n"; - } - break; - - case WT_compare: - // int func(PyObject *self, Py_ssize_t index) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static int " << def._wrapper_name << "(PyObject *self, PyObject *arg) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - - string expected_params; - if (!write_function_forset(out, def._remaps, 1, 1, expected_params, 2, true, true, - AT_single_arg, RF_compare, false, true)) { - error_bad_args_return(out, 2, RF_int, expected_params); - } - out << "}\n\n"; - } - break; - - case WT_hash: - // Py_hash_t func(PyObject *self) - { - out << "//////////////////\n"; - out << "// A wrapper function to satisfy Python's internal calling conventions.\n"; - out << "// " << ClassName << " slot " << rfi->second._answer_location << " -> " << fname << "\n"; - out << "//////////////////\n"; - out << "static Py_hash_t " << def._wrapper_name << "(PyObject *self) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - - FunctionRemap *remap = *def._remaps.begin(); - vector_string params; - out << " return (Py_hash_t) " << remap->call_function(out, 4, false, "local_this", params) << ";\n"; - out << "}\n\n"; - } - break; - - case WT_new: - { - string fname = "static PyObject *" + def._wrapper_name + "(PyTypeObject *cls, PyObject *args, PyObject *kwds)\n"; - - std::vector remaps; - remaps.insert(remaps.end(), def._remaps.begin(), def._remaps.end()); - string expected_params; - write_function_for_name(out, obj, remaps, fname, expected_params, true, AT_keyword_args, RF_pyobject | RF_err_null); - } - break; - - case WT_none: - // Nothing special about the wrapper function: just write it normally. - string fname = "static PyObject *" + def._wrapper_name + "(PyObject *self, PyObject *args, PyObject *kwds)\n"; - - std::vector remaps; - remaps.insert(remaps.end(), def._remaps.begin(), def._remaps.end()); - string expected_params; - write_function_for_name(out, obj, remaps, fname, expected_params, true, AT_keyword_args, RF_pyobject | RF_err_null); - break; - } - - if (def._min_version > 0) { - out << "#endif // PY_VERSION_HEX >= 0x" << hex << def._min_version << dec << "\n"; - } - } - - int need_repr = 0; - if (slots.count("tp_repr") == 0) { - need_repr = NeedsAReprFunction(obj->_itype); - } - if (need_repr > 0) { - out << "//////////////////\n"; - out << "// A __repr__ function\n"; - out << "// " << ClassName << "\n"; - out << "//////////////////\n"; - out << "static PyObject *Dtool_Repr_" << ClassName << "(PyObject *self) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return nullptr;\n"; - out << " }\n\n"; - out << " std::ostringstream os;\n"; - if (need_repr == 3) { - out << " invoke_extension(local_this).python_repr(os, \"" - << classNameFromCppName(ClassName, false) << "\");\n"; - } else if (need_repr == 2) { - out << " local_this->output(os);\n"; - } else { - out << " local_this->python_repr(os, \"" - << classNameFromCppName(ClassName, false) << "\");\n"; - } - out << " std::string ss = os.str();\n"; - out << " return Dtool_WrapValue(ss);\n"; - out << "}\n\n"; - has_local_repr = true; - } - - int need_str = 0; - if (slots.count("tp_str") == 0) { - need_str = NeedsAStrFunction(obj->_itype); - } - if (need_str > 0) { - out << "//////////////////\n"; - out << "// A __str__ function\n"; - out << "// " << ClassName << "\n"; - out << "//////////////////\n"; - out << "static PyObject *Dtool_Str_" << ClassName << "(PyObject *self) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return nullptr;\n"; - out << " }\n\n"; - out << " std::ostringstream os;\n"; - if (need_str == 2) { - out << " local_this->write(os, 0);\n"; - } else { - out << " local_this->write(os);\n"; - } - out << " std::string ss = os.str();\n"; - out << " return Dtool_WrapValue(ss);\n"; - out << "}\n\n"; - has_local_str = true; - } - } - - if (NeedsARichCompareFunction(obj->_itype) || slots.count("tp_compare")) { - out << "//////////////////\n"; - out << "// A rich comparison function\n"; - out << "// " << ClassName << "\n"; - out << "//////////////////\n"; - out << "static PyObject *Dtool_RichCompare_" << ClassName << "(PyObject *self, PyObject *arg, int op) {\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return nullptr;\n"; - out << " }\n\n"; - - std::set threeway_remaps; - bool have_eq = false; - bool have_ne = false; - for (Function *func : obj->_methods) { - std::set remaps; - if (!func) { - continue; - } - // We only accept comparison operators that take one parameter (besides - // 'this'). - for (FunctionRemap *remap : func->_remaps) { - if (is_remap_legal(remap) && remap->_has_this && (remap->_args_type == AT_single_arg)) { - remaps.insert(remap); - } - } - const string &fname = func->_ifunc.get_name(); - const char *op_type; - if (fname == "operator <") { - op_type = "Py_LT"; - } else if (fname == "operator <=") { - op_type = "Py_LE"; - } else if (fname == "operator ==") { - op_type = "Py_EQ"; - have_eq = true; - } else if (fname == "operator !=") { - op_type = "Py_NE"; - have_ne = true; - } else if (fname == "operator >") { - op_type = "Py_GT"; - } else if (fname == "operator >=") { - op_type = "Py_GE"; - } else if (fname == "operator <=>") { - threeway_remaps = std::move(remaps); - continue; - } else { - continue; - } - if (!has_local_richcompare) { - out << " switch (op) {\n"; - has_local_richcompare = true; - } - out << " case " << op_type << ":\n"; - - out << " {\n"; - - string expected_params; - if (!write_function_forset(out, remaps, 1, 1, expected_params, 6, true, false, - AT_single_arg, RF_pyobject | RF_err_null, false)) { - out << " break;\n"; - } - out << " }\n"; - } - - if (has_local_richcompare) { - if (!threeway_remaps.empty()) { - out << " default:\n"; - out << " {\n"; - string expected_params; - write_function_forset(out, threeway_remaps, 1, 1, expected_params, 6, true, false, - AT_single_arg, RF_richcompare_zero | RF_err_null, false); - out << " }\n"; - } - else if (have_eq && !have_ne) { - // Generate a not-equal function from the equal function. - for (Function *func : obj->_methods) { - std::set remaps; - if (!func) { - continue; - } - const string &fname = func->_ifunc.get_name(); - if (fname != "operator ==") { - continue; - } - for (FunctionRemap *remap : func->_remaps) { - if (is_remap_legal(remap) && remap->_has_this && (remap->_args_type == AT_single_arg)) { - remaps.insert(remap); - } - } - out << " case Py_NE: // from Py_EQ\n"; - out << " {\n"; - - string expected_params; - if (!write_function_forset(out, remaps, 1, 1, expected_params, 6, true, false, - AT_single_arg, RF_pyobject | RF_invert_bool | RF_err_null, false)) { - out << " break;\n"; - } - out << " }\n"; - } - } - else if (!have_eq && !slots.count("tp_compare")) { - // Generate an equals function. - out << " case Py_EQ:\n"; - out << " return PyBool_FromLong(DtoolInstance_Check(arg) && DtoolInstance_VOID_PTR(self) == DtoolInstance_VOID_PTR(arg));\n"; - if (!have_ne) { - out << " case Py_NE:\n"; - out << " return PyBool_FromLong(!DtoolInstance_Check(arg) || DtoolInstance_VOID_PTR(self) != DtoolInstance_VOID_PTR(arg));\n"; - } - } - - // End of switch block - out << " }\n\n"; - out << " if (PyErr_Occurred()) {\n"; - out << " PyErr_Clear();\n"; - out << " }\n\n"; - } - else if (!threeway_remaps.empty()) { - string expected_params; - write_function_forset(out, threeway_remaps, 1, 1, expected_params, 2, true, false, - AT_single_arg, RF_richcompare_zero | RF_err_null, false); - } - - if (slots.count("tp_compare") && threeway_remaps.empty()) { - // A lot of Panda code depends on comparisons being done via the - // compare_to function, which is mapped to the tp_compare slot, which - // Python 3 no longer has. So, we'll write code to fall back to that if - // no matching comparison operator was found. - out << " // All is not lost; we still have the compare_to function to fall back onto.\n"; - out << " int cmpval = " << slots["tp_compare"]._wrapper_name << "(self, arg);\n"; - out << " if (cmpval == -1 && PyErr_Occurred()) {\n"; - out << " if (PyErr_ExceptionMatches(PyExc_TypeError)) {\n"; - out << " PyErr_Clear();\n"; - out << " } else {\n"; - out << " return nullptr;\n"; - out << " }\n"; - out << " }\n"; - out << " switch (op) {\n"; - out << " case Py_LT:\n"; - out << " return PyBool_FromLong(cmpval < 0);\n"; - out << " case Py_LE:\n"; - out << " return PyBool_FromLong(cmpval <= 0);\n"; - out << " case Py_EQ:\n"; - out << " return PyBool_FromLong(cmpval == 0);\n"; - out << " case Py_NE:\n"; - out << " return PyBool_FromLong(cmpval != 0);\n"; - out << " case Py_GT:\n"; - out << " return PyBool_FromLong(cmpval > 0);\n"; - out << " case Py_GE:\n"; - out << " return PyBool_FromLong(cmpval >= 0);\n"; - out << " }\n"; - has_local_richcompare = true; - } - - out << " return Py_NewRef(Py_NotImplemented);\n"; - out << "}\n\n"; - } - - bool has_gc = (slots.count("tp_traverse") || has_self_member(struct_type)); - bool has_local_traverse = false; - bool has_local_clear = false; - if (py_subclassable || has_gc) { - // Note that in the case of py_subclassable, the traverse function will - // only be called if the class is subclassed from Python, since we don't - // set Py_TPFLAGS_HAVE_GC, so we don't need to check whether it's a proxy. - if (!slots.count("tp_traverse")) { - has_local_traverse = true; - out << "static int Dtool_Traverse_" << ClassName << "(PyObject *self, visitproc visit, void *arg) {\n"; - out << " // If the only reference remaining is the one held by the Python wrapper,\n"; - out << " // report the circular reference to Python's GC, so that it can break it.\n"; - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - out << " return -1;\n"; - out << " }\n"; - out << " if (local_this->get_ref_count() == (int)((Dtool_PyInstDef *)self)->_memory_rules) {\n"; - if (py_subclassable) { - out << " Py_VISIT(self);\n"; - } - if (has_self_member(struct_type)) { - out << " Py_VISIT(local_this->__self__);\n"; - } - out << " }\n"; - out << " return 0;\n"; - out << "}\n"; - out << "\n"; - } - - if (!slots.count("tp_clear")) { - has_local_clear = true; - out << "static int Dtool_Clear_" << ClassName << "(PyObject *self) {\n"; - if (has_self_member(struct_type)) { - out << " Py_CLEAR(local_this->__self__);\n"; - } - if (py_subclassable) { - if (struct_type->is_final()) { - out << " if (Py_TYPE(self) != &Dtool_" << ClassName << "._PyType) {\n"; - } else { - out << " if (Py_TYPE(self) != &Dtool_" << ClassName << "._PyType && DtoolInstance_TYPE(self) == &Dtool_" << ClassName << ") {\n"; - } - out << " DtoolProxy_" << ClassName << " *proxy = (DtoolProxy_" << ClassName << " *)DtoolInstance_VOID_PTR(self);\n"; - out << " Py_CLEAR(proxy->DtoolProxy::_self);\n"; - out << " }\n"; - } - out << " return 0;\n"; - out << "}\n\n"; - } - } - - int num_getset = 0; - - if (obj->_properties.size() > 0) { - // Write out the array of properties, telling Python which getter and - // setter to call when they are assigned or queried in Python code. - for (Property *property : obj->_properties) { - const InterrogateElement &ielem = property->_ielement; - if (!property->_has_this || property->_getter_remaps.empty()) { - continue; - } - - // Actually, if we have a conflicting static method with the same name, - // we will need to use Dtool_StaticProperty instead. - for (const Function *func : obj->_methods) { - if (!func->_has_this && func->_ifunc.get_name() == ielem.get_name()) { - continue; - } - } - - if (num_getset == 0) { - out << "static PyGetSetDef Dtool_Properties_" << ClassName << "[] = {\n"; - } - - ++num_getset; - - string name1 = methodNameFromCppName(ielem.get_name(), "", false); - // string name2 = methodNameFromCppName(ielem.get_name(), "", true); - - string getter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter"; - string setter = "nullptr"; - if (!ielem.is_sequence() && !ielem.is_mapping() && !property->_setter_remaps.empty()) { - setter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter"; - } - - out << " {(char *)\"" << name1 << "\", " << getter << ", " << setter; - - if (ielem.has_comment()) { - out << ", (char *)\n"; - output_quoted(out, 4, ielem.get_comment()); - out << ",\n "; - } else { - out << ", nullptr, "; - } - - // Extra void* argument; we don't make use of it. - out << "nullptr},\n"; - - /*if (name1 != name2 && name1 != "__dict__") { - // Add alternative spelling. - out << " {(char *)\"" << name2 << "\", " << getter << ", " << setter - << ", (char *)\n" - << " \"Alias of " << name1 << ", for consistency with old naming conventions.\",\n" - << " NULL},\n"; - }*/ - } - - if (num_getset != 0) { - out << " {nullptr},\n"; - out << "};\n\n"; - } - } - - // These fields are inherited together. We should either write all of them - // or none of them so that they are inherited from DTOOL_SUPER_BASE. - bool has_hash_compare = (slots.count("tp_hash") != 0 || - slots.count("tp_compare") != 0 || - has_local_richcompare); - - bool has_parent_class = (obj->_itype.number_of_derivations() != 0); - - // Output the type slot tables. - out << "static PyNumberMethods Dtool_NumberMethods_" << ClassName << " = {\n"; - write_function_slot(out, 2, slots, "nb_add"); - write_function_slot(out, 2, slots, "nb_subtract"); - write_function_slot(out, 2, slots, "nb_multiply"); - out << "#if PY_MAJOR_VERSION < 3\n"; - // Note: nb_divide does not exist in Python 3. We will probably need some - // smart mechanism for dispatching to either floor_divide or true_divide. - write_function_slot(out, 2, slots, "nb_divide"); - out << "#endif\n"; - write_function_slot(out, 2, slots, "nb_remainder"); - write_function_slot(out, 2, slots, "nb_divmod"); - write_function_slot(out, 2, slots, "nb_power"); - write_function_slot(out, 2, slots, "nb_negative"); - write_function_slot(out, 2, slots, "nb_positive"); - write_function_slot(out, 2, slots, "nb_absolute"); - write_function_slot(out, 2, slots, "nb_bool"); - write_function_slot(out, 2, slots, "nb_invert"); - write_function_slot(out, 2, slots, "nb_lshift"); - write_function_slot(out, 2, slots, "nb_rshift"); - write_function_slot(out, 2, slots, "nb_and"); - write_function_slot(out, 2, slots, "nb_xor"); - write_function_slot(out, 2, slots, "nb_or"); - out << "#if PY_MAJOR_VERSION < 3\n"; - write_function_slot(out, 2, slots, "nb_coerce"); - out << "#endif\n"; - write_function_slot(out, 2, slots, "nb_int"); - out << " nullptr, // nb_long\n"; // removed in Python 3 - write_function_slot(out, 2, slots, "nb_float"); - out << "#if PY_MAJOR_VERSION < 3\n"; - write_function_slot(out, 2, slots, "nb_oct"); - write_function_slot(out, 2, slots, "nb_hex"); - out << "#endif\n"; - - write_function_slot(out, 2, slots, "nb_inplace_add"); - write_function_slot(out, 2, slots, "nb_inplace_subtract"); - write_function_slot(out, 2, slots, "nb_inplace_multiply"); - out << "#if PY_MAJOR_VERSION < 3\n"; - write_function_slot(out, 2, slots, "nb_inplace_divide"); - out << "#endif\n"; - write_function_slot(out, 2, slots, "nb_inplace_remainder"); - write_function_slot(out, 2, slots, "nb_inplace_power"); - write_function_slot(out, 2, slots, "nb_inplace_lshift"); - write_function_slot(out, 2, slots, "nb_inplace_rshift"); - write_function_slot(out, 2, slots, "nb_inplace_and"); - write_function_slot(out, 2, slots, "nb_inplace_xor"); - write_function_slot(out, 2, slots, "nb_inplace_or"); - - write_function_slot(out, 2, slots, "nb_floor_divide"); - write_function_slot(out, 2, slots, "nb_true_divide"); - write_function_slot(out, 2, slots, "nb_inplace_floor_divide"); - write_function_slot(out, 2, slots, "nb_inplace_true_divide"); - - out << "#if PY_VERSION_HEX >= 0x02050000\n"; - write_function_slot(out, 2, slots, "nb_index"); - out << "#endif\n"; - - out << "#if PY_VERSION_HEX >= 0x03050000\n"; - write_function_slot(out, 2, slots, "nb_matrix_multiply"); - write_function_slot(out, 2, slots, "nb_inplace_matrix_multiply"); - out << "#endif\n"; - - out << "};\n\n"; - - // NB: it's tempting not to write this table when a class doesn't have them. - // But then Python won't inherit them from base classes either! So we - // always write this table for now even if it will be full of 0's, unless - // this type has no base classes at all. - if (has_parent_class || (obj->_protocol_types & Object::PT_sequence) != 0) { - out << "static PySequenceMethods Dtool_SequenceMethods_" << ClassName << " = {\n"; - write_function_slot(out, 2, slots, "sq_length"); - write_function_slot(out, 2, slots, "sq_concat"); - write_function_slot(out, 2, slots, "sq_repeat"); - write_function_slot(out, 2, slots, "sq_item"); - out << " nullptr, // sq_slice\n"; // removed in Python 3 - write_function_slot(out, 2, slots, "sq_ass_item"); - out << " nullptr, // sq_ass_slice\n"; // removed in Python 3 - write_function_slot(out, 2, slots, "sq_contains"); - - write_function_slot(out, 2, slots, "sq_inplace_concat"); - write_function_slot(out, 2, slots, "sq_inplace_repeat"); - out << "};\n\n"; - } - - // Same note applies as for the SequenceMethods. - if (has_parent_class || (obj->_protocol_types & Object::PT_mapping) != 0) { - out << "static PyMappingMethods Dtool_MappingMethods_" << ClassName << " = {\n"; - write_function_slot(out, 2, slots, "mp_length"); - write_function_slot(out, 2, slots, "mp_subscript"); - write_function_slot(out, 2, slots, "mp_ass_subscript"); - out << "};\n\n"; - } - - // Same note applies as above. - if (has_parent_class || has_local_getbuffer) { - out << "static PyBufferProcs Dtool_BufferProcs_" << ClassName << " = {\n"; - out << "#if PY_MAJOR_VERSION < 3\n"; - write_function_slot(out, 2, slots, "bf_getreadbuffer"); - write_function_slot(out, 2, slots, "bf_getwritebuffer"); - write_function_slot(out, 2, slots, "bf_getsegcount"); - write_function_slot(out, 2, slots, "bf_getcharbuffer"); - out << "#endif\n"; - out << "#if PY_VERSION_HEX >= 0x02060000\n"; - write_function_slot(out, 2, slots, "bf_getbuffer"); - write_function_slot(out, 2, slots, "bf_releasebuffer"); - out << "#endif\n"; - out << "};\n\n"; - } - - bool have_async = false; - if (has_parent_class || slots.count("am_await") != 0 || - slots.count("am_aiter") != 0 || - slots.count("am_anext") != 0) { - out << "#if PY_VERSION_HEX >= 0x03050000\n"; - out << "static PyAsyncMethods Dtool_AsyncMethods_" << ClassName << " = {\n"; - write_function_slot(out, 2, slots, "am_await"); - write_function_slot(out, 2, slots, "am_aiter"); - write_function_slot(out, 2, slots, "am_anext"); - out << "};\n"; - out << "#endif\n\n"; - have_async = true; - } - - // Output the actual PyTypeObject definition. - out << "struct Dtool_PyTypedObject Dtool_" << ClassName << " = {\n"; - out << " {\n"; - out << " PyVarObject_HEAD_INIT(nullptr, 0)\n"; - // const char *tp_name; - out << " \"" << _def->module_name << "." << export_class_name << "\",\n"; - // Py_ssize_t tp_basicsize; - out << " 0, // tp_basicsize\n"; // inherited from tp_base - // Py_ssize_t tp_itemsize; - out << " 0, // tp_itemsize\n"; - - // destructor tp_dealloc; - out << " &Dtool_FreeInstance_" << ClassName << ",\n"; - - out << "#if PY_VERSION_HEX >= 0x03080000\n"; - out << " 0, // tp_vectorcall_offset\n"; - out << "#else\n"; - write_function_slot(out, 4, slots, "tp_print"); - out << "#endif\n"; - - // getattrfunc tp_getattr; - write_function_slot(out, 4, slots, "tp_getattr"); - // setattrfunc tp_setattr; - write_function_slot(out, 4, slots, "tp_setattr"); - - // cmpfunc tp_compare; (reserved in Python 3) - out << "#if PY_VERSION_HEX >= 0x03050000\n"; - if (have_async) { - out << " &Dtool_AsyncMethods_" << ClassName << ",\n"; - } else { - out << " nullptr, // tp_as_async\n"; - } - out << "#elif PY_MAJOR_VERSION >= 3\n"; - out << " nullptr, // tp_reserved\n"; - out << "#else\n"; - if (has_hash_compare) { - write_function_slot(out, 4, slots, "tp_compare", - "&DtoolInstance_ComparePointers"); - } else { - out << " nullptr, // tp_compare\n"; - } - out << "#endif\n"; - - // reprfunc tp_repr; - if (has_local_repr) { - out << " &Dtool_Repr_" << ClassName << ",\n"; - } else { - write_function_slot(out, 4, slots, "tp_repr"); - } - - // PyNumberMethods *tp_as_number; - out << " &Dtool_NumberMethods_" << ClassName << ",\n"; - // PySequenceMethods *tp_as_sequence; - if (has_parent_class || (obj->_protocol_types & Object::PT_sequence) != 0) { - out << " &Dtool_SequenceMethods_" << ClassName << ",\n"; - } else { - out << " nullptr, // tp_as_sequence\n"; - } - // PyMappingMethods *tp_as_mapping; - if (has_parent_class || (obj->_protocol_types & Object::PT_mapping) != 0) { - out << " &Dtool_MappingMethods_" << ClassName << ",\n"; - } else { - out << " nullptr, // tp_as_mapping\n"; - } - - // hashfunc tp_hash; - if (has_hash_compare) { - write_function_slot(out, 4, slots, "tp_hash", "&DtoolInstance_HashPointer"); - } else { - out << " nullptr, // tp_hash\n"; - } - - // ternaryfunc tp_call; - write_function_slot(out, 4, slots, "tp_call"); - - // reprfunc tp_str; - if (has_local_str) { - out << " &Dtool_Str_" << ClassName << ",\n"; - } else if (has_local_repr) { - out << " &Dtool_Repr_" << ClassName << ",\n"; - } else { - write_function_slot(out, 4, slots, "tp_str"); - } - - // getattrofunc tp_getattro; - write_function_slot(out, 4, slots, "tp_getattro"); - // setattrofunc tp_setattro; - write_function_slot(out, 4, slots, "tp_setattro"); - - // PyBufferProcs *tp_as_buffer; - if (has_parent_class || has_local_getbuffer) { - out << " &Dtool_BufferProcs_" << ClassName << ",\n"; - } else { - out << " nullptr, // tp_as_buffer\n"; - } - - string gcflag; - if (has_gc && slots.count("tp_traverse")) { - gcflag = " | Py_TPFLAGS_HAVE_GC"; - } - - // long tp_flags; - if (has_local_getbuffer) { - out << "#if PY_VERSION_HEX >= 0x02060000 && PY_VERSION_HEX < 0x03000000\n"; - out << " Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER" << gcflag << ",\n"; - out << "#else\n"; - out << " Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES" << gcflag << ",\n"; - out << "#endif\n"; - } else { - out << " Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES" << gcflag << ",\n"; - } - - // const char *tp_doc; - if (obj->_itype.has_comment()) { - out << "#ifdef NDEBUG\n"; - out << " 0,\n"; - out << "#else\n"; - output_quoted(out, 4, obj->_itype.get_comment()); - out << ",\n"; - out << "#endif\n"; - } else { - out << " nullptr, // tp_doc\n"; - } - - // traverseproc tp_traverse; - if (has_local_traverse) { - out << " &Dtool_Traverse_" << ClassName << ",\n"; - } else if (has_gc) { - write_function_slot(out, 4, slots, "tp_traverse"); - } else { - out << " nullptr, // tp_traverse\n"; - } - - // inquiry tp_clear; - if (has_local_clear) { - out << " &Dtool_Clear_" << ClassName << ",\n"; - } else if (has_gc) { - write_function_slot(out, 4, slots, "tp_clear"); - } else { - out << " nullptr, // tp_clear\n"; - } - - // richcmpfunc tp_richcompare; - if (has_local_richcompare) { - out << " &Dtool_RichCompare_" << ClassName << ",\n"; - } else if (has_hash_compare) { - // All hashable types need to be comparable. - out << "#if PY_MAJOR_VERSION >= 3\n"; - out << " &DtoolInstance_RichComparePointers,\n"; - out << "#else\n"; - out << " nullptr, // tp_richcompare\n"; - out << "#endif\n"; - } else { - out << " nullptr, // tp_richcompare\n"; - } - - // Py_ssize_t tp_weaklistoffset; - out << " 0, // tp_weaklistoffset\n"; - - // getiterfunc tp_iter; - write_function_slot(out, 4, slots, "tp_iter"); - // iternextfunc tp_iternext; - write_function_slot(out, 4, slots, "tp_iternext"); - - // struct PyMethodDef *tp_methods; - out << " Dtool_Methods_" << ClassName << ",\n"; - // struct PyMemberDef *tp_members; - out << " nullptr, // tp_members\n"; - - // struct PyGetSetDef *tp_getset; - if (num_getset > 0) { - out << " Dtool_Properties_" << ClassName << ",\n"; - } else { - out << " nullptr, // tp_getset\n"; - } - - // struct _typeobject *tp_base; - out << " nullptr, // tp_base\n"; - // PyObject *tp_dict; - out << " nullptr, // tp_dict\n"; - // descrgetfunc tp_descr_get; - write_function_slot(out, 4, slots, "tp_descr_get"); - // descrsetfunc tp_descr_set; - write_function_slot(out, 4, slots, "tp_descr_set"); - // Py_ssize_t tp_dictoffset; - out << " 0, // tp_dictoffset\n"; - // initproc tp_init; - out << " Dtool_Init_" << ClassName << ",\n"; - // allocfunc tp_alloc; - out << " PyType_GenericAlloc,\n"; - // newfunc tp_new; - write_function_slot(out, 4, slots, "tp_new", "Dtool_new_" + ClassName); - // freefunc tp_free; - if (slots.count("tp_traverse") || has_self_member(struct_type)) { - out << " PyObject_GC_Del,\n"; - } else { - out << " PyObject_Del,\n"; - } - // inquiry tp_is_gc; - out << " nullptr, // tp_is_gc\n"; - // PyObject *tp_bases; - out << " nullptr, // tp_bases\n"; - // PyObject *tp_mro; - out << " nullptr, // tp_mro\n"; - // PyObject *tp_cache; - out << " nullptr, // tp_cache\n"; - // PyObject *tp_subclasses; - out << " nullptr, // tp_subclasses\n"; - // PyObject *tp_weaklist; - out << " nullptr, // tp_weaklist\n"; - // destructor tp_del; - out << " nullptr, // tp_del\n"; - // unsigned int tp_version_tag - out << "#if PY_VERSION_HEX >= 0x02060000\n"; - out << " 0, // tp_version_tag\n"; - out << "#endif\n"; - // destructor tp_finalize - out << "#if PY_VERSION_HEX >= 0x03040000\n"; - out << " nullptr, // tp_finalize\n"; - out << "#endif\n"; - // vectorcallfunc tp_vectorcall - out << "#if PY_VERSION_HEX >= 0x03080000\n"; - out << " nullptr, // tp_vectorcall\n"; - out << "#endif\n"; - out << " },\n"; - - // It's tempting to initialize the type handle here, but this causes static - // init ordering issues; this may run before init_type is called. - out << " TypeHandle::none(),\n"; - out << " Dtool_PyModuleClassInit_" << ClassName << ",\n"; - out << " Dtool_UpcastInterface_" << ClassName << ",\n"; - out << " Dtool_Wrap_" << ClassName << ",\n"; - - int has_coerce = has_coerce_constructor(struct_type); - if (has_coerce > 0) { - if (TypeManager::is_reference_count(struct_type)) { - out << " (CoerceFunction)Dtool_ConstCoerce_" << ClassName << ",\n"; - if (has_coerce > 1) { - out << " (CoerceFunction)Dtool_Coerce_" << ClassName << ",\n"; - } else { - out << " nullptr,\n"; - } - } else { - out << " nullptr,\n"; - out << " (CoerceFunction)Dtool_Coerce_" << ClassName << ",\n"; - } - } else { - out << " nullptr,\n"; - out << " nullptr,\n"; - } - - out << "};\n\n"; - - out << "static void Dtool_PyModuleClassInit_" << ClassName << "(PyObject *module) {\n"; - out << " (void) module; // Unused\n"; - out << " static bool initdone = false;\n"; - out << " if (!initdone) {\n"; - out << " initdone = true;\n"; - - // Add bases. - out << " // Dependent objects\n"; - if (bases.size() > 0) { - string baseargs; - for (CPPType *base : bases) { - string safe_name = make_safe_name(base->get_local_name(&parser)); - - if (isExportThisRun(base)) { - baseargs += ", (PyTypeObject *)&Dtool_" + safe_name; - out << " Dtool_PyModuleClassInit_" << safe_name << "(nullptr);\n"; - - } else { - baseargs += ", (PyTypeObject *)Dtool_Ptr_" + safe_name; - - out << " assert(Dtool_Ptr_" << safe_name << " != nullptr);\n" - << " assert(Dtool_Ptr_" << safe_name << "->_Dtool_ModuleClassInit != nullptr);\n" - << " Dtool_Ptr_" << safe_name << "->_Dtool_ModuleClassInit(nullptr);\n"; - } - } - - out << " Dtool_" << ClassName << "._PyType.tp_bases = PyTuple_Pack(" << bases.size() << baseargs << ");\n"; - } - out << " Dtool_" << ClassName << "._PyType.tp_base = (PyTypeObject *)Dtool_GetSuperBase();\n"; - - int num_nested = obj->_itype.number_of_nested_types(); - int num_dict_items = 1; - - // Go through once to estimate the number of elements the dict will hold. - for (int ni = 0; ni < num_nested; ni++) { - TypeIndex nested_index = obj->_itype.get_nested_type(ni); - if (_objects.count(nested_index) == 0) { - continue; - } - Object *nested_obj = _objects[nested_index]; - assert(nested_obj != nullptr); - - if (nested_obj->_itype.is_class() || nested_obj->_itype.is_struct()) { - num_dict_items += 2; - - } else if (nested_obj->_itype.is_typedef()) { - ++num_dict_items; - - } else if (nested_obj->_itype.is_enum() && !nested_obj->_itype.is_scoped_enum()) { - CPPEnumType *enum_type = nested_obj->_itype._cpptype->as_enum_type(); - num_dict_items += 2 * enum_type->_elements.size(); - } - } - - // Build type dictionary. The size is just an estimation. - if (num_dict_items > 5) { - out << " PyObject *dict = _PyDict_NewPresized(" << num_dict_items << ");\n"; - } else { - out << " PyObject *dict = PyDict_New();\n"; - } - out << " Dtool_" << ClassName << "._PyType.tp_dict = dict;\n"; - out << " PyDict_SetItemString(dict, \"DtoolClassDict\", dict);\n"; - - // Now go through the nested types again to actually add the dict items. - for (int ni = 0; ni < num_nested; ni++) { - TypeIndex nested_index = obj->_itype.get_nested_type(ni); - if (_objects.count(nested_index) == 0) { - // Illegal type. - continue; - } - - Object *nested_obj = _objects[nested_index]; - assert(nested_obj != nullptr); - - if (nested_obj->_itype.is_class() || nested_obj->_itype.is_struct()) { - std::string ClassName1 = make_safe_name(nested_obj->_itype.get_scoped_name()); - std::string ClassName2 = make_safe_name(nested_obj->_itype.get_name()); - out << " // Nested Object " << ClassName1 << ";\n"; - out << " Dtool_PyModuleClassInit_" << ClassName1 << "(nullptr);\n"; - string name1 = classNameFromCppName(ClassName2, false); - string name2 = classNameFromCppName(ClassName2, true); - out << " PyDict_SetItemString(dict, \"" << name1 << "\", (PyObject *)&Dtool_" << ClassName1 << ");\n"; - if (name1 != name2) { - out << " PyDict_SetItemString(dict, \"" << name2 << "\", (PyObject *)&Dtool_" << ClassName1 << ");\n"; - } - - } else if (nested_obj->_itype.is_typedef()) { - // Unwrap typedefs. - TypeIndex wrapped = nested_obj->_itype._wrapped_type; - while (interrogate_type_is_typedef(wrapped)) { - wrapped = interrogate_type_wrapped_type(wrapped); - } - - // Er, we can only export typedefs to structs. - if (!interrogate_type_is_struct(wrapped)) { - continue; - } - - string ClassName1 = make_safe_name(interrogate_type_scoped_name(wrapped)); - string ClassName2 = make_safe_name(interrogate_type_name(wrapped)); - - string name1 = classNameFromCppName(ClassName2, false); - out << " PyDict_SetItemString(dict, \"" << name1 << "\", (PyObject *)&Dtool_" << ClassName1 << ");\n"; - // No need to support mangled names for nested typedefs; we only added - // support recently. - - } else if (nested_obj->_itype.is_scoped_enum()) { - // Convert enum class as Python 3.4-style enum. - string class_name = nested_obj->_itype._cpptype->get_local_name(&parser); - string safe_name = make_safe_name(class_name); - - int enum_count = nested_obj->_itype.number_of_enum_values(); - CPPType *underlying_type = TypeManager::unwrap_const(nested_obj->_itype._cpptype->as_enum_type()->get_underlying_type()); - string cast_to = underlying_type->get_local_name(&parser); - out << " // enum class " << nested_obj->_itype.get_scoped_name() << ";\n"; - out << " {\n"; - out << " PyObject *members = PyTuple_New(" << enum_count << ");\n"; - out << " PyObject *member;\n"; - for (int xx = 0; xx < enum_count; xx++) { - out << " member = PyTuple_New(2);\n" - "#if PY_MAJOR_VERSION >= 3\n" - " PyTuple_SET_ITEM(member, 0, PyUnicode_FromString(\"" - << nested_obj->_itype.get_enum_value_name(xx) << "\"));\n" - "#else\n" - " PyTuple_SET_ITEM(member, 0, PyString_FromString(\"" - << nested_obj->_itype.get_enum_value_name(xx) << "\"));\n" - "#endif\n" - " PyTuple_SET_ITEM(member, 1, Dtool_WrapValue((" - << cast_to << ")" << nested_obj->_itype.get_scoped_name() << "::" - << nested_obj->_itype.get_enum_value_name(xx) << "));\n" - " PyTuple_SET_ITEM(members, " << xx << ", member);\n"; - } - out << " Dtool_Ptr_" << safe_name << " = Dtool_EnumType_Create(\"" - << nested_obj->_itype.get_name() << "\", members, \"" - << _def->module_name << "\");\n"; - out << " PyDict_SetItemString(dict, \"" << nested_obj->_itype.get_name() - << "\", (PyObject *)Dtool_Ptr_" << safe_name << ");\n"; - out << " }\n"; - - } else if (nested_obj->_itype.is_enum()) { - out << " // enum " << nested_obj->_itype.get_scoped_name() << ";\n"; - CPPEnumType *enum_type = nested_obj->_itype._cpptype->as_enum_type(); - CPPEnumType::Elements::const_iterator ei; - for (ei = enum_type->_elements.begin(); ei != enum_type->_elements.end(); ++ei) { - string name1 = classNameFromCppName((*ei)->get_simple_name(), false); - string name2; - if (nested_obj->_itype.has_true_name()) { - name2 = classNameFromCppName((*ei)->get_simple_name(), true); - } else { - // Don't generate the alternative syntax for anonymous enums, since - // we added support for those after we started deprecating the - // alternative syntax. - name2 = name1; - } - string enum_value = obj->_itype.get_scoped_name() + "::" + (*ei)->get_simple_name(); - out << " PyDict_SetItemString(dict, \"" << name1 << "\", Dtool_WrapValue(" << enum_value << "));\n"; - if (name1 != name2) { - out << " PyDict_SetItemString(dict, \"" << name2 << "\", Dtool_WrapValue(" << enum_value << "));\n"; - } - } - } - } - - // Also add the static properties, which can't be added via getset. - for (Property *property : obj->_properties) { - const InterrogateElement &ielem = property->_ielement; - if (property->_getter_remaps.empty()) { - continue; - } - if (property->_has_this) { - // Actually, continue if we have a conflicting static method with the - // same name, which may still require use of Dtool_StaticProperty. - bool have_shadow = false; - for (const Function *func : obj->_methods) { - if (!func->_has_this && func->_ifunc.get_name() == ielem.get_name()) { - have_shadow = true; - break; - } - } - if (!have_shadow) { - continue; - } - } - - string name1 = methodNameFromCppName(ielem.get_name(), "", false); - // string name2 = methodNameFromCppName(ielem.get_name(), "", true); - - string getter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter"; - string setter = "nullptr"; - if (!ielem.is_sequence() && !ielem.is_mapping() && !property->_setter_remaps.empty()) { - setter = "&Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter"; - } - - out << " static const PyGetSetDef def_" << name1 << " = {(char *)\"" << name1 << "\", " << getter << ", " << setter; - - if (ielem.has_comment()) { - out << ", (char *)\n"; - output_quoted(out, 4, ielem.get_comment()); - out << ",\n "; - } else { - out << ", nullptr, "; - } - - // Extra void* argument; we don't make use of it. - out << "nullptr};\n"; - - out << " PyDict_SetItemString(dict, \"" << name1 << "\", Dtool_NewStaticProperty(&Dtool_" << ClassName << "._PyType, &def_" << name1 << "));\n"; - /* Alternative spelling: - out << " PyDict_SetItemString(\"" << name2 << "\", &def_" << name1 << ");\n"; - */ - } - - out << " if (PyType_Ready((PyTypeObject *)&Dtool_" << ClassName << ") < 0) {\n" - " PyErr_Format(PyExc_TypeError, \"PyType_Ready(%s)\", \"" << ClassName << "\");\n" - " return;\n" - " }\n" - " Py_INCREF((PyTypeObject *)&Dtool_" << ClassName << ");\n" - " }\n"; - -/* - * Also write out the explicit alternate names. int num_alt_names = - * obj->_itype.get_num_alt_names(); for (int i = 0; i < num_alt_names; ++i) { - * string alt_name = make_safe_name(obj->_itype.get_alt_name(i)); if - * (export_class_name != alt_name) { out << " PyModule_AddObject(module, - * \"" << alt_name << "\", (PyObject *)&Dtool_" << ClassName << - * ".As_PyTypeObject());\n"; } } - */ - - // out << " }\n"; - out << "}\n\n"; -} - -/** - * This method should be overridden and redefined to return true for - * interfaces that require the implicit "this" parameter, if present, to be - * passed as the first parameter to any wrapper functions. - */ -bool InterfaceMakerPythonNative:: -synthesize_this_parameter() { - return true; -} - -/** - * This method should be overridden and redefined to return true for - * interfaces that require overloaded instances of a function to be defined as - * separate functions (each with its own hashed name), or false for interfaces - * that can support overloading natively, and thus only require one wrapper - * function per each overloaded input function. - */ -bool InterfaceMakerPythonNative:: -separate_overloading() { - // We used to return true here. Nowadays, some of the default arguments are - // handled in the PyArg_ParseTuple code, and some are still being considered - // as separate overloads (this depends on a bunch of factors, see - // collapse_default_remaps). This is all handled elsewhere. - return false; -} - -/** - * Returns the prefix string used to generate wrapper function names. - */ -string InterfaceMakerPythonNative:: -get_wrapper_prefix() { - return "Dtool_"; -} - -/** - * Returns the prefix string used to generate unique symbolic names, which are - * not necessarily C-callable function names. - */ -string InterfaceMakerPythonNative:: -get_unique_prefix() { - return "Dtool_"; -} - -/** - * Associates the function wrapper with its function in the appropriate - * structures in the database. - */ -void InterfaceMakerPythonNative:: -record_function_wrapper(InterrogateFunction &ifunc, FunctionWrapperIndex wrapper_index) { - ifunc._python_wrappers.push_back(wrapper_index); -} - -/** - * Writes the prototype for the indicated function. - */ -void InterfaceMakerPythonNative:: -write_prototype_for(ostream &out, InterfaceMaker::Function *func) { - std::string fname = "PyObject *" + func->_name + "(PyObject *self, PyObject *args)"; - write_prototype_for_name(out, func, fname); -} -/** - * - */ -void InterfaceMakerPythonNative:: -write_prototype_for_name(ostream &out, InterfaceMaker::Function *func, const std::string &function_namename) { -// Function::Remaps::const_iterator ri; - -// for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { -// FunctionRemap *remap = (*ri); - if (!output_function_names) { - // If we're not saving the function names, don't export it from the - // library. - out << "static "; - } else { - out << "extern \"C\" "; - } - out << function_namename << ";\n"; -// } -} - -/** - * Writes the definition for a function that will call the indicated C++ - * function or method. - */ -void InterfaceMakerPythonNative:: -write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker::Function *func) { - - // First check if this function has non-slotted and legal remaps, ie. if we - // should even write it. - bool has_remaps = false; - - for (FunctionRemap *remap : func->_remaps) { - if (!is_remap_legal(remap)) { - continue; - } - - SlottedFunctionDef slotted_def; - if (!get_slotted_function_def(obj, func, remap, slotted_def) || slotted_def._keep_method) { - // It has a non-slotted remap, so we should write it. - has_remaps = true; - break; - } - } - - if (!has_remaps) { - // Nope. - return; - } - - // This is a bit of a hack, as these methods should probably be going - // through the slotted function system. But it's kind of pointless to write - // these out, and a waste of space. - string fname = func->_ifunc.get_name(); - if (fname == "operator <" || - fname == "operator <=" || - fname == "operator ==" || - fname == "operator !=" || - fname == "operator >" || - fname == "operator >=" || - fname == "operator <=>") { - return; - } - - if (func->_ifunc.is_unary_op()) { - assert(func->_args_type == AT_no_args); - } - - string prototype = "static PyObject *" + func->_name + "(PyObject *"; - - // This will be NULL for static funcs, so prevent code from using it. - if (func->_has_this) { - prototype += "self"; - } - else if (func->_flags & FunctionRemap::F_explicit_cls) { - prototype += "cls"; - } - - switch (func->_args_type) { - case AT_keyword_args: - prototype += ", PyObject *args, PyObject *kwds"; - break; - - case AT_varargs: - prototype += ", PyObject *args"; - break; - - case AT_single_arg: - prototype += ", PyObject *arg"; - break; - - default: - prototype += ", PyObject *"; - break; - } - prototype += ")"; - - string expected_params; - write_function_for_name(out, obj, func->_remaps, prototype, expected_params, true, func->_args_type, RF_pyobject | RF_err_null); - - // Now synthesize a variable for the docstring. - ostringstream comment; - if (!expected_params.empty()) { - comment << "C++ Interface:\n" - << expected_params; - } - - if (func->_ifunc._comment.size() > 2) { - if (!expected_params.empty()) { - comment << "\n"; - } - comment << func->_ifunc._comment; - } - - out << "#ifndef NDEBUG\n"; - out << "static const char *" << func->_name << "_comment =\n"; - output_quoted(out, 2, comment.str()); - out << ";\n"; - out << "#else\n"; - out << "static const char *" << func->_name << "_comment = nullptr;\n"; - out << "#endif\n\n"; -} - -/** - * Writes the definition for a function that will call the indicated C++ - * function or method. - */ -void InterfaceMakerPythonNative:: -write_function_for_name(ostream &out, Object *obj, - const Function::Remaps &remaps, - const string &function_name, - string &expected_params, - bool coercion_allowed, - ArgsType args_type, int return_flags) { - std::map > map_sets; - std::map >::iterator mii; - std::set::iterator sii; - - bool has_this = false; - Function::Remaps::const_iterator ri; - FunctionRemap *remap = nullptr; - int max_required_args = 0; - bool all_nonconst = true; - bool has_keywords = false; - - out << "/**\n * Python function wrapper for:\n"; - for (ri = remaps.begin(); ri != remaps.end(); ++ri) { - remap = (*ri); - if (is_remap_legal(remap)) { - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - if (remap->_has_this) { - has_this = true; - } - - if (!remap->_has_this || remap->_const_method) { - all_nonconst = false; - } - - if (remap->_args_type == AT_keyword_args) { - has_keywords = true; - } - - max_required_args = max(max_num_args, max_required_args); - - for (int i = min_num_args; i <= max_num_args; ++i) { - map_sets[i].insert(remap); - } - out << " * "; - remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args)); - out << "\n"; - } else { - out << " * Rejected Remap ["; - remap->write_orig_prototype(out, 0); - out << "]\n"; - } - } - - out << " */\n"; - - if (has_this && obj == nullptr) { - assert(obj != nullptr); - } - - out << function_name << " {\n"; - - if (has_this) { - std::string ClassName = make_safe_name(obj->_itype.get_scoped_name()); - std::string cClassName = obj->_itype.get_true_name(); - // string class_name = remap->_cpptype->get_simple_name(); - CPPStructType *struct_type = obj->_itype._cpptype->as_struct_type(); - - // If this is a non-static __setstate__, we run the default constructor. - if (remap->_cppfunc->get_local_name() == "__setstate__" && - !struct_type->is_abstract()) { - out << " " << cClassName << " *local_this = nullptr;\n" - << " if (DtoolInstance_VOID_PTR(self) == nullptr) {\n" - << " local_this = new " << cClassName << ";\n" - << " DTool_PyInit_Finalize(self, local_this, &Dtool_" << ClassName - << ", true, false);\n" - << " if (local_this == nullptr) {\n" - << " PyErr_NoMemory();\n"; - error_return(out, 6, return_flags); - out << " }\n" - << " } else if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", " - << "(void **)&local_this, \"" << classNameFromCppName(cClassName, false) - << "." << methodNameFromCppName(remap, cClassName, false) << "\")) {\n"; - } - else if (all_nonconst) { - // All remaps are non-const. Also check that this object isn't const. - out << " " << cClassName << " *local_this = nullptr;\n" - << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", " - << "(void **)&local_this, \"" << classNameFromCppName(cClassName, false) - << "." << methodNameFromCppName(remap, cClassName, false) << "\")) {\n"; - } - else { - out << " " << cClassName << " *local_this = nullptr;\n" - << " if (!DtoolInstance_GetPointer(self, local_this, Dtool_" << ClassName << ")) {\n"; - } - - error_return(out, 4, return_flags); - out << " }\n"; - } - - if (map_sets.empty()) { - error_return(out, 2, return_flags); - out << "}\n\n"; - return; - } - - if (args_type == AT_keyword_args && !has_keywords) { - // We don't actually take keyword arguments. Make sure we didn't get any. - out << " if (kwds != nullptr && PyDict_Size(kwds) > 0) {\n"; - out << "#ifdef NDEBUG\n"; - error_raise_return(out, 4, return_flags, "TypeError", "function takes no keyword arguments"); - out << "#else\n"; - error_raise_return(out, 4, return_flags, "TypeError", - methodNameFromCppName(remap, "", false) + "() takes no keyword arguments"); - out << "#endif\n"; - out << " }\n"; - args_type = AT_varargs; - } - - // If this is a __setstate__ taking multiple arguments, and we're given a - // tuple as argument, unpack it. - if (args_type == AT_single_arg && max_required_args > 1 && - remap->_cppfunc->get_local_name() == "__setstate__") { - out << " PyObject *args = arg;\n"; - args_type = AT_varargs; - } - - if (args_type == AT_keyword_args || args_type == AT_varargs) { - max_required_args = collapse_default_remaps(map_sets, max_required_args); - } - - if (remap->_flags & FunctionRemap::F_explicit_args) { - // We have a remap that wants to handle the wrapper itself. - string expected_params; - write_function_instance(out, remap, 0, 0, expected_params, 2, true, true, - args_type, return_flags); - - } else if (map_sets.size() > 1 && (args_type == AT_varargs || args_type == AT_keyword_args)) { - // We have more than one remap. - switch (args_type) { - case AT_keyword_args: - indent(out, 2) << "int parameter_count = (int)PyTuple_Size(args);\n"; - indent(out, 2) << "if (kwds != nullptr) {\n"; - indent(out, 2) << " parameter_count += (int)PyDict_Size(kwds);\n"; - indent(out, 2) << "}\n"; - break; - - case AT_varargs: - indent(out, 2) << "int parameter_count = (int)PyTuple_Size(args);\n"; - break; - - case AT_single_arg: - // It shouldn't get here, but we'll handle these cases nonetheless. - indent(out, 2) << "const int parameter_count = 1;\n"; - break; - - default: - indent(out, 2) << "const int parameter_count = 0;\n"; - break; - } - - // Keep track of how many args this function actually takes for the error - // message. We add one to the parameter count for "self", following the - // Python convention. - int add_self = has_this ? 1 : 0; - set num_args; - - indent(out, 2) << "switch (parameter_count) {\n"; - for (mii = map_sets.begin(); mii != map_sets.end(); ++mii) { - int max_args = mii->first; - int min_args = min(max_required_args, max_args); - - for (int i = min_args; i <= max_args; ++i) { - indent(out, 2) << "case " << i << ":\n"; - num_args.insert(i + add_self); - } - num_args.insert(max_args + add_self); - - bool strip_keyword_args = false; - - // Check whether any remap actually takes keyword arguments. If not, - // then we don't have to bother checking that for every remap. - if (args_type == AT_keyword_args && max_args > 0) { - strip_keyword_args = true; - - std::set::iterator sii; - for (sii = mii->second.begin(); sii != mii->second.end(); ++sii) { - remap = (*sii); - size_t first_param = remap->_has_this ? 1u : 0u; - for (size_t i = first_param; i < remap->_parameters.size(); ++i) { - if (remap->_parameters[i]._has_name) { - strip_keyword_args = false; - break; - } - } - } - } - - bool always_returns; - if (strip_keyword_args) { - // None of the remaps take any keyword arguments, so let's check that - // we take none. This saves some checks later on. - indent(out, 4) << "if (kwds == nullptr || PyDict_GET_SIZE(kwds) == 0) {\n"; - if (min_args == 1 && max_args == 1) { - indent(out, 4) << " PyObject *arg = PyTuple_GET_ITEM(args, 0);\n"; - always_returns = write_function_forset(out, mii->second, min_args, - max_args, expected_params, 6, - coercion_allowed, true, - AT_single_arg, return_flags, - true, !all_nonconst); - } else { - always_returns = write_function_forset(out, mii->second, min_args, - max_args, expected_params, 6, - coercion_allowed, true, - AT_varargs, return_flags, - true, !all_nonconst); - } - } else if (min_args == 1 && max_args == 1 && args_type == AT_varargs) { - // We already checked that the args tuple has only one argument, so - // we might as well extract that from the tuple now. - indent(out, 4) << "{\n"; - indent(out, 4) << " PyObject *arg = PyTuple_GET_ITEM(args, 0);\n"; - - always_returns = write_function_forset(out, mii->second, min_args, - max_args, expected_params, 6, - coercion_allowed, true, - AT_single_arg, return_flags, - true, !all_nonconst); - } else { - indent(out, 4) << "{\n"; - always_returns = write_function_forset(out, mii->second, min_args, - max_args, expected_params, 6, - coercion_allowed, true, args_type, - return_flags, true, !all_nonconst); - } - - indent(out, 4) << "}\n"; - if (!always_returns) { - indent(out, 4) << "break;\n"; - } - } - - // In NDEBUG case, fall through to the error at end of function. - out << "#ifndef NDEBUG\n"; - - indent(out, 2) << "default:\n"; - - // Format an error saying how many arguments we actually take. So much - // logic for such a silly matter. Sheesh. - ostringstream msg; - msg << methodNameFromCppName(remap, "", false) << "() takes "; - - set::iterator si = num_args.begin(); - msg << *si; - if (num_args.size() == 2) { - msg << " or " << *(++si); - } else if (num_args.size() > 2) { - ++si; - while (si != num_args.end()) { - int num = *si; - if ((++si) == num_args.end()) { - msg << " or " << num; - } else { - msg << ", " << num; - } - } - } - msg << " arguments (%d given)"; - - string count_var = "parameter_count"; - if (add_self) { - count_var += " + 1"; - } - - error_raise_return(out, 4, return_flags, "TypeError", - msg.str(), count_var); - out << "#endif\n"; - indent(out, 2) << "}\n"; - - error_bad_args_return(out, 2, return_flags, expected_params); - - } else { - mii = map_sets.begin(); - - // If no parameters are accepted, we do need to check that the argument - // count is indeed 0, since we won't check that in - // write_function_instance. - if (mii->first == 0 && args_type != AT_no_args) { - switch (args_type) { - case AT_keyword_args: - out << " if (!Dtool_CheckNoArgs(args, kwds)) {\n"; - out << " int parameter_count = (int)PyTuple_Size(args);\n"; - out << " if (kwds != nullptr) {\n"; - out << " parameter_count += (int)PyDict_Size(kwds);\n"; - out << " }\n"; - break; - case AT_varargs: - out << " if (!Dtool_CheckNoArgs(args)) {\n"; - out << " const int parameter_count = (int)PyTuple_GET_SIZE(args);\n"; - break; - case AT_single_arg: - // Shouldn't happen, but let's handle this case nonetheless. - out << " {\n"; - out << " const int parameter_count = 1;\n"; - break; - case AT_no_args: - break; - case AT_unknown: - break; - } - - out << "#ifdef NDEBUG\n"; - error_raise_return(out, 4, return_flags, "TypeError", "function takes no arguments"); - out << "#else\n"; - error_raise_return(out, 4, return_flags, "TypeError", - methodNameFromCppName(remap, "", false) + "() takes no arguments (%d given)", - "parameter_count"); - out << "#endif\n"; - out << " }\n"; - - } else if (args_type == AT_keyword_args && max_required_args == 1 && mii->first == 1) { - // Check this to be sure, as we handle the case of only 1 keyword arg in - // write_function_forset (not using ParseTupleAndKeywords). - out << " int parameter_count = (int)PyTuple_Size(args);\n" - " if (kwds != nullptr) {\n" - " parameter_count += (int)PyDict_Size(kwds);\n" - " }\n" - " if (parameter_count != 1) {\n" - "#ifdef NDEBUG\n"; - error_raise_return(out, 4, return_flags, "TypeError", - "function takes exactly 1 argument"); - out << "#else\n"; - error_raise_return(out, 4, return_flags, "TypeError", - methodNameFromCppName(remap, "", false) + "() takes exactly 1 argument (%d given)", - "parameter_count"); - out << "#endif\n"; - out << " }\n"; - } - - int min_args = min(max_required_args, mii->first); - if (!write_function_forset(out, mii->second, min_args, mii->first, - expected_params, 2, coercion_allowed, true, - args_type, return_flags, true, !all_nonconst)) { - error_bad_args_return(out, 2, return_flags, expected_params); - } - } - - out << "}\n\n"; -} - -/** - * Writes the definition for a coerce constructor: a special constructor that - * is called to implicitly cast a tuple or other type to a desired type. This - * is done by calling the appropriate constructor or static make() function. - * Constructors marked with the "explicit" keyword aren't considered, just - * like in C++. - * - * There are usually two coerce constructors: one for const pointers, one for - * non-const pointers. This is due to the possibility that a static make() - * function may return a const pointer. - * - * There are two variants of this: if the class in question is a - * ReferenceCount, the coerce constructor takes a reference to a PointerTo or - * ConstPointerTo to store the converted pointer in. Otherwise, it is a - * regular pointer, and an additional boolean indicates whether the caller is - * supposed to call "delete" on the coerced pointer or not. - * - * In all cases, the coerce constructor returns a bool indicating whether the - * conversion was possible. It does not raise exceptions when none of the - * constructors matched, but just returns false. - */ -void InterfaceMakerPythonNative:: -write_coerce_constructor(ostream &out, Object *obj, bool is_const) { - std::map > map_sets; - std::map >::iterator mii; - - int max_required_args = 0; - - // Go through the methods and find appropriate static make() functions. - for (Function *func : obj->_methods) { - for (FunctionRemap *remap : func->_remaps) { - if (is_remap_legal(remap) && remap->_flags & FunctionRemap::F_coerce_constructor) { - nassertd(!remap->_has_this) continue; - - // It's a static make() function. - CPPType *return_type = remap->_return_type->get_new_type(); - - if (!is_const && TypeManager::is_const_pointer_or_ref(return_type)) { - // If we're making the non-const coerce constructor, reject this - // remap if it returns a const pointer. - continue; - } - - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - - // Coerce constructor should take at least one argument. - nassertd(max_num_args > 0) continue; - min_num_args = max(min_num_args, 1); - - max_required_args = max(max_num_args, max_required_args); - - for (int i = min_num_args; i <= max_num_args; ++i) { - map_sets[i].insert(remap); - } - - size_t parameter_size = remap->_parameters.size(); - map_sets[parameter_size].insert(remap); - } - } - } - - // Now go through the constructors that are suitable for coercion. This - // excludes copy constructors and ones marked "explicit". - for (Function *func : obj->_constructors) { - for (FunctionRemap *remap : func->_remaps) { - if (is_remap_legal(remap) && remap->_flags & FunctionRemap::F_coerce_constructor) { - nassertd(!remap->_has_this) continue; - - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - - // Coerce constructor should take at least one argument. - nassertd(max_num_args > 0) continue; - min_num_args = max(min_num_args, 1); - - max_required_args = max(max_num_args, max_required_args); - - for (int i = min_num_args; i <= max_num_args; ++i) { - map_sets[i].insert(remap); - } - - size_t parameter_size = remap->_parameters.size(); - map_sets[parameter_size].insert(remap); - } - } - } - - std::string ClassName = make_safe_name(obj->_itype.get_scoped_name()); - std::string cClassName = obj->_itype.get_true_name(); - - int return_flags = RF_coerced; - - if (TypeManager::is_reference_count(obj->_itype._cpptype)) { - // The coercion works slightly different for reference counted types, - // since we can handle those a bit more nicely by taking advantage of the - // refcount instead of having to use a boolean to indicate that it should - // be managed. - if (is_const) { - out << "bool Dtool_ConstCoerce_" << ClassName << "(PyObject *args, CPT(" << cClassName << ") &coerced) {\n"; - } else { - out << "bool Dtool_Coerce_" << ClassName << "(PyObject *args, PT(" << cClassName << ") &coerced) {\n"; - } - - // Note: this relies on the PT() being initialized to NULL. This is - // currently the case in all invocations, but this may not be true in the - // future. - out << " if (DtoolInstance_GetPointer(args, coerced.cheat(), Dtool_" << ClassName << ")) {\n"; - out << " // The argument is already of matching type, no need to coerce.\n"; - if (!is_const) { - out << " if (!DtoolInstance_IS_CONST(args)) {\n"; - out << " // A non-const instance is required, which this is.\n"; - out << " coerced->ref();\n"; - out << " return true;\n"; - out << " }\n"; - } else { - out << " coerced->ref();\n"; - out << " return true;\n"; - } - return_flags |= RF_err_false; - - } else { - out << cClassName << " *Dtool_Coerce_" << ClassName << "(PyObject *args, " << cClassName << " &coerced) {\n"; - - out << " " << cClassName << " *local_this;\n"; - out << " if (DtoolInstance_GetPointer(args, local_this, Dtool_" << ClassName << ")) {\n"; - out << " if (DtoolInstance_IS_CONST(args)) {\n"; - out << " // This is a const object. Make a copy.\n"; - out << " coerced = *(const " << cClassName << " *)local_this;\n"; - out << " return &coerced;\n"; - out << " }\n"; - out << " return local_this;\n"; - - return_flags |= RF_err_null; - } - - out << " }\n\n"; - - if (map_sets.empty()) { - error_return(out, 2, return_flags); - out << "}\n\n"; - return; - } - - // Coercion constructors are special cases in that they can take either a - // single value or a tuple. (They never, however, take a tuple containing a - // single value.) - string expected_params; - mii = map_sets.find(1); - if (mii != map_sets.end()) { - out << " if (!PyTuple_Check(args)) {\n"; - out << " PyObject *arg = args;\n"; - - write_function_forset(out, mii->second, mii->first, mii->first, expected_params, 4, false, false, - AT_single_arg, return_flags, true, false); - - if (map_sets.size() == 1) { - out << " }\n"; - // out << " PyErr_Clear();\n"; - error_return(out, 2, return_flags); - out << "}\n\n"; - return; - } - - // We take this one out of the map sets. There's not much value in - // coercing tuples containing just one value. - map_sets.erase(mii); - - out << " } else {\n"; - } else { - out << " if (PyTuple_Check(args)) {\n"; - } - - max_required_args = collapse_default_remaps(map_sets, max_required_args); - - if (map_sets.size() > 1) { - indent(out, 4) << "switch (PyTuple_GET_SIZE(args)) {\n"; - - for (mii = map_sets.begin(); mii != map_sets.end(); ++mii) { - int max_args = mii->first; - int min_args = min(max_required_args, max_args); - - // This is not called for tuples containing just one value or no values - // at all, so we should never have to consider that case. - if (min_args < 2) { - min_args = 2; - } - nassertd(max_args >= min_args) continue; - - for (int i = min_args; i < max_args; ++i) { - if (i != 1) { - indent(out, 6) << "case " << i << ":\n"; - } - } - indent(out, 6) << "case " << max_args << ": {\n"; - - if (!write_function_forset(out, mii->second, min_args, max_args, - expected_params, 8, false, false, - AT_varargs, return_flags, true, false)) { - indent(out, 8) << "break;\n"; - } - indent(out, 6) << "}\n"; - } - indent(out, 4) << "}\n"; - - } else { - mii = map_sets.begin(); - - int max_args = mii->first; - int min_args = min(max_required_args, max_args); - - // This is not called for tuples containing just one value or no values at - // all, so we should never have to consider that case. - if (min_args < 2) { - min_args = 2; - } - nassertv(max_args >= min_args); - - if (min_args == max_args) { - indent(out, 4) << "if (PyTuple_GET_SIZE(args) == " << mii->first << ") {\n"; - } else { - indent(out, 4) << "Py_ssize_t size = PyTuple_GET_SIZE(args);\n"; - // Not sure if this check really does any good. I guess it's a useful - // early-fail test. - indent(out, 4) << "if (size >= " << min_args << " && size <= " << max_args << ") {\n"; - } - - write_function_forset(out, mii->second, min_args, max_args, expected_params, 6, false, false, - AT_varargs, return_flags, true, false); - indent(out, 4) << "}\n"; - } - - out << " }\n\n"; - // out << " PyErr_Clear();\n"; - error_return(out, 2, return_flags); - out << "}\n\n"; -} - -/** - * Special case optimization: if the last map is a subset of the map before - * it, we can merge the cases. When this happens, we can make use of a - * special feature of PyArg_ParseTuple for handling of these last few default - * arguments. - * - * This isn't just to help reduce the amount of generated code; it also - * enables arbitrary selection of keyword arguments for many functions, ie. - * for this function: - * - * int func(int a=0, int b=0, bool c=false, string d=""); - * - * Thanks to this mechanism, we can call it like so: - * - * func(c=True, d=".") - */ -int InterfaceMakerPythonNative:: -collapse_default_remaps(std::map > &map_sets, - int max_required_args) { - if (map_sets.size() < 1) { - return max_required_args; - } - - std::map >::reverse_iterator rmi, rmi_next; - rmi = map_sets.rbegin(); - rmi_next = rmi; - for (++rmi_next; rmi_next != map_sets.rend();) { - if (std::includes(rmi_next->second.begin(), rmi_next->second.end(), - rmi->second.begin(), rmi->second.end())) { - - // rmi_next has a superset of the remaps in rmi, and we are going to - // erase rmi_next, so put all the remaps in rmi. - - max_required_args = rmi_next->first; - rmi = rmi_next; - ++rmi_next; - } else { - break; - } - } - - // Now erase the other remap sets. Reverse iterators are weird, we first - // need to get forward iterators and decrement them by one. - std::map >::iterator erase_begin, erase_end; - erase_begin = rmi.base(); - erase_end = map_sets.rbegin().base(); - --erase_begin; - --erase_end; - - if (erase_begin == erase_end) { - return max_required_args; - } - - // We're never erasing the map set with the highest number of args. - nassertr(erase_end != map_sets.end(), max_required_args); - - // We know erase_begin is a superset of erase_end, but we want all the - // remaps in erase_end (which we aren't erasing). if (rmi == - // map_sets.rbegin()) { - erase_end->second = erase_begin->second; - // } - - map_sets.erase(erase_begin, erase_end); - - assert(map_sets.size() >= 1); - - return max_required_args; -} - -/** - - */ -int get_type_sort(CPPType *type) { - int answer = 0; -// printf(" %s\n",type->get_local_name().c_str()); - - // The highest numbered one will be checked first. - if (TypeManager::is_nullptr(type)) { - return 15; - } else if (TypeManager::is_pointer_to_Py_buffer(type)) { - return 14; - } else if (TypeManager::is_pointer_to_PyTypeObject(type)) { - return 13; - } else if (TypeManager::is_pointer_to_PyObject(type)) { - return 12; - } else if (TypeManager::is_wstring(type)) { - return 11; - } else if (TypeManager::is_wchar_pointer(type)) { - return 10; - } else if (TypeManager::is_string(type)) { - return 9; - } else if (TypeManager::is_char_pointer(type)) { - return 8; - } else if (TypeManager::is_unsigned_longlong(type)) { - return 7; - } else if (TypeManager::is_longlong(type)) { - return 6; - } else if (TypeManager::is_integer(type) && !TypeManager::is_bool(type)) { - return 5; - } else if (TypeManager::is_double(type)) { - return 4; - } else if (TypeManager::is_float(type)) { - return 3; - } else if (TypeManager::is_pointer_to_simple(type)) { - return 2; - } else if (TypeManager::is_bool(type)) { - return 1; - } else if (TypeManager::is_pointer(type) || - TypeManager::is_reference(type) || - TypeManager::is_struct(type)) { - answer = 20; - int deepest = 0; - - // Sort such that more derived classes come first. - type = TypeManager::unwrap(TypeManager::resolve_type(type)); - if (type != nullptr) { - CPPStructType *struct_type = type->as_struct_type(); - if (struct_type != nullptr) { - for (const CPPStructType::Base &base : struct_type->_derivation) { - if (base._base != nullptr) { - int this_one = get_type_sort(base._base); - if (this_one > deepest) { - deepest = this_one; - } - } - } - } - } - answer += deepest; -// printf(" Class Name %s %d\n",itype.get_name().c_str(),answer); - } - -// printf(" Class Name %s %d\n",itype.get_name().c_str(),answer); - return answer; -} - -// The Core sort function for remap calling orders.. -bool RemapCompareLess(FunctionRemap *in1, FunctionRemap *in2) { - assert(in1 != nullptr); - assert(in2 != nullptr); - - if (in1->_const_method != in2->_const_method) { - // Non-const methods should come first. - return in2->_const_method; - } - - if (in1->_parameters.size() != in2->_parameters.size()) { - return (in1->_parameters.size() > in2->_parameters.size()); - } - - int pcount = in1->_parameters.size(); - for (int x = 0; x < pcount; x++) { - CPPType *orig_type1 = in1->_parameters[x]._remap->get_orig_type(); - CPPType *orig_type2 = in2->_parameters[x]._remap->get_orig_type(); - - int pd1 = get_type_sort(orig_type1); - int pd2 = get_type_sort(orig_type2); - if (pd1 != pd2) { - return (pd1 > pd2); - } - } - - // ok maybe something to do with return strength.. - - return false; -} - -/** - * Writes out a set of function wrappers that handle all instances of a - * particular function with the same number of parameters. (Actually, in some - * cases relating to default argument handling, this may be called with remaps - * taking a range of parameters.) - * - * min_num_args and max_num_args are the range of parameter counts to respect - * for these functions. This is important for default argument handling. - * - * expected_params is a reference to a string that will be filled in with a - * list of overloads that this function takes, for displaying in the doc - * string and error messages. - * - * If coercion_allowed is true, it will attempt to convert arguments to the - * appropriate parameter type using the appropriate Dtool_Coerce function. - * This means it may write some remaps twice: once without coercion, and then - * it may go back and write it a second time to try parameter coercion. - * - * If report_errors is true, it will print an error and exit when one has - * occurred, instead of falling back to the next overload. This is - * automatically disabled when more than one function is passed. - * - * args_type indicates whether this function takes no args, a single PyObject* - * arg, an args tuple, or an args tuple and kwargs dictionary. - * - * return_flags indicates which value should be returned from the wrapper - * function and what should be returned on error. - * - * If check_exceptions is false, it will not check if the function raised an - * exception, except if it took PyObject* arguments. This should NEVER be - * false for C++ functions that call Python code, since that would block a - * meaningful exception like SystemExit or KeyboardInterrupt. - * - * If verify_const is set, it will write out a check to make sure that non- - * const functions aren't called for a const "this". This is usually only - * false when write_function_for_name has already done this check (which it - * does when *all* remaps are non-const). - * - * If first_pexpr is not empty, it represents the preconverted value of the - * first parameter. This is a special-case hack for one of the slot - * functions. - */ -bool InterfaceMakerPythonNative:: -write_function_forset(ostream &out, - const std::set &remapsin, - int min_num_args, int max_num_args, - string &expected_params, int indent_level, - bool coercion_allowed, bool report_errors, - ArgsType args_type, int return_flags, - bool check_exceptions, bool verify_const, - const string &first_pexpr) { - - if (remapsin.empty()) { - return false; - } - - FunctionRemap *remap = nullptr; - std::set::iterator sii; - - bool all_nonconst = false; - bool always_returns = true; - - if (verify_const) { - // Check if all of the remaps are non-const. If so, we only have to check - // the constness of the self pointer once, rather than per remap. - all_nonconst = true; - - for (sii = remapsin.begin(); sii != remapsin.end(); ++sii) { - remap = (*sii); - if (!remap->_has_this || remap->_const_method) { - all_nonconst = false; - break; - } - } - - if (all_nonconst) { - // Yes, they do. Check that the parameter has the required constness. - indent(out, indent_level) - << "if (!DtoolInstance_IS_CONST(self)) {\n"; - indent_level += 2; - verify_const = false; - } - } - - string first_param_name; - bool same_first_param = false; - - // If there's only one arg and all remaps have the same parameter name, we - // extract it from the dictionary, so we don't have to call - // ParseTupleAndKeywords. - if (first_pexpr.empty() && min_num_args == 1 && max_num_args == 1 && - args_type == AT_keyword_args) { - sii = remapsin.begin(); - remap = (*sii); - if (remap->_parameters[(int)remap->_has_this]._has_name) { - first_param_name = remap->_parameters[(int)remap->_has_this]._name; - same_first_param = true; - - for (++sii; sii != remapsin.end(); ++sii) { - remap = (*sii); - if (remap->_parameters[(int)remap->_has_this]._name != first_param_name) { - same_first_param = false; - break; - } - } - } - } - - if (same_first_param) { - // Yes, they all have the same argument name (or there is only one remap). - // Extract it from the dict so we don't have to call - // ParseTupleAndKeywords. - indent(out, indent_level) << "PyObject *arg;\n"; - indent(out, indent_level) << "if (Dtool_ExtractArg(&arg, args, kwds, \"" << first_param_name << "\")) {\n"; - indent_level += 2; - args_type = AT_single_arg; - always_returns = false; - } - - if (remapsin.size() > 1) { - // There are multiple different overloads for this number of parameters. - // Sort them all into order from most-specific to least-specific, then try - // them one at a time. - std::vector remaps (remapsin.begin(), remapsin.end()); - std::sort(remaps.begin(), remaps.end(), RemapCompareLess); - std::vector::const_iterator sii; - - int num_coercion_possible = 0; - bool caught_all = false; - sii = remaps.begin(); - while (sii != remaps.end()) { - remap = *(sii++); - - if (coercion_allowed && is_remap_coercion_possible(remap)) { - if (++num_coercion_possible == 1 && sii == remaps.end()) { - // This is the last remap, and it happens to be the only one with - // coercion possible. So we might as well just break off now, and - // let this case be handled by the coercion loop, below. BUG: this - // remap doesn't get listed in expected_params. - break; - } - } - - if (caught_all) { - indent(out, indent_level) - << " // [DCE] -2 \n"; - remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args)); - out << "\n"; - continue; - } - - bool remap_verify_const = verify_const && (remap->_has_this && !remap->_const_method); - if (remap_verify_const) { - // If it's a non-const method, we only allow a non-const this. - indent(out, indent_level) - << "if (!DtoolInstance_IS_CONST(self)) {\n"; - } else { - indent(out, indent_level) - << "{\n"; - } - - indent(out, indent_level) << " // -2 "; - remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args)); - out << "\n"; - - // NB. We don't pass on report_errors here because we want it to - // silently drop down to the next overload. - - if (write_function_instance(out, remap, min_num_args, max_num_args, - expected_params, indent_level + 2, - false, false, args_type, return_flags, - check_exceptions, first_pexpr)) { - // The rest of the overloads are dead code. - if (!remap_verify_const) { - caught_all = true; - //indent(out, indent_level) << " // caught all cases here\n"; - } - } - - indent(out, indent_level) << "}\n\n"; - } - - // Go through one more time, but allow coercion this time. - if (coercion_allowed && !caught_all) { - for (sii = remaps.begin(); sii != remaps.end(); ++sii) { - remap = (*sii); - if (!is_remap_coercion_possible(remap)) { - indent(out, indent_level) - << "// No coercion possible: "; - remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args)); - out << "\n"; - continue; - } - - if (caught_all) { - indent(out, indent_level) - << " // [DCE] -2 \n"; - remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args)); - out << "\n"; - continue; - } - - bool remap_verify_const = verify_const && (remap->_has_this && !remap->_const_method); - if (remap_verify_const) { - indent(out, indent_level) - << "if (!DtoolInstance_IS_CONST(self)) {\n"; - } else { - indent(out, indent_level) - << "{\n"; - } - - indent(out, indent_level) << " // -2 "; - remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args)); - out << "\n"; - - string ignore_expected_params; - if (write_function_instance(out, remap, min_num_args, max_num_args, - ignore_expected_params, indent_level + 2, - true, false, args_type, return_flags, - check_exceptions, first_pexpr)) { - // The rest of the overloads are dead code. - if (!remap_verify_const) { - caught_all = true; - //indent(out, indent_level) << " // caught all cases here\n"; - } - } - - indent(out, indent_level) << "}\n\n"; - } - } - - if (!caught_all) { - always_returns = false; - } - } else { - // There is only one possible overload with this number of parameters. - // Just call it. - sii = remapsin.begin(); - - remap = (*sii); - indent(out, indent_level) - << "// 1-" ; - remap->write_orig_prototype(out, 0, false, (max_num_args - min_num_args)); - out << "\n"; - - if (!write_function_instance(out, remap, min_num_args, max_num_args, - expected_params, indent_level, - coercion_allowed, report_errors, - args_type, return_flags, - check_exceptions, first_pexpr)) { - always_returns = false; - } - } - - // Close the brace we opened earlier. - if (same_first_param) { - indent_level -= 2; - indent(out, indent_level) << "}\n"; - } - - // If we did a const check earlier, and we were asked to report errors, - // write out an else case raising an exception. - if (all_nonconst) { - if (report_errors) { - indent(out, indent_level - 2) - << "} else {\n"; - - string class_name = remap->_cpptype->get_simple_name(); - ostringstream msg; - msg << "Cannot call " - << classNameFromCppName(class_name, false) - << "." << methodNameFromCppName(remap, class_name, false) - << "() on a const object."; - - out << "#ifdef NDEBUG\n"; - error_raise_return(out, indent_level, return_flags, "TypeError", - "non-const method called on const object"); - out << "#else\n"; - error_raise_return(out, indent_level, return_flags, "TypeError", msg.str()); - out << "#endif\n"; - } else { - always_returns = false; - } - indent_level -= 2; - indent(out, indent_level) << "}\n"; - } - - return always_returns; -} - -/** - * Writes out the code to handle a a single instance of an overloaded - * function. This will convert all of the arguments from PyObject* to the - * appropriate C++ type, call the C++ function, possibly check for errors, and - * construct a Python wrapper for the return value. - * - * return_flags indicates which value should be returned from the wrapper - * function and what should be returned on error. - * - * If coercion_possible is true, it will attempt to convert arguments to the - * appropriate parameter type using the appropriate Dtool_Coerce function. - * - * If report_errors is true, it will print an error and exit when one has - * occurred, instead of falling back to the next overload. This should be - * done if it is the only overload. - * - * If check_exceptions is false, it will not check if the function raised an - * exception, except if it took PyObject* arguments. This should NEVER be - * false for C++ functions that call Python code, since that would block a - * meaningful exception like SystemExit or KeyboardInterrupt. - * - * If first_pexpr is not empty, it represents the preconverted value of the - * first parameter. This is a special-case hack for one of the slot - * functions. - * - * Returns true if the function returns unconditionally, false if it may fall - * through and additional error handling code is needed. - */ -bool InterfaceMakerPythonNative:: -write_function_instance(ostream &out, FunctionRemap *remap, - int min_num_args, int max_num_args, - string &expected_params, int indent_level, - bool coercion_possible, bool report_errors, - ArgsType args_type, int return_flags, - bool check_exceptions, - const string &first_pexpr) { - string format_specifiers; - string keyword_list_old; - string keyword_list_new; - string parameter_list; - string container; - string type_check; - string param_name; - bool has_keywords = false; - vector_string pexprs; - LineStream extra_convert; - ostringstream extra_param_check; - LineStream extra_cleanup; - int min_version = 0; - - // This will be set if the function itself is suspected of possibly raising - // a TypeError. - bool may_raise_typeerror = false; - - // This will be set to true if one of the things we're about to do *might* - // raise a TypeError that we may have to clear. - bool clear_error = false; - - bool is_constructor = (remap->_type == FunctionRemap::T_constructor); - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - // Make one pass through the parameter list. We will output a one-line - // temporary variable definition for each parameter, while simultaneously - // building the ParseTuple() function call and also the parameter expression - // list for call_function(). - - expected_params += methodNameFromCppName(remap, "", false); - expected_params += "("; - - int num_params = 0; - - if ((remap->_flags & FunctionRemap::F_explicit_args) == 0) { - num_params = max_num_args; - if (remap->_has_this) { - num_params += 1; - } - if (num_params > (int)remap->_parameters.size()) { - // Limit to how many parameters this remap actually has. - num_params = (int)remap->_parameters.size(); - max_num_args = num_params; - if (remap->_has_this) { - --max_num_args; - } - } - nassertr(num_params <= (int)remap->_parameters.size(), false); - } - - bool only_pyobjects = true; - - int pn = 0; - - if (remap->_has_this) { - // The first parameter is the 'this' parameter. - string expected_class_name = classNameFromCppName(remap->_cpptype->get_simple_name(), false); - if (remap->_const_method) { - expected_params += expected_class_name + " self"; - string class_name = remap->_cpptype->get_local_name(&parser); - container = "(const " + class_name + "*)local_this"; - } else { - expected_params += "const " + expected_class_name + " self"; - container = "local_this"; - } - pexprs.push_back(container); - ++pn; - } - - if (!first_pexpr.empty()) { - if (pn >= num_params) { - // first_pexpr was passed even though the function takes no arguments. - nassert_raise("pn < num_params"); - } else { - // The first actual argument was already converted. - if (pn > 0) { - expected_params += ", "; - } - expected_params += first_pexpr; - pexprs.push_back(first_pexpr); - ++pn; - } - } - - if (remap->_flags & FunctionRemap::F_explicit_args) { - // The function handles the arguments by itself. - expected_params += "*args"; - pexprs.push_back("args"); - if (remap->_args_type == AT_keyword_args) { - if (args_type == AT_keyword_args) { - expected_params += ", **kwargs"; - pexprs.push_back("kwds"); - } else { - pexprs.push_back("nullptr"); - } - } - num_params = 0; - } - - // Now convert (the rest of the) actual arguments, one by one. - for (; pn < num_params; ++pn) { - ParameterRemap *param = remap->_parameters[pn]._remap; - CPPType *orig_type = param->get_orig_type(); - CPPType *type = param->get_new_type(); - CPPExpression *default_value = param->get_default_value(); - param_name = remap->get_parameter_name(pn); - - if (!is_cpp_type_legal(orig_type)) { - // We can't wrap this. We sometimes get here for default arguments. - // Just skip this parameter. - continue; - } - - // Has this remap been selected to consider optional arguments for this - // parameter? We can do that by adding a vertical bar to the - // PyArg_ParseTuple format string, coupled with some extra logic in the - // argument handling, below. - bool is_optional = false; - if (remap->_has_this && !is_constructor) { - if (pn > min_num_args) { - is_optional = true; - if ((pn - 1) == min_num_args) { - format_specifiers += "|"; - } - } - } else { - if (pn >= min_num_args) { - is_optional = true; - if (pn == min_num_args) { - format_specifiers += "|"; - } - } - } - - if (pn > 0) { - expected_params += ", "; - } - - // This is the string to convert our local variable to the appropriate C++ - // type. Normally this is just a cast. - string pexpr_string = - "(" + orig_type->get_local_name(&parser) + ")" + param_name; - - string default_expr; - const char *null_assign = ""; - - if (is_optional) { - // If this is an optional argument, PyArg_ParseTuple will leave the - // variable unchanged if it has been omitted, so we have to initialize - // it to the desired default expression. Format it. - ostringstream default_expr_str; - default_expr_str << " = "; - default_value->output(default_expr_str, 0, &parser, false); - default_expr = default_expr_str.str(); - null_assign = " = nullptr"; - - // We should only ever have to consider optional arguments for functions - // taking a variable number of arguments. - nassertr(args_type == AT_varargs || args_type == AT_keyword_args, false); - } - - string reported_name = remap->_parameters[pn]._name; - if (!keyword_list_old.empty()) { - keyword_list_old += ", "; - keyword_list_new += ", "; - } - if (remap->_parameters[pn]._has_name) { - has_keywords = true; - } - keyword_list_old += "\"" + reported_name + "\""; - if (has_keywords) { - keyword_list_new += "\"" + reported_name + "\""; - } else { - // Positional-only argument. - keyword_list_new += "\"\""; - } - - if (param->new_type_is_atomic_string()) { - - if (TypeManager::is_char_pointer(orig_type)) { - indent(out, indent_level) << "char "; - if (TypeManager::is_const_char_pointer(orig_type)) { - out << "const "; - } - out << "*" << param_name << default_expr << ";\n"; - format_specifiers += "z"; - parameter_list += ", &" + param_name; - expected_params += "str"; - - } else if (TypeManager::is_wchar_pointer(orig_type)) { - out << "#if PY_VERSION_HEX >= 0x03020000\n"; - indent(out, indent_level) << "PyObject *" << param_name << null_assign << ";\n"; - out << "#else\n"; - indent(out, indent_level) << "PyUnicodeObject *" << param_name << null_assign << ";\n"; - out << "#endif\n"; - format_specifiers += "U"; - parameter_list += ", &" + param_name; - - if (is_optional) { - extra_convert - << "wchar_t *" << param_name << "_str = nullptr;\n" - << "if (" << param_name << " != nullptr) {\n" - << "#if PY_VERSION_HEX >= 0x03030000\n" - << " " << param_name << "_str = PyUnicode_AsWideCharString(" << param_name << ", nullptr);\n" - << "#else" - << "Py_ssize_t " << param_name << "_len = PyUnicode_GET_SIZE(" << param_name << ");\n" - << " " << param_name << "_str = (wchar_t *)alloca(sizeof(wchar_t) * (" + param_name + "_len + 1));\n" - << "PyUnicode_AsWideChar(" << param_name << ", " << param_name << "_str, " << param_name << "_len);\n" - << param_name << "_str[" << param_name << "_len] = 0;\n" - << "#endif\n" - << "} else {\n" - << " " << param_name << "_str" << default_expr << ";\n" - << "}\n"; - } else { - extra_convert - << "#if PY_VERSION_HEX >= 0x03030000\n" - << "wchar_t *" << param_name << "_str = PyUnicode_AsWideCharString(" << param_name << ", nullptr);\n" - << "#else" - << "Py_ssize_t " << param_name << "_len = PyUnicode_GET_SIZE(" << param_name << ");\n" - << "wchar_t *" << param_name << "_str = (wchar_t *)alloca(sizeof(wchar_t) * (" + param_name + "_len + 1));\n" - << "PyUnicode_AsWideChar(" << param_name << ", " << param_name << "_str, " << param_name << "_len);\n" - << param_name << "_str[" << param_name << "_len] = 0;\n" - << "#endif\n"; - } - - pexpr_string = param_name + "_str"; - - extra_cleanup - << "#if PY_VERSION_HEX >= 0x03030000\n" - << "PyMem_Free(" << param_name << "_str);\n" - << "#endif\n"; - - expected_params += "unicode"; - - } else if (TypeManager::is_wstring(orig_type) || - TypeManager::is_const_ptr_to_basic_string_wchar(orig_type)) { - out << "#if PY_VERSION_HEX >= 0x03020000\n"; - indent(out, indent_level) << "PyObject *" << param_name << null_assign << ";\n"; - out << "#else\n"; - indent(out, indent_level) << "PyUnicodeObject *" << param_name << null_assign << ";\n"; - out << "#endif\n"; - format_specifiers += "U"; - parameter_list += ", &" + param_name; - - if (is_optional) { - extra_convert - << "Py_ssize_t " << param_name << "_len;\n" - << "wchar_t *" << param_name << "_str = nullptr;\n" - << "std::wstring " << param_name << "_wstr;\n" - << "if (" << param_name << " != nullptr) {\n" - << "#if PY_VERSION_HEX >= 0x03030000\n" - << " " << param_name << "_str = PyUnicode_AsWideCharString(" - << param_name << ", &" << param_name << "_len);\n" - << "#else\n" - << " " << param_name << "_len = PyUnicode_GET_SIZE(" << param_name << ");\n" - << " " << param_name << "_str = (wchar_t *)alloca(sizeof(wchar_t) * (" + param_name + "_len + 1));\n" - << "PyUnicode_AsWideChar(" << param_name << ", " << param_name << "_str, " << param_name << "_len);\n" - << "#endif\n" - << " " << param_name << "_wstr.assign(" << param_name << "_str, " << param_name << "_len);\n" - << "} else {\n" - << " " << param_name << "_wstr" << default_expr << ";\n" - << "}\n"; - pexpr_string = "std::move(" + param_name + "_wstr)"; - } else { - extra_convert - << "#if PY_VERSION_HEX >= 0x03030000\n" - << "Py_ssize_t " << param_name << "_len;\n" - << "wchar_t *" << param_name << "_str = PyUnicode_AsWideCharString(" - << param_name << ", &" << param_name << "_len);\n" - << "#else\n" - << "Py_ssize_t " << param_name << "_len = PyUnicode_GET_SIZE(" << param_name << ");\n" - << "wchar_t *" << param_name << "_str = (wchar_t *)alloca(sizeof(wchar_t) * (" + param_name + "_len + 1));\n" - << "PyUnicode_AsWideChar(" << param_name << ", " << param_name << "_str, " << param_name << "_len);\n" - << "#endif\n"; - pexpr_string = param_name + "_str, " + param_name + "_len"; - } - - extra_cleanup - << "#if PY_VERSION_HEX >= 0x03030000\n" - << "PyMem_Free(" << param_name << "_str);\n" - << "#endif\n"; - - expected_params += "unicode"; - - } else { // A regular string. - if (is_optional) { - CPPExpression::Type expr_type = default_value->_type; - if (expr_type == CPPExpression::T_default_construct) { - // The default string constructor yields an empty string. - indent(out, indent_level) << "const char *" << param_name << "_str = \"\";\n"; - indent(out, indent_level) << "Py_ssize_t " << param_name << "_len = 0;\n"; - } else { - // We only get here for string literals, so this should be fine - indent(out, indent_level) << "const char *" << param_name << "_str" - << default_expr << ";\n"; - indent(out, indent_level) << "Py_ssize_t " << param_name << "_len = " - << default_value->_str.size() << ";\n"; - } - } else { - indent(out, indent_level) << "const char *" << param_name << "_str = nullptr;\n"; - indent(out, indent_level) << "Py_ssize_t " << param_name << "_len;\n"; - } - - if (args_type == AT_single_arg) { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &" - << param_name << "_len);\n"; - out << "#else\n"; // NB. PyString_AsStringAndSize also accepts a PyUnicode. - indent(out, indent_level) << "if (PyString_AsStringAndSize(arg, (char **)&" - << param_name << "_str, &" << param_name << "_len) == -1) {\n"; - indent(out, indent_level + 2) << param_name << "_str = nullptr;\n"; - indent(out, indent_level) << "}\n"; - out << "#endif\n"; - - extra_param_check << " && " << param_name << "_str != nullptr"; - } else { - format_specifiers += "s#"; - parameter_list += ", &" + param_name - + "_str, &" + param_name + "_len"; - } - - //if (TypeManager::is_const_ptr_to_basic_string_char(orig_type)) { - // pexpr_string = "&std::string(" + param_name + "_str, " + param_name + "_len)"; - //} else { - pexpr_string = param_name + "_str, " + param_name + "_len"; - //} - expected_params += "str"; - } - // Remember to clear the TypeError that any of the above methods raise. - clear_error = true; - only_pyobjects = false; - - } else if (TypeManager::is_vector_unsigned_char(type)) { - indent(out, indent_level) << "unsigned char *" << param_name << "_str = nullptr;\n"; - indent(out, indent_level) << "Py_ssize_t " << param_name << "_len;\n"; - - if (args_type == AT_single_arg) { - extra_param_check << " && PyBytes_AsStringAndSize(arg, (char **)&" - << param_name << "_str, &" << param_name << "_len) >= 0"; - } else { - format_specifiers += "\" FMTCHAR_BYTES \"#"; - parameter_list += ", &" + param_name + "_str, &" + param_name + "_len"; - } - - pexpr_string = type->get_local_name(&parser); - pexpr_string += "(" + param_name + "_str, " + param_name + "_str + " + param_name + "_len" + ")"; - expected_params += "bytes"; - - // Remember to clear the TypeError that any of the above methods raise. - clear_error = true; - only_pyobjects = false; - - } else if (TypeManager::is_scoped_enum(type)) { - if (args_type == AT_single_arg) { - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name; - if (default_value != nullptr) { - out << " = nullptr"; - } - out << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - - CPPEnumType *enum_type = (CPPEnumType *)TypeManager::unwrap(type); - //CPPType *underlying_type = enum_type->get_underlying_type(); - //underlying_type = TypeManager::unwrap_const(underlying_type); - //indent(out, indent_level); - //underlying_type->output_instance(out, param_name + "_val", &parser); - //out << default_expr << ";\n"; - extra_convert << "long " << param_name << "_val"; - - if (default_value != nullptr) { - extra_convert << " = (long)"; - default_value->output(extra_convert, 0, &parser, false); - extra_convert << - ";\nif (" << param_name << " != nullptr) {\n" - " " << param_name << "_val = Dtool_EnumValue_AsLong(" + param_name + ");\n" - "}"; - } else { - extra_convert - << ";\n" - << param_name << "_val = Dtool_EnumValue_AsLong(" + param_name + ");\n"; - } - - pexpr_string = "(" + enum_type->get_local_name(&parser) + ")" + param_name + "_val"; - expected_params += classNameFromCppName(enum_type->get_simple_name(), false); - extra_param_check << " && " << param_name << "_val != -1"; - clear_error = true; - - } else if (TypeManager::is_bool(type)) { - if (args_type == AT_single_arg) { - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name; - if (is_optional) { - CPPExpression::Result res = default_value->evaluate(); - if (res._type != CPPExpression::RT_error) { - // It's a compile-time constant. Write Py_True or Py_False. - out << " = " << (res.as_boolean() ? "Py_True" : "Py_False"); - } else { - // Select Py_True or Py_False at runtime. - out << " = ("; - default_value->output(out, 0, &parser, false); - out << ") ? Py_True : Py_False"; - } - } - out << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - pexpr_string = "(PyObject_IsTrue(" + param_name + ") != 0)"; - expected_params += "bool"; - - } else if (TypeManager::is_nullptr(type)) { - if (args_type == AT_single_arg) { - type_check = "arg == Py_None"; - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name << default_expr << ";\n"; - extra_param_check << " && " << param_name << " == Py_None"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - pexpr_string = "nullptr"; - expected_params += "NoneType"; - - } else if (TypeManager::is_char(type)) { - indent(out, indent_level) << "char *" << param_name << "_str;\n"; - indent(out, indent_level) << "Py_ssize_t " << param_name << "_len;\n"; - - format_specifiers += "s#"; - parameter_list += ", &" + param_name + "_str, &" + param_name + "_len"; - extra_param_check << " && " << param_name << "_len == 1"; - - pexpr_string = param_name + "_str[0]"; - expected_params += "char"; - only_pyobjects = false; - - } else if (TypeManager::is_wchar(type)) { - out << "#if PY_VERSION_HEX >= 0x03020000\n"; - indent(out, indent_level) << "PyObject *" << param_name << ";\n"; - out << "#else\n"; - indent(out, indent_level) << "PyUnicodeObject *" << param_name << ";\n"; - out << "#endif\n"; - format_specifiers += "U"; - parameter_list += ", &" + param_name; - - // We tell it to copy 2 characters, but make sure it only copied one, as - // a trick to check for the proper length in one go. - extra_convert << "wchar_t " << param_name << "_chars[2];\n"; - extra_param_check << " && PyUnicode_AsWideChar(" << param_name << ", " << param_name << "_chars, 2) == 1"; - - pexpr_string = param_name + "_chars[0]"; - expected_params += "unicode char"; - only_pyobjects = false; - clear_error = true; - - } else if (TypeManager::is_ssize(type)) { - indent(out, indent_level) << "Py_ssize_t " << param_name << default_expr << ";\n"; - format_specifiers += "n"; - parameter_list += ", &" + param_name; - expected_params += "int"; - only_pyobjects = false; - - } else if (TypeManager::is_size(type)) { - if (args_type == AT_single_arg) { - type_check = "PyLongOrInt_Check(arg)"; - - extra_convert << - "size_t arg_val = PyLongOrInt_AsSize_t(arg);\n" - "#ifndef NDEBUG\n" - "if (arg_val == (size_t)-1 && PyErr_Occurred()) {\n"; - error_return(extra_convert, 2, return_flags); - extra_convert << - "}\n" - "#endif\n"; - - pexpr_string = "arg_val"; - - } else { - // It certainly isn't the exact same thing as size_t, but Py_ssize_t - // should at least be the same size. The problem with mapping this to - // unsigned int is that that doesn't work well on 64-bit systems, on - // which size_t is a 64-bit integer. - indent(out, indent_level) << "Py_ssize_t " << param_name << default_expr << ";\n"; - format_specifiers += "n"; - parameter_list += ", &" + param_name; - - extra_convert - << "#ifndef NDEBUG\n" - << "if (" << param_name << " < 0) {\n"; - - error_raise_return(extra_convert, 2, return_flags, "OverflowError", - "can't convert negative value %zd to size_t", - param_name); - extra_convert - << "}\n" - << "#endif\n"; - } - expected_params += "int"; - only_pyobjects = false; - - } else if (TypeManager::is_longlong(type)) { - // It's not trivial to do overflow checking for a long long, so we - // simply don't do it. - if (TypeManager::is_unsigned_longlong(type)) { - indent(out, indent_level) << "unsigned PY_LONG_LONG " << param_name << default_expr << ";\n"; - format_specifiers += "K"; - } else { - indent(out, indent_level) << "PY_LONG_LONG " << param_name << default_expr << ";\n"; - format_specifiers += "L"; - } - parameter_list += ", &" + param_name; - expected_params += "long"; - only_pyobjects = false; - - } else if (TypeManager::is_unsigned_short(type) || - TypeManager::is_unsigned_char(type) || TypeManager::is_signed_char(type)) { - - if (args_type == AT_single_arg) { - type_check = "PyLongOrInt_Check(arg)"; - extra_convert - << "long " << param_name << " = PyLongOrInt_AS_LONG(arg);\n"; - - pexpr_string = "(" + type->get_local_name(&parser) + ")" + param_name; - } else { - indent(out, indent_level) << "long " << param_name << default_expr << ";\n"; - format_specifiers += "l"; - parameter_list += ", &" + param_name; - } - - // The "H" format code, unlike "h", does not do overflow checking, so we - // have to do it ourselves (except in release builds). - extra_convert - << "#ifndef NDEBUG\n"; - - if (TypeManager::is_unsigned_short(type)) { - extra_convert << "if (" << param_name << " < 0 || " << param_name << " > USHRT_MAX) {\n"; - error_raise_return(extra_convert, 2, return_flags, "OverflowError", - "value %ld out of range for unsigned short integer", - param_name); - } else if (TypeManager::is_unsigned_char(type)) { - extra_convert << "if (" << param_name << " < 0 || " << param_name << " > UCHAR_MAX) {\n"; - error_raise_return(extra_convert, 2, return_flags, "OverflowError", - "value %ld out of range for unsigned byte", - param_name); - } else { - extra_convert << "if (" << param_name << " < SCHAR_MIN || " << param_name << " > SCHAR_MAX) {\n"; - error_raise_return(extra_convert, 2, return_flags, "OverflowError", - "value %ld out of range for signed byte", - param_name); - } - - extra_convert - << "}\n" - << "#endif\n"; - - expected_params += "int"; - only_pyobjects = false; - - } else if (TypeManager::is_short(type)) { - if (args_type == AT_single_arg) { - type_check = "PyLongOrInt_Check(arg)"; - - // Perform overflow checking in debug builds. - extra_convert - << "long arg_val = PyLongOrInt_AS_LONG(arg);\n" - << "#ifndef NDEBUG\n" - << "if (arg_val < SHRT_MIN || arg_val > SHRT_MAX) {\n"; - - error_raise_return(extra_convert, 2, return_flags, "OverflowError", - "value %ld out of range for signed short integer", - "arg_val"); - extra_convert - << "}\n" - << "#endif\n"; - - pexpr_string = "(" + type->get_local_name(&parser) + ")arg_val"; - - } else { - indent(out, indent_level) << "short " << param_name << default_expr << ";\n"; - format_specifiers += "h"; - parameter_list += ", &" + param_name; - } - expected_params += "int"; - only_pyobjects = false; - - } else if (TypeManager::is_unsigned_integer(type)) { - if (args_type == AT_single_arg) { - // Windows has 32-bit longs, and Python 2 stores a C long for PyInt - // internally, so a PyInt wouldn't cover the whole range; that's why - // we have to accept PyLong as well here. - type_check = "PyLongOrInt_Check(arg)"; - extra_convert - << "unsigned long " << param_name << " = PyLong_AsUnsignedLong(arg);\n"; - pexpr_string = "(" + type->get_local_name(&parser) + ")" + param_name; - } else { - indent(out, indent_level) << "unsigned long " << param_name << default_expr << ";\n"; - format_specifiers += "k"; - parameter_list += ", &" + param_name; - } - - // The "I" format code, unlike "i", does not do overflow checking, so we - // have to do it ourselves (in debug builds). Note that Python 2 stores - // longs internally, for ints, so we don't do it for Python 2 on - // Windows, where longs are the same size as ints. BUG: does not catch - // negative values on Windows when going through the PyArg_ParseTuple - // case. - if (!TypeManager::is_long(type)) { - extra_convert - << "#if (SIZEOF_LONG > SIZEOF_INT) && !defined(NDEBUG)\n" - << "if (" << param_name << " > UINT_MAX) {\n"; - - error_raise_return(extra_convert, 2, return_flags, "OverflowError", - "value %lu out of range for unsigned integer", - param_name); - - extra_convert - << "}\n" - << "#endif\n"; - } - expected_params += "int"; - only_pyobjects = false; - - } else if (TypeManager::is_long(type)) { - // Signed longs are equivalent to Python's int type. - if (args_type == AT_single_arg) { - pexpr_string = "PyLongOrInt_AS_LONG(arg)"; - type_check = "PyLongOrInt_Check(arg)"; - } else { - indent(out, indent_level) << "long " << param_name << default_expr << ";\n"; - format_specifiers += "l"; - parameter_list += ", &" + param_name; - } - expected_params += "int"; - only_pyobjects = false; - - } else if (TypeManager::is_integer(type)) { - if (args_type == AT_single_arg) { - type_check = "PyLongOrInt_Check(arg)"; - - // Perform overflow checking in debug builds. Note that Python 2 - // stores longs internally, for ints, so we don't do it on Windows, - // where longs are the same size as ints. - extra_convert - << "long arg_val = PyLongOrInt_AS_LONG(arg);\n" - << "#if (SIZEOF_LONG > SIZEOF_INT) && !defined(NDEBUG)\n" - << "if (arg_val < INT_MIN || arg_val > INT_MAX) {\n"; - - error_raise_return(extra_convert, 2, return_flags, "OverflowError", - "value %ld out of range for signed integer", - "arg_val"); - - extra_convert - << "}\n" - << "#endif\n"; - - pexpr_string = "(" + type->get_local_name(&parser) + ")arg_val"; - - } else { - indent(out, indent_level) << "int " << param_name << default_expr << ";\n"; - format_specifiers += "i"; - parameter_list += ", &" + param_name; - } - expected_params += "int"; - only_pyobjects = false; - - } else if (TypeManager::is_double(type)) { - if (args_type == AT_single_arg) { - pexpr_string = "PyFloat_AsDouble(arg)"; - type_check = "PyNumber_Check(arg)"; - } else { - indent(out, indent_level) << "double " << param_name << default_expr << ";\n"; - format_specifiers += "d"; - parameter_list += ", &" + param_name; - } - expected_params += "double"; - only_pyobjects = false; - - } else if (TypeManager::is_float(type)) { - if (args_type == AT_single_arg) { - pexpr_string = "(" + type->get_local_name(&parser) + ")PyFloat_AsDouble(arg)"; - type_check = "PyNumber_Check(arg)"; - } else { - indent(out, indent_level) << "float " << param_name << default_expr << ";\n"; - format_specifiers += "f"; - parameter_list += ", &" + param_name; - } - expected_params += "float"; - only_pyobjects = false; - - } else if (TypeManager::is_const_char_pointer(type)) { - indent(out, indent_level) << "const char *" << param_name << default_expr << ";\n"; - format_specifiers += "z"; - parameter_list += ", &" + param_name; - expected_params += "buffer"; - only_pyobjects = false; - - } else if (TypeManager::is_pointer_to_PyTypeObject(type)) { - if (args_type == AT_single_arg) { - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name << default_expr << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - pexpr_string = param_name; - } - extra_param_check << " && PyType_Check(" << param_name << ")"; - pexpr_string = "(PyTypeObject *)" + param_name; - expected_params += "type"; - - // It's reasonable to assume that a function taking a PyTypeObject might - // also throw a TypeError if the type is incorrect. - may_raise_typeerror = true; - - } else if (TypeManager::is_pointer_to_PyStringObject(type)) { - if (args_type == AT_single_arg) { - // This is a single-arg function, so there's no need to convert - // anything. - param_name = "arg"; - type_check = "PyString_Check(arg)"; - pexpr_string = "(PyStringObject *)" + param_name; - } else { - indent(out, indent_level) << "PyStringObject *" << param_name << default_expr << ";\n"; - format_specifiers += "S"; - parameter_list += ", &" + param_name; - pexpr_string = param_name; - } - expected_params += "string"; - - } else if (TypeManager::is_pointer_to_PyUnicodeObject(type)) { - if (args_type == AT_single_arg) { - // This is a single-arg function, so there's no need to convert - // anything. - param_name = "arg"; - type_check = "PyUnicode_Check(arg)"; - pexpr_string = "(PyUnicodeObject *)" + param_name; - } else { - indent(out, indent_level) << "PyUnicodeObject *" << param_name << default_expr << ";\n"; - format_specifiers += "U"; - parameter_list += ", &" + param_name; - pexpr_string = param_name; - } - expected_params += "unicode"; - - } else if (TypeManager::is_pointer_to_PyObject(type)) { - if (args_type == AT_single_arg) { - // This is a single-arg function, so there's no need to convert - // anything. - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name << default_expr << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - pexpr_string = param_name; - expected_params += "object"; - - // It's reasonable to assume that a function taking a PyObject might - // also throw a TypeError if the type is incorrect. - may_raise_typeerror = true; - - } else if (TypeManager::is_pointer_to_Py_buffer(type)) { - min_version = 0x02060000; // Only support this remap in version 2.6+. - - if (args_type == AT_single_arg) { - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name << null_assign << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - indent(out, indent_level) << "Py_buffer " << param_name << "_view;\n"; - - if (is_optional) { - indent(out, indent_level) << "Py_buffer *" << param_name << "_viewp;\n"; - - extra_convert - << "bool " << param_name << "_success;\n" - << "if (" << param_name << " != nullptr) {\n" - << " " << param_name << "_success = (PyObject_GetBuffer(" - << param_name << ", &" << param_name << "_view, PyBUF_FULL) == 0);\n" - << " " << param_name << "_viewp = &" << param_name << "_view;\n" - << "} else {\n" - << " " << param_name << "_viewp" << default_expr << ";\n" - << " " << param_name << "_success = true;\n" - << "}\n"; - - extra_param_check << " && " << param_name << "_success"; - pexpr_string = param_name + "_viewp"; - extra_cleanup << "if (" << param_name << " != nullptr) PyBuffer_Release(&" << param_name << "_view);\n"; - } else { - extra_param_check << " && PyObject_GetBuffer(" - << param_name << ", &" - << param_name << "_view, PyBUF_FULL) == 0"; - pexpr_string = "&" + param_name + "_view"; - extra_cleanup << "PyBuffer_Release(&" << param_name << "_view);\n"; - } - expected_params += "buffer"; - may_raise_typeerror = true; - clear_error = true; - - } else if (TypeManager::is_pointer_to_simple(type)) { - if (args_type == AT_single_arg) { - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name << null_assign << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - indent(out, indent_level) << "Py_buffer " << param_name << "_view;\n"; - - // Unravel the type to determine its properties. - int array_len = -1; - bool is_const = true; - CPPSimpleType *simple = nullptr; - CPPType *unwrap = TypeManager::unwrap_const_reference(type); - if (unwrap != nullptr) { - CPPArrayType *array_type = unwrap->as_array_type(); - CPPPointerType *pointer_type = unwrap->as_pointer_type(); - - if (array_type != nullptr) { - if (array_type->_bounds != nullptr) { - array_len = array_type->_bounds->evaluate().as_integer(); - } - unwrap = array_type->_element_type; - } else if (pointer_type != nullptr) { - unwrap = pointer_type->_pointing_at; - } - - CPPConstType *const_type = unwrap->as_const_type(); - if (const_type != nullptr) { - unwrap = const_type->_wrapped_around; - } else { - is_const = false; - } - - while (unwrap->get_subtype() == CPPDeclaration::ST_typedef) { - unwrap = unwrap->as_typedef_type()->_type; - } - simple = unwrap->as_simple_type(); - } - - // Determine the format, so we can check the type of the buffer we get. - char format_chr = 'B'; - - switch (simple->_type) { - case CPPSimpleType::T_char: - if (simple->_flags & CPPSimpleType::F_unsigned) { - format_chr = 'B'; - } else if (simple->_flags & CPPSimpleType::F_signed) { - format_chr = 'b'; - } else { - format_chr = 'c'; - } - break; - - case CPPSimpleType::T_int: - if (simple->_flags & CPPSimpleType::F_longlong) { - format_chr = 'q'; - } else if (simple->_flags & CPPSimpleType::F_long) { - format_chr = 'l'; - } else if (simple->_flags & CPPSimpleType::F_short) { - format_chr = 'h'; - } else { - format_chr = 'i'; - } - - if (simple->_flags & CPPSimpleType::F_unsigned) { - format_chr &= 0x5f; // Uppercase - } - break; - - case CPPSimpleType::T_float: - format_chr = 'f'; - break; - - case CPPSimpleType::T_double: - format_chr = 'd'; - break; - - default: - nout << "Warning: cannot determine buffer format string for type " - << type->get_local_name(&parser) - << " (simple type " << *simple << ")\n"; - extra_param_check << " && false"; - } - - const char *flags; - if (format_chr == 'B') { - if (is_const) { - flags = "PyBUF_SIMPLE"; - } else { - flags = "PyBUF_WRITABLE"; - } - } else if (is_const) { - flags = "PyBUF_FORMAT"; - } else { - flags = "PyBUF_FORMAT | PyBUF_WRITABLE"; - } - - extra_param_check << " && PyObject_GetBuffer(" << param_name << ", &" - << param_name << "_view, " << flags << ") == 0"; - - if (format_chr != 'B') { - extra_param_check - << " && " << param_name << "_view.format[0] == '" << format_chr << "'" - << " && " << param_name << "_view.format[1] == 0"; - } - if (array_len != -1) { - extra_param_check - << " && " << param_name << "_view.len == " << array_len; - } - - pexpr_string = "(" + simple->get_local_name(&parser) + " *)" + - param_name + "_view.buf"; - - extra_cleanup << "PyBuffer_Release(&" << param_name << "_view);\n"; - expected_params += "buffer"; - clear_error = true; - - } else if (TypeManager::is_pointer(type)) { - CPPType *obj_type = TypeManager::unwrap(TypeManager::resolve_type(type)); - bool const_ok = !TypeManager::is_non_const_pointer_or_ref(orig_type); - - if (TypeManager::is_const_pointer_or_ref(orig_type)) { - expected_params += "const "; - // } else { expected_params += "non-const "; - } - string expected_class_name = classNameFromCppName(obj_type->get_simple_name(), false); - expected_params += expected_class_name; - - if (args_type == AT_single_arg) { - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name << null_assign << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - - // If the default value is NULL, we also accept a None value. - bool maybe_none = false; - if (default_value != nullptr && (return_flags & RF_coerced) == 0 && - TypeManager::is_pointer(orig_type)) { - CPPExpression::Result res = param->get_default_value()->evaluate(); - if (res._type == CPPExpression::RT_integer || - res._type == CPPExpression::RT_pointer) { - if (res.as_integer() == 0) { - maybe_none = true; - } - } - } - - string class_name = obj_type->get_local_name(&parser); - - // need to a forward scope for this class.. - if (!isExportThisRun(obj_type)) { - _external_imports.insert(TypeManager::resolve_type(obj_type)); - } - - string this_class_name; - string method_prefix; - if (remap->_cpptype) { - this_class_name = remap->_cpptype->get_simple_name(); - method_prefix = classNameFromCppName(this_class_name, false) + string("."); - } - - if (coercion_possible && - has_coerce_constructor(obj_type->as_struct_type())) { - // Call the coercion function directly, which will try to extract the - // pointer directly before trying coercion. - string coerce_call; - - if (TypeManager::is_reference_count(obj_type)) { - // We use a PointerTo to handle the management here. It's cleaner - // that way. - if (default_expr == " = 0" || default_expr == " = nullptr") { - default_expr.clear(); - } - if (TypeManager::is_const_pointer_to_anything(type)) { - extra_convert - << "CPT(" << class_name << ") " << param_name << "_this" - << default_expr << ";\n"; - - coerce_call = "Dtool_ConstCoerce_" + make_safe_name(class_name) + - "(" + param_name + ", " + param_name + "_this)"; - } else { - extra_convert - << "PT(" << class_name << ") " << param_name << "_this" - << default_expr << ";\n"; - - coerce_call = "Dtool_Coerce_" + make_safe_name(class_name) + - "(" + param_name + ", " + param_name + "_this)"; - } - - // Use move constructor when available for functions that take an - // actual PointerTo. This eliminates an unref()ref() pair. - pexpr_string = "std::move(" + param_name + "_this)"; - - } else { - // This is a move-assignable type, such as TypeHandle or LVecBase4. - obj_type->output_instance(extra_convert, param_name + "_local", &parser); - extra_convert << ";\n"; - - type->output_instance(extra_convert, param_name + "_this", &parser); - - if (is_optional && maybe_none) { - extra_convert - << default_expr << ";\n" - << "if (" << param_name << " != nullptr && " << param_name << " != Py_None) {\n" - << " " << param_name << "_this"; - } else if (is_optional) { - if (TypeManager::is_pointer(orig_type)) { - extra_convert << default_expr; - } - extra_convert - << ";\n" - << "if (" << param_name << " != nullptr) {\n" - << " " << param_name << "_this"; - } else if (maybe_none) { - extra_convert - << " = nullptr;\n" - << "if (" << param_name << " != Py_None) {\n" - << " " << param_name << "_this"; - } - - extra_convert << " = Dtool_Coerce_" + make_safe_name(class_name) + - "(" + param_name + ", " + param_name + "_local);\n"; - - if (is_optional && !TypeManager::is_pointer(orig_type)) { - extra_convert - << "} else {\n" - << " " << param_name << "_local" << default_expr << ";\n" - << " " << param_name << "_this = &" << param_name << "_local;\n" - << "}\n"; - } else if (is_optional || maybe_none) { - extra_convert << "}\n"; - } - - coerce_call = "(" + param_name + "_this != nullptr)"; - - pexpr_string = param_name + "_this"; - } - - if (report_errors) { - // We were asked to report any errors. Let's do it. - if (is_optional && maybe_none) { - extra_convert << "if (" << param_name << " != nullptr && " << param_name << " != Py_None && !" << coerce_call << ") {\n"; - } else if (is_optional) { - extra_convert << "if (" << param_name << " != nullptr && !" << coerce_call << ") {\n"; - } else if (maybe_none) { - extra_convert << "if (" << param_name << " != Py_None && !" << coerce_call << ") {\n"; - } else { - extra_convert << "if (!" << coerce_call << ") {\n"; - } - - // Display error like: Class.func() argument 0 must be A, not B - if ((return_flags & ~RF_pyobject) == RF_err_null) { - // Dtool_Raise_ArgTypeError returns NULL already - extra_convert << " return "; - } else { - extra_convert << " "; - } - extra_convert - << "Dtool_Raise_ArgTypeError(" << param_name << ", " - << pn << ", \"" << method_prefix - << methodNameFromCppName(remap, this_class_name, false) - << "\", \"" << expected_class_name << "\");\n"; - - if ((return_flags & ~RF_pyobject) != RF_err_null) { - error_return(extra_convert, 2, return_flags); - } - extra_convert << "}\n"; - - } else if (is_optional && maybe_none) { - extra_param_check << " && (" << param_name << " == nullptr || " << param_name << " == Py_None || " << coerce_call << ")"; - - } else if (is_optional) { - extra_param_check << " && (" << param_name << " == nullptr || " << coerce_call << ")"; - - } else if (maybe_none) { - extra_param_check << " && (" << param_name << " == Py_None || " << coerce_call << ")"; - - } else { - extra_param_check << " && " << coerce_call; - } - - } else { // The regular, non-coercion case. - type->output_instance(extra_convert, param_name + "_this", &parser); - if (is_optional && maybe_none) { - // This parameter has a default value of nullptr, so we need to also - // allow passing in None. - extra_convert - << default_expr << ";\n" - << "if (" << param_name << " != nullptr && " << param_name << " != Py_None) {\n" - << " " << param_name << "_this"; - } - else if (is_optional && !TypeManager::is_pointer(orig_type) && !default_value->is_lvalue()) { - // Most annoying case, where we have to use an rvalue reference to - // extend the lifetime of the default argument. In this case, the - // default expression is invoked even if not used. - extra_convert << ";\n"; - if (TypeManager::is_const_pointer_to_anything(type)) { - extra_convert << "const "; - obj_type->output_instance(extra_convert, "&" + param_name + "_ref", &parser); - } else { - obj_type->output_instance(extra_convert, "&&" + param_name + "_ref", &parser); - } - extra_convert - << default_expr << ";\n" - << "if (" << param_name << " == nullptr) {\n" - << " " << param_name << "_this = &" << param_name << "_ref;\n" - << "} else {\n" - << " " << param_name << "_this"; - } - else if (is_optional) { - // General case where the default argument is either an lvalue or a - // pointer. - extra_convert - << ";\n" - << "if (" << param_name << " == nullptr) {\n" - << " " << param_name << "_this = "; - if (TypeManager::is_pointer(orig_type)) { - default_value->output(extra_convert, 0, &parser, false); - extra_convert << ";\n"; - } else { - // The rvalue case was handled above, so this is an lvalue, which - // means we can safely take a reference to it. - extra_convert << "&("; - default_value->output(extra_convert, 0, &parser, false); - extra_convert << ");\n"; - } - extra_convert - << "} else {\n" - << " " << param_name << "_this"; - } - else if (maybe_none) { - // No default argument, but we still need to check for None. - extra_convert - << " = nullptr;\n" - << "if (" << param_name << " != Py_None) {\n" - << " " << param_name << "_this"; - } - - if (const_ok && !report_errors) { - // This function does the same thing in this case and is slightly - // simpler. But maybe we should just reorganize these functions - // entirely? - extra_convert << " = nullptr;\n"; - int indent_level = (is_optional || maybe_none) ? 2 : 0; - indent(extra_convert, indent_level) - << "DtoolInstance_GetPointer(" << param_name - << ", " << param_name << "_this" - << ", *Dtool_Ptr_" << make_safe_name(class_name) - << ");\n"; - } else { - extra_convert << std::boolalpha - << " = (" << class_name << " *)" - << "DTOOL_Call_GetPointerThisClass(" << param_name - << ", Dtool_Ptr_" << make_safe_name(class_name) - << ", " << pn << ", \"" - << method_prefix << methodNameFromCppName(remap, this_class_name, false) - << "\", " << const_ok << ", " << report_errors << ");\n"; - } - - if (is_optional && maybe_none) { - extra_convert << "}\n"; - extra_param_check << " && (" << param_name << " == nullptr || " << param_name << " == Py_None || " << param_name << "_this != nullptr)"; - } else if (is_optional) { - extra_convert << "}\n"; - extra_param_check << " && (" << param_name << " == nullptr || " << param_name << "_this != nullptr)"; - } else if (maybe_none) { - extra_convert << "}\n"; - extra_param_check << " && (" << param_name << " == Py_None || " << param_name << "_this != nullptr)"; - } else { - extra_param_check << " && " << param_name << "_this != nullptr"; - } - - pexpr_string = param_name + "_this"; - } - - } else { - // Ignore a parameter. - if (args_type == AT_single_arg) { - param_name = "arg"; - } else { - indent(out, indent_level) << "PyObject *" << param_name << ";\n"; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - expected_params += "any"; - } - - if (!reported_name.empty()) { - expected_params += " " + reported_name; - } - pexprs.push_back(pexpr_string); - } - expected_params += ")\n"; - - if (min_version > 0) { - out << "#if PY_VERSION_HEX >= 0x" << hex << min_version << dec << "\n"; - } - - // Track how many curly braces we've opened. - short open_scopes = 0; - - if (!type_check.empty() && args_type == AT_single_arg) { - indent(out, indent_level) - << "if (" << type_check << ") {\n"; - - ++open_scopes; - indent_level += 2; - - } else if (!format_specifiers.empty()) { - string method_name = methodNameFromCppName(remap, "", false); - - switch (args_type) { - case AT_keyword_args: - // Wrapper takes a varargs tuple and a keyword args dict. - if (has_keywords) { - if (only_pyobjects && max_num_args == 1) { - // But we are only expecting one object arg, which is an easy common - // case we have implemented ourselves. - if (min_num_args == 1) { - indent(out, indent_level) - << "if (Dtool_ExtractArg(&" << param_name << ", args, kwds, " << keyword_list_new << ")) {\n"; - } else { - indent(out, indent_level) - << "if (Dtool_ExtractOptionalArg(&" << param_name << ", args, kwds, " << keyword_list_new << ")) {\n"; - } - } else { - // We have to use the more expensive PyArg_ParseTupleAndKeywords. - clear_error = true; - if (keyword_list_new != keyword_list_old) { - out << "#if PY_VERSION_HEX >= 0x03060000\n"; - indent(out, indent_level) - << "static const char *keyword_list[] = {" << keyword_list_new << ", nullptr};\n"; - out << "#else\n"; - indent(out, indent_level) - << "static const char *keyword_list[] = {" << keyword_list_old << ", nullptr};\n"; - out << "#endif\n"; - } else { - indent(out, indent_level) - << "static const char *keyword_list[] = {" << keyword_list_new << ", nullptr};\n"; - } - indent(out, indent_level) - << "if (PyArg_ParseTupleAndKeywords(args, kwds, \"" - << format_specifiers << ":" << method_name - << "\", (char **)keyword_list" << parameter_list << ")) {\n"; - } - - } else if (only_pyobjects) { - // This function actually has no named parameters, so let's not take - // any keyword arguments. - if (max_num_args == 1) { - if (min_num_args == 1) { - indent(out, indent_level) - << "if (Dtool_ExtractArg(&" << param_name << ", args, kwds)) {\n"; - } else { - indent(out, indent_level) - << "if (Dtool_ExtractOptionalArg(&" << param_name << ", args, kwds)) {\n"; - } - } else if (max_num_args == 0) { - indent(out, indent_level) - << "if (Dtool_CheckNoArgs(args, kwds)) {\n"; - } else { - clear_error = true; - indent(out, indent_level) - << "if ((kwds == nullptr || PyDict_Size(kwds) == 0) && PyArg_UnpackTuple(args, \"" - << methodNameFromCppName(remap, "", false) - << "\", " << min_num_args << ", " << max_num_args - << parameter_list << ")) {\n"; - } - - } else { - clear_error = true; - indent(out, indent_level) - << "if ((kwds == nullptr || PyDict_Size(kwds) == 0) && PyArg_ParseTuple(args, \"" - << format_specifiers << ":" << method_name - << "\"" << parameter_list << ")) {\n"; - } - - ++open_scopes; - indent_level += 2; - break; - - case AT_varargs: - // Wrapper takes a varargs tuple. - if (only_pyobjects) { - // All parameters are PyObject*, so we can use the slightly more - // efficient PyArg_UnpackTuple function instead. - if (min_num_args == 1 && max_num_args == 1) { - indent(out, indent_level) - << "if (PyTuple_GET_SIZE(args) == 1) {\n"; - indent(out, indent_level + 2) - << param_name << " = PyTuple_GET_ITEM(args, 0);\n"; - } else { - clear_error = true; - indent(out, indent_level) - << "if (PyArg_UnpackTuple(args, \"" - << methodNameFromCppName(remap, "", false) - << "\", " << min_num_args << ", " << max_num_args - << parameter_list << ")) {\n"; - } - - } else { - clear_error = true; - indent(out, indent_level) - << "if (PyArg_ParseTuple(args, \"" - << format_specifiers << ":" << method_name - << "\"" << parameter_list << ")) {\n"; - } - ++open_scopes; - indent_level += 2; - break; - - case AT_single_arg: - // Single argument. If not a PyObject*, use PyArg_Parse. - if (!only_pyobjects && format_specifiers != "O") { - indent(out, indent_level) - << "if (PyArg_Parse(arg, \"" << format_specifiers << ":" - << method_name << "\"" << parameter_list << ")) {\n"; - - ++open_scopes; - clear_error = true; - indent_level += 2; - } - - default: - break; - } - } - - while (extra_convert.is_text_available()) { - string line = extra_convert.get_line(); - if (line.size() == 0 || line[0] == '#') { - out << line << "\n"; - } else { - indent(out, indent_level) << line << "\n"; - } - } - - string extra_param_check_str = extra_param_check.str(); - if (!extra_param_check_str.empty()) { - indent(out, indent_level) - << "if (" << extra_param_check_str.substr(4) << ") {\n"; - - ++open_scopes; - indent_level += 2; - } - - bool init_self_member = is_constructor && - (return_flags & RF_coerced) == 0 && - has_self_member(remap->_cpptype->as_struct_type()); - - if (init_self_member || (is_constructor && !remap->_has_this && - (remap->_flags & FunctionRemap::F_explicit_self) != 0)) { - // If we'll be passing "self" to the constructor, we need to pre- - // initialize it here. Unfortunately, we can't pre-load the "this" - // pointer, but the constructor itself can do this. - - CPPType *orig_type = remap->_return_type->get_orig_type(); - TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)), false); - const InterrogateType &itype = idb->get_type(type_index); - - indent(out, indent_level) - << "// Pre-initialize self for the constructor\n"; - - if (!is_constructor || (return_flags & RF_int) == 0) { - // This is not a constructor, but somehow we landed up here at a static - // method requiring a 'self' pointer. This happens in coercion - // constructors in particular. We'll have to create a temporary - // PyObject instance to pass to it. - - indent(out, indent_level) - << "PyObject *self = Dtool_new_" - << make_safe_name(itype.get_scoped_name()) << "(&" - << CLASS_PREFIX << make_safe_name(itype.get_scoped_name()) - << "._PyType, nullptr, nullptr);\n"; - - extra_cleanup << "PyObject_Del(self);\n"; - } else { - // XXX rdb: this isn't needed, is it, because tp_new already initializes - // the instance? - indent(out, indent_level) - << "DTool_PyInit_Finalize(self, nullptr, &" - << CLASS_PREFIX << make_safe_name(itype.get_scoped_name()) - << ", false, false);\n"; - } - } - - string return_expr; - - if (remap->_blocking) { - // With SIMPLE_THREADS, it's important that we never release the - // interpreter lock. - out << "#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)\n"; - indent(out, indent_level) - << "PyThreadState *_save;\n"; - indent(out, indent_level) - << "Py_UNBLOCK_THREADS\n"; - out << "#endif // HAVE_THREADS && !SIMPLE_THREADS\n"; - } - if (track_interpreter) { - indent(out, indent_level) << "in_interpreter = 0;\n"; - } - - // If the function returns a pointer that we may need to manage, we store it - // in a temporary return_value variable and set this to true. - bool manage_return = false; - - if (remap->_return_type->new_type_is_atomic_string()) { - // Treat strings as a special case. We don't want to format the return - // expression. - return_expr = remap->call_function(out, indent_level, false, container, pexprs); - CPPType *type = remap->_return_type->get_orig_type(); - indent(out, indent_level); - type->output_instance(out, "return_value", &parser); - out << " = " << return_expr << ";\n"; - manage_return = remap->_return_value_needs_management; - return_expr = "return_value"; - - } else if ((return_flags & RF_coerced) != 0 && !TypeManager::is_reference_count(remap->_cpptype)) { - // Another special case is the coerce constructor for a trivial type. We - // don't want to invoke "operator new" unnecessarily. - if (is_constructor && remap->_extension) { - // Extension constructors are a special case, as usual. - indent(out, indent_level) - << remap->get_call_str("&coerced", pexprs) << ";\n"; - - } else { - indent(out, indent_level) - << "coerced = " << remap->get_call_str(container, pexprs) << ";\n"; - } - return_expr = "&coerced"; - - } else if (is_constructor && (return_flags & RF_coerced) == 0 && - is_python_subclassable(remap->_cpptype->as_struct_type())) { - // Add special code to detect whether we're trying to create a subclass - // of this object. If so, create a proxy instance instead. - CPPType *orig_type = remap->_return_type->get_orig_type(); - TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)), false); - const InterrogateType &itype = idb->get_type(type_index); - std::string safe_name = make_safe_name(itype.get_scoped_name()); - - CPPType *type = remap->_return_type->get_temporary_type(); - type->output_instance(indent(out, indent_level), "return_value", &parser); - out << ";\n"; - - indent(out, indent_level) - << "if (Py_TYPE(self) != &Dtool_" << safe_name << "._PyType) {\n"; - indent(out, indent_level) - << " DtoolProxy_" << safe_name << " *proxy = new DtoolProxy_" << safe_name << "("; - remap->write_call_args(out, pexprs); - out << ");\n"; - indent(out, indent_level) - << " DtoolProxy_Init(proxy, self, Dtool_" << safe_name << ", &Dtool_WrapProxy_" << safe_name << ");\n"; - indent(out, indent_level) - << " return_value = proxy;\n"; - indent(out, indent_level) - << "} else {\n"; - - return_expr = remap->call_function(out, indent_level, true, container, pexprs); - indent(out, indent_level) - << " return_value = " << return_expr << ";\n"; - indent(out, indent_level) - << "}\n"; - - return_expr = "return_value"; - manage_return = true; - - } else { - // The general case; an ordinary constructor or function. - return_expr = remap->call_function(out, indent_level, true, container, pexprs); - - if ((return_flags & RF_self) != 0) { - if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) { - // If the function returns a PyObject *, let it override the default - // behavior of returning self. - return_flags = (return_flags & ~RF_self) | RF_pyobject; - } else { - // We won't be using the return value, anyway. - return_expr.clear(); - } - } - - if (!return_expr.empty()) { - manage_return = remap->_return_value_needs_management; - CPPType *type = remap->_return_type->get_temporary_type(); - indent(out, indent_level); - type->output_instance(out, "return_value", &parser); - out << " = " << return_expr << ";\n"; - return_expr = "return_value"; - } - } - - // Clean up any memory we might have allocate for parsing the parameters. - while (extra_cleanup.is_text_available()) { - string line = extra_cleanup.get_line(); - if (line.size() == 0 || line[0] == '#') { - out << line << "\n"; - } else { - indent(out, indent_level) << line << "\n"; - } - } - - if (track_interpreter) { - indent(out, indent_level) << "in_interpreter = 1;\n"; - } - if (remap->_blocking) { - out << "#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)\n"; - indent(out, indent_level) - << "Py_BLOCK_THREADS\n"; - out << "#endif // HAVE_THREADS && !SIMPLE_THREADS\n"; - } - - if (manage_return) { - // If a constructor returns NULL, that means allocation failed. - if (remap->_return_type->return_value_needs_management()) { - indent(out, indent_level) << "if (return_value == nullptr) {\n"; - if ((return_flags & ~RF_pyobject) == RF_err_null) { - // PyErr_NoMemory returns NULL, so allow tail call elimination. - indent(out, indent_level) << " return PyErr_NoMemory();\n"; - } else { - indent(out, indent_level) << " PyErr_NoMemory();\n"; - error_return(out, indent_level + 2, return_flags); - } - indent(out, indent_level) << "}\n"; - } - - if (init_self_member) { - indent(out, indent_level) - << "return_value->__self__ = Py_NewRef(self);\n"; - } - - if (TypeManager::is_pointer_to_PyObject(remap->_return_type->get_orig_type())) { - return_expr = "Py_XNewRef(return_value)"; - } else { - return_expr = manage_return_value(out, indent_level, remap, "return_value"); - } - return_expr = remap->_return_type->temporary_to_return(return_expr); - } - - // How could we raise a TypeError if we don't take any args? - if (args_type == AT_no_args || max_num_args == 0) { - may_raise_typeerror = false; - } - - // If a function takes a PyObject* argument, it would be a good idea to - // always check for exceptions. - if (may_raise_typeerror) { - check_exceptions = true; - } - - // Generated getters and setters don't raise exceptions or asserts since - // they don't contain any code. - if (remap->_type == FunctionRemap::T_getter || - remap->_type == FunctionRemap::T_setter) { - check_exceptions = false; - } - - // The most common case of the below logic is consolidated in a single - // function, as another way to reduce code bloat. Sigh. - if (check_exceptions && (!may_raise_typeerror || report_errors) && - watch_asserts && (return_flags & RF_coerced) == 0) { - - if (return_flags & RF_decref_args) { - indent(out, indent_level) << "Py_DECREF(args);\n"; - return_flags &= ~RF_decref_args; - } - - // An even specialer special case for functions with void return or bool - // return. We have our own functions that do all this in a single - // function call, so it should reduce the amount of code output while not - // being any slower. - bool return_null = (return_flags & RF_pyobject) != 0 && - (return_flags & RF_err_null) != 0 && - (return_flags & RF_richcompare_zero) == 0; - if (return_null && return_expr.empty()) { - indent(out, indent_level) - << "return Dtool_Return_None();\n"; - - // Reset the return value bit so that the code below doesn't generate - // the return statement a second time. - return_flags &= ~RF_pyobject; - - } else if (return_null && TypeManager::is_bool(remap->_return_type->get_new_type())) { - if (return_flags & RF_invert_bool) { - indent(out, indent_level) - << "return Dtool_Return_Bool(!(" << return_expr << "));\n"; - } else { - indent(out, indent_level) - << "return Dtool_Return_Bool(" << return_expr << ");\n"; - } - return_flags &= ~RF_pyobject; - - } else if (return_null && TypeManager::is_pointer_to_PyObject(remap->_return_type->get_new_type())) { - indent(out, indent_level) - << "return Dtool_Return(" << return_expr << ");\n"; - return_flags &= ~RF_pyobject; - - } else { - indent(out, indent_level) - << "if (Dtool_CheckErrorOccurred()) {\n"; - - if (manage_return) { - delete_return_value(out, indent_level + 2, remap, return_expr); - } - error_return(out, indent_level + 2, return_flags); - - indent(out, indent_level) << "}\n"; - } - - } else { - if (check_exceptions) { - // Check if a Python exception has occurred. We only do this when - // check_exception is set. If report_errors is set, this method must - // terminate on error. - if (!may_raise_typeerror || report_errors) { - indent(out, indent_level) - << "if (PyErr_Occurred()) {\n"; - } else { - // If a method is some extension method that takes a PyObject*, and it - // raised a TypeError, continue. The documentation tells us not to - // compare the result of PyErr_Occurred against a specific exception - // type. However, in our case, this seems okay because we know that - // the TypeError we want to catch here is going to be generated by a - // PyErr_SetString call, not by user code. - indent(out, indent_level) - << "PyObject *exception = PyErr_Occurred();\n"; - indent(out, indent_level) - << "if (exception == PyExc_TypeError) {\n"; - indent(out, indent_level) - << " // TypeError raised; continue to next overload type.\n"; - indent(out, indent_level) - << "} else if (exception != nullptr) {\n"; - } - - if (manage_return) { - delete_return_value(out, indent_level + 2, remap, return_expr); - } - - error_return(out, indent_level + 2, return_flags); - - indent(out, indent_level) - << "} else {\n"; - - ++open_scopes; - indent_level += 2; - } - - if (return_flags & RF_decref_args) { - indent(out, indent_level) << "Py_DECREF(args);\n"; - return_flags &= ~RF_decref_args; - } - - // Outputs code to check to see if an assertion has failed while the C++ - // code was executing, and report this failure back to Python. Don't do - // this for coercion constructors since they are called by other wrapper - // functions which already check this on their own. Generated getters - // obviously can't raise asserts. - if (watch_asserts && (return_flags & (RF_coerced | RF_raise_keyerror)) == 0 && - remap->_type != FunctionRemap::T_getter && - remap->_type != FunctionRemap::T_setter) { - out << "#ifndef NDEBUG\n"; - indent(out, indent_level) - << "Notify *notify = Notify::ptr();\n"; - indent(out, indent_level) - << "if (UNLIKELY(notify->has_assert_failed())) {\n"; - - if (manage_return) { - // Output code to delete any temporary object we may have allocated. - delete_return_value(out, indent_level + 2, remap, return_expr); - } - - if (return_flags & RF_err_null) { - // This function returns NULL, so we can pass it on. - indent(out, indent_level + 2) - << "return Dtool_Raise_AssertionError();\n"; - } else { - indent(out, indent_level + 2) - << "Dtool_Raise_AssertionError();\n"; - error_return(out, indent_level + 2, return_flags); - } - - indent(out, indent_level) - << "}\n"; - out << "#endif\n"; - } - } - - // Okay, we're past all the error conditions and special cases. Now return - // the return type in the way that was requested. - if ((return_flags & RF_int) != 0 && (return_flags & RF_raise_keyerror) == 0) { - CPPType *orig_type = remap->_return_type->get_orig_type(); - if (is_constructor) { - // Special case for constructor. - TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)), false); - const InterrogateType &itype = idb->get_type(type_index); - indent(out, indent_level) - << "return DTool_PyInit_Finalize(self, (void *)" << return_expr << ", &" << CLASS_PREFIX << make_safe_name(itype.get_scoped_name()) << ", true, false);\n"; - - } else if (TypeManager::is_bool(orig_type)) { - // It's an error return boolean, I guess. Return 0 on success. - indent(out, indent_level) << "return (" << return_expr << ") ? 0 : -1;\n"; - - } else if (TypeManager::is_integer(orig_type)) { - if ((return_flags & RF_compare) == RF_compare) { - // Make sure it returns -1, 0, or 1, or Python complains with: - // RuntimeWarning: tp_compare didn't return -1, 0 or 1 - indent(out, indent_level) << "return (int)(" << return_expr << " > 0) - (int)(" << return_expr << " < 0);\n"; - } else { - indent(out, indent_level) << "return " << return_expr << ";\n"; - } - - } else if (TypeManager::is_void(orig_type)) { - indent(out, indent_level) << "return 0;\n"; - - } else { - nout << "Warning: function has return type " << *orig_type - << ", expected int or void:\n" << expected_params << "\n"; - indent(out, indent_level) << "// Don't know what to do with return type " - << *orig_type << ".\n"; - indent(out, indent_level) << "return 0;\n"; - } - - } else if (return_flags & RF_self) { - indent(out, indent_level) << "return Py_NewRef(self);\n"; - - } else if (return_flags & RF_richcompare_zero) { - indent(out, indent_level) - << "Py_RETURN_RICHCOMPARE(" << return_expr << ", 0, op);\n"; - - } else if (return_flags & RF_pyobject) { - if (return_expr.empty()) { - indent(out, indent_level) << "return Py_NewRef(Py_None);\n"; - - } else if (return_flags & RF_preserve_null) { - indent(out, indent_level) << "if (" << return_expr << " == nullptr) {\n"; - indent(out, indent_level) << " return nullptr;\n"; - indent(out, indent_level) << "} else {\n"; - pack_return_value(out, indent_level + 2, remap, return_expr, return_flags); - indent(out, indent_level) << "}\n"; - - } else { - pack_return_value(out, indent_level, remap, return_expr, return_flags); - } - - } else if (return_flags & RF_coerced) { - // We were asked to assign the result to a "coerced" reference. - CPPType *return_type = remap->_cpptype; - CPPType *orig_type = remap->_return_type->get_orig_type(); - - // Special case for static make function that returns a pointer: cast the - // pointer to the right pointer type. - if (!is_constructor && (remap->_flags & FunctionRemap::F_coerce_constructor) != 0 && - (TypeManager::is_pointer(orig_type) || TypeManager::is_pointer_to_base(orig_type))) { - - CPPType *new_type = remap->_return_type->get_new_type(); - - if (TypeManager::is_const_pointer_to_anything(new_type)) { - return_type = CPPType::new_type(new CPPConstType(return_type)); - } - - if (IsPandaTypedObject(return_type->as_struct_type())) { - return_expr = "DCAST(" - + return_type->get_local_name(&parser) - + ", " + return_expr + ")"; - - } else { - return_type = CPPType::new_type(new CPPPointerType(return_type)); - return_expr = "(" + return_type->get_local_name(&parser) + - ") " + return_expr; - } - } - - if (return_expr == "coerced") { - // We already did this earlier... - indent(out, indent_level) << "return true;\n"; - - } else if (TypeManager::is_reference_count(remap->_cpptype)) { - indent(out, indent_level) << "coerced = std::move(" << return_expr << ");\n"; - indent(out, indent_level) << "return true;\n"; - - } else { - indent(out, indent_level) << "return &coerced;\n"; - } - - } else if (return_flags & RF_raise_keyerror) { - CPPType *orig_type = remap->_return_type->get_orig_type(); - - if (TypeManager::is_bool(orig_type) || TypeManager::is_pointer(orig_type)) { - indent(out, indent_level) << "if (!" << return_expr << ") {\n"; - } else if (TypeManager::is_unsigned_integer(orig_type)) { - indent(out, indent_level) << "if ((int)" << return_expr << " == -1) {\n"; - } else if (TypeManager::is_integer(orig_type)) { - indent(out, indent_level) << "if (" << return_expr << " < 0) {\n"; - } else { - indent(out, indent_level) << "if (false) {\n"; - } - - if (args_type == AT_single_arg) { - indent(out, indent_level) << " PyErr_SetObject(PyExc_KeyError, arg);\n"; - } else { - indent(out, indent_level) << " PyErr_SetObject(PyExc_KeyError, key);\n"; - } - error_return(out, indent_level + 2, return_flags); - indent(out, indent_level) << "}\n"; - } - - // If we were in a scope - bool always_returns = true; - if (open_scopes > 0) { - always_returns = false; - - // Close the extra braces opened earlier. - while (open_scopes > 0) { - indent_level -= 2; - indent(out, indent_level) << "}\n"; - - --open_scopes; - } - } - - if (clear_error && !report_errors) { - // We were asked not to report errors, so clear the active exception if - // this overload might have raised a TypeError. - indent(out, indent_level) << "PyErr_Clear();\n"; - } - - if (min_version > 0) { - // Close the #if PY_VERSION_HEX check. - out << "#endif\n"; - always_returns = false; - } - - return always_returns; -} - -/** - * Outputs the correct return statement that should be used in case of error - * based on the ReturnFlags. - */ -void InterfaceMakerPythonNative:: -error_return(ostream &out, int indent_level, int return_flags) { - // if (return_flags & RF_coerced) { indent(out, indent_level) << "coerced = - // NULL;\n"; } - - if (return_flags & RF_decref_args) { - indent(out, indent_level) << "Py_DECREF(args);\n"; - } - - if (return_flags & RF_int) { - indent(out, indent_level) << "return -1;\n"; - - } else if (return_flags & RF_err_notimplemented) { - indent(out, indent_level) << "return Py_NewRef(Py_NotImplemented);\n"; - - } else if (return_flags & RF_err_null) { - indent(out, indent_level) << "return nullptr;\n"; - - } else if (return_flags & RF_err_false) { - indent(out, indent_level) << "return false;\n"; - } -} - -/** - * Similar to error_return, except raises a "bad arguments" error before - * returning, if the error indicator has not yet been set. - */ -void InterfaceMakerPythonNative:: -error_bad_args_return(ostream &out, int indent_level, int return_flags, - const string &expected_params) { - - if (return_flags & RF_decref_args) { - indent(out, indent_level) << "Py_DECREF(args);\n"; - } - - if ((return_flags & RF_err_null) != 0 && - (return_flags & RF_pyobject) != 0) { - // It always returns nullptr, so we'll allow the compiler to do a tail - // call optimization. - indent(out, indent_level) << "return Dtool_Raise_BadArgumentsError(\n"; - output_quoted(out, indent_level + 2, expected_params); - out << ");\n"; - return; - } - - if (return_flags & RF_int) { - // Same, but for -1. - indent(out, indent_level) << "return Dtool_Raise_BadArgumentsError_Int(\n"; - output_quoted(out, indent_level + 2, expected_params); - out << ");\n"; - return; - } - - indent(out, indent_level) << "Dtool_Raise_BadArgumentsError(\n"; - output_quoted(out, indent_level + 2, expected_params); - out << ");\n"; - - if (return_flags & RF_int) { - indent(out, indent_level) << "return -1;\n"; - - } else if (return_flags & RF_err_notimplemented) { - indent(out, indent_level) << "return Py_NewRef(Py_NotImplemented);\n"; - - } else if (return_flags & RF_err_null) { - indent(out, indent_level) << "return nullptr;\n"; - - } else if (return_flags & RF_err_false) { - indent(out, indent_level) << "return false;\n"; - } -} - -/** - * Similar to error_return, except raises an exception before returning. If - * format_args are not the empty string, uses PyErr_Format instead of - * PyErr_SetString. - */ -void InterfaceMakerPythonNative:: -error_raise_return(ostream &out, int indent_level, int return_flags, - const string &exc_type, const string &message, - const string &format_args) { - - if (return_flags & RF_decref_args) { - indent(out, indent_level) << "Py_DECREF(args);\n"; - return_flags &= ~RF_decref_args; - } - - if (format_args.empty()) { - if (exc_type == "TypeError") { - if ((return_flags & RF_err_null) != 0) { - // This is probably an over-optimization, but why the heck not. - indent(out, indent_level) << "return Dtool_Raise_TypeError("; - output_quoted(out, indent_level + 29, message, false); - out << ");\n"; - return; - } else { - indent(out, indent_level) << "Dtool_Raise_TypeError("; - output_quoted(out, indent_level + 22, message, false); - out << ");\n"; - } - } else { - indent(out, indent_level) << "PyErr_SetString(PyExc_" << exc_type << ",\n"; - output_quoted(out, indent_level + 16, message); - out << ");\n"; - } - - } else if ((return_flags & RF_err_null) != 0 && - (return_flags & RF_pyobject) != 0) { - // PyErr_Format always returns NULL. Passing it on directly allows the - // compiler to make a tiny optimization, so why not. - indent(out, indent_level) << "return PyErr_Format(PyExc_" << exc_type << ",\n"; - output_quoted(out, indent_level + 20, message); - out << ",\n"; - indent(out, indent_level + 20) << format_args << ");\n"; - return; - - } else { - indent(out, indent_level) << "PyErr_Format(PyExc_" << exc_type << ",\n"; - output_quoted(out, indent_level + 13, message); - out << ",\n"; - indent(out, indent_level + 13) << format_args << ");\n"; - } - - error_return(out, indent_level, return_flags); -} - -/** - * Outputs a command to pack the indicated expression, of the return_type - * type, as a Python return value. - */ -void InterfaceMakerPythonNative:: -pack_return_value(ostream &out, int indent_level, FunctionRemap *remap, - string return_expr, int return_flags) { - - ParameterRemap *return_type = remap->_return_type; - CPPType *orig_type = return_type->get_orig_type(); - CPPType *type = return_type->get_new_type(); - - if (TypeManager::is_scoped_enum(type)) { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)), false); - const InterrogateType &itype = idb->get_type(type_index); - string safe_name = make_safe_name(itype.get_scoped_name()); - - indent(out, indent_level) - << "return PyObject_CallFunction((PyObject *)Dtool_Ptr_" << safe_name; - - CPPType *underlying_type = ((CPPEnumType *)itype._cpptype)->get_underlying_type(); - if (TypeManager::is_unsigned_integer(underlying_type)) { - out << ", \"k\", (unsigned long)"; - } else { - out << ", \"l\", (long)"; - } - out << "(" << return_expr << "));\n"; - - } else if (return_type->new_type_is_atomic_string() || - TypeManager::is_simple(type) || - TypeManager::is_char_pointer(type) || - TypeManager::is_wchar_pointer(type) || - TypeManager::is_pointer_to_PyObject(type) || - TypeManager::is_pointer_to_Py_buffer(type) || - TypeManager::is_vector_unsigned_char(type)) { - // Most types are now handled by the many overloads of Dtool_WrapValue, - // defined in py_panda.h. - if (return_flags & RF_invert_bool) { - indent(out, indent_level) - << "return Dtool_WrapValue(!(" << return_expr << "));\n"; - } - else { - indent(out, indent_level) - << "return Dtool_WrapValue(" << return_expr << ");\n"; - } - } else if (TypeManager::is_pointer(type)) { - bool is_const = TypeManager::is_const_pointer_to_anything(type); - bool owns_memory = remap->_return_value_needs_management; - - // Note, we don't check for NULL here any more. This is now done by the - // appropriate CreateInstance(Typed) function. - - if (manage_reference_counts && TypeManager::is_pointer_to_base(orig_type)) { - // Use a trick to transfer the reference count to avoid a pair of - // unnecessary ref() and unref() calls. Ideally we'd use move - // semantics, but py_panda.cxx cannot make use of PointerTo. - indent(out, indent_level) << "// Transfer ownership of return_value.\n"; - indent(out, indent_level); - type->output_instance(out, "return_ptr", &parser); - out << " = " << return_expr << ";\n"; - indent(out, indent_level) << "return_value.cheat() = nullptr;\n"; - return_expr = "return_ptr"; - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - if (TypeManager::is_struct(orig_type) || TypeManager::is_ref_to_anything(orig_type)) { - if (TypeManager::is_ref_to_anything(orig_type) || remap->_manage_reference_count) { - TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(type)),false); - const InterrogateType &itype = idb->get_type(type_index); - - write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const); - - } else { - TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)),false); - const InterrogateType &itype = idb->get_type(type_index); - - write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const); - } - } else if (TypeManager::is_struct(orig_type->remove_pointer())) { - TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)),false); - const InterrogateType &itype = idb->get_type(type_index); - - write_python_instance(out, indent_level, return_expr, owns_memory, itype, is_const); - - } else { - indent(out, indent_level) << "Should Never Reach This InterfaceMakerPythonNative::pack_python_value"; - // << "return Dtool_Integer((int) " << return_expr << ");\n"; - } - - } else { - // Return None. - indent(out, indent_level) - << "return Py_BuildValue(\"\"); // Don't know how to wrap type.\n"; - } -} - -/** - * Generates the synthetic method described by the MAKE_SEQ() macro. - */ -void InterfaceMakerPythonNative:: -write_make_seq(ostream &out, Object *obj, const std::string &ClassName, - const std::string &cClassName, MakeSeq *make_seq) { - - out << "/*\n" - " * Python make_seq wrapper\n" - " */\n"; - - out << "static PyObject *" << make_seq->_name + "(PyObject *self, PyObject *) {\n"; - - // This used to return a list. But it should really be a tuple, I think, - // because it probably makes more sense for it to be immutable (as changes - // to it won't be visible on the C++ side anyway). - - FunctionRemap *remap = make_seq->_length_getter->_remaps.front(); - vector_string pexprs; - - if (make_seq->_length_getter->_has_this) { - out << - " " << cClassName << " *local_this = nullptr;\n" - " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n" - " return nullptr;\n" - " }\n" - " Py_ssize_t count = (Py_ssize_t)" << remap->get_call_str("local_this", pexprs) << ";\n"; - } else { - out << " Py_ssize_t count = (Py_ssize_t)" << remap->get_call_str("", pexprs) << ";\n"; - } - - Function *elem_getter = make_seq->_element_getter; - - if ((elem_getter->_args_type & AT_varargs) == AT_varargs) { - // Fast way to create a temporary tuple to hold only a single item, under - // the assumption that the called method doesn't do anything with this - // tuple other than unpack it (which is a fairly safe assumption to make). - out << " PyTupleObject args;\n"; - out << " (void)PyObject_INIT_VAR((PyVarObject *)&args, &PyTuple_Type, 1);\n"; - } - - out << - " PyObject *tuple = PyTuple_New(count);\n" - "\n" - " for (Py_ssize_t i = 0; i < count; ++i) {\n" - " PyObject *index = Dtool_WrapValue(i);\n"; - - switch (elem_getter->_args_type) { - case AT_keyword_args: - out << " PyTuple_SET_ITEM(&args, 0, index);\n" - " PyObject *value = " << elem_getter->_name << "(self, (PyObject *)&args, nullptr);\n"; - break; - - case AT_varargs: - out << " PyTuple_SET_ITEM(&args, 0, index);\n" - " PyObject *value = " << elem_getter->_name << "(self, (PyObject *)&args);\n"; - break; - - case AT_single_arg: - out << " PyObject *value = " << elem_getter->_name << "(self, index);\n"; - break; - - default: - out << " PyObject *value = " << elem_getter->_name << "(self, nullptr);\n"; - break; - } - - out << - " PyTuple_SET_ITEM(tuple, i, value);\n" - " Py_DECREF(index);\n" - " }\n" - "\n"; - - if ((elem_getter->_args_type & AT_varargs) == AT_varargs) { - out << "#if defined(Py_TRACE_REFS) || PY_VERSION_HEX < 0x03090000\n"; - out << " _Py_ForgetReference((PyObject *)&args);\n"; - out << "#endif\n"; - } - - out << - " if (Dtool_CheckErrorOccurred()) {\n" - " Py_DECREF(tuple);\n" - " return nullptr;\n" - " }\n" - " return tuple;\n" - "}\n" - "\n"; -} - -/** - * Generates the synthetic method described by the MAKE_PROPERTY() macro. - */ -void InterfaceMakerPythonNative:: -write_getset(ostream &out, Object *obj, Property *property) { - // We keep around this empty vector for passing to get_call_str. - const vector_string pexprs; - - string ClassName = make_safe_name(obj->_itype.get_scoped_name()); - std::string cClassName = obj->_itype.get_true_name(); - - const InterrogateElement &ielem = property->_ielement; - - FunctionRemap *len_remap = nullptr; - if (property->_length_function != nullptr) { - assert(!property->_length_function->_remaps.empty()); - - // This is actually a sequence. Wrap this with a special class. - len_remap = property->_length_function->_remaps.front(); - - out << "/**\n" - " * sequence length function for property " << ielem.get_scoped_name() << "\n" - " */\n" - "static Py_ssize_t Dtool_" + ClassName + "_" + ielem.get_name() + "_Len(PyObject *self) {\n"; - if (property->_length_function->_has_this) { - out << - " " << cClassName << " *local_this = nullptr;\n" - " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n" - " return -1;\n" - " }\n" - " return (Py_ssize_t)" << len_remap->get_call_str("local_this", pexprs) << ";\n"; - } else { - out << " return (Py_ssize_t)" << len_remap->get_call_str("", pexprs) << ";\n"; - } - out << "}\n\n"; - } - - if (property->_getter_remaps.empty()) { - return; - } - - if (ielem.is_sequence()) { - assert(len_remap != nullptr); - out << - "/**\n" - " * sequence getter for property " << ielem.get_scoped_name() << "\n" - " */\n" - "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Sequence_Getitem(PyObject *self, Py_ssize_t index) {\n"; - - if (property->_has_this) { - out << - " " << cClassName << " *local_this = nullptr;\n" - " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n" - " return nullptr;\n" - " }\n"; - } - - // This is a getitem of a sequence type. This means we *need* to raise - // IndexError if we're out of bounds. - out << " if (index < 0 || index >= (Py_ssize_t)" - << len_remap->get_call_str("local_this", pexprs) << ") {\n"; - out << "#ifdef NDEBUG\n"; - out << " PyErr_SetString(PyExc_IndexError, \"index out of range\");\n"; - out << "#else\n"; - out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << "." << ielem.get_name() << "[] index out of range\");\n"; - out << "#endif\n"; - out << " return nullptr;\n"; - out << " }\n"; - - /*if (property->_has_function != NULL) { - out << " if (!local_this->" << property->_has_function->_ifunc.get_name() << "(index)) {\n" - << " return Py_NewRef(Py_None);\n" - << " }\n"; - }*/ - - std::set remaps; - - // Extract only the getters that take one integral argument. - for (FunctionRemap *remap : property->_getter_remaps) { - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - if (min_num_args <= 1 && max_num_args >= 1 && - TypeManager::is_integer(remap->_parameters[(size_t)remap->_has_this]._remap->get_new_type())) { - remaps.insert(remap); - } - } - - string expected_params; - if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true, - AT_no_args, RF_pyobject | RF_err_null, false, true, "index")) { - error_bad_args_return(out, 2, RF_pyobject | RF_err_null, expected_params); - } - out << "}\n\n"; - - // Write out a setitem if this is not a read-only property. - if (!property->_setter_remaps.empty()) { - out << "static int Dtool_" + ClassName + "_" + ielem.get_name() + "_Sequence_Setitem(PyObject *self, Py_ssize_t index, PyObject *arg) {\n"; - if (property->_has_this) { - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \"" - << classNameFromCppName(cClassName, false) << "." << ielem.get_name() << "\")) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - } - - out << " if (index < 0 || index >= (Py_ssize_t)" - << len_remap->get_call_str("local_this", pexprs) << ") {\n"; - out << "#ifdef NDEBUG\n"; - out << " PyErr_SetString(PyExc_IndexError, \"index out of range\");\n"; - out << "#else\n"; - out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << "." << ielem.get_name() << "[] index out of range\");\n"; - out << "#endif\n"; - out << " return -1;\n"; - out << " }\n"; - - out << " if (arg == nullptr) {\n"; - if (property->_deleter != nullptr) { - if (property->_deleter->_has_this) { - out << " local_this->" << property->_deleter->_ifunc.get_name() << "(index);\n"; - } else { - out << " " << cClassName << "::" << property->_deleter->_ifunc.get_name() << "(index);\n"; - } - out << " return 0;\n"; - } else { - out << "#ifdef NDEBUG\n" - " Dtool_Raise_TypeError(\"can't delete attribute\");\n" - "#else\n" - " Dtool_Raise_TypeError(\"can't delete " << ielem.get_name() << "[] attribute\");\n" - "#endif\n" - " return -1;\n"; - } - out << " }\n"; - - if (property->_clear_function != nullptr) { - out << " if (arg == Py_None) {\n"; - if (property->_clear_function->_has_this) { - out << " local_this->" << property->_clear_function->_ifunc.get_name() << "(index);\n"; - } else { - out << " " << cClassName << "::" << property->_clear_function->_ifunc.get_name() << "(index);\n"; - } - out << " return 0;\n" - << " }\n"; - } - - std::set remaps; - - // Extract only the setters that take two arguments. - for (FunctionRemap *remap : property->_setter_remaps) { - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - if (min_num_args <= 2 && max_num_args >= 2 && - TypeManager::is_integer(remap->_parameters[1]._remap->get_new_type())) { - remaps.insert(remap); - } - } - - string expected_params; - if (!write_function_forset(out, remaps, 2, 2, expected_params, 2, true, - true, AT_single_arg, RF_int, false, false, "index")) { - error_bad_args_return(out, 2, RF_int, expected_params); - } - out << "}\n\n"; - } - - // Finally, add the inserter, if one exists. - if (property->_inserter != nullptr) { - out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Sequence_insert(PyObject *self, size_t index, PyObject *arg) {\n"; - if (property->_has_this) { - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \"" - << classNameFromCppName(cClassName, false) << "." << ielem.get_name() << "\")) {\n"; - out << " return nullptr;\n"; - out << " }\n\n"; - } - - std::set remaps; - remaps.insert(property->_inserter->_remaps.begin(), - property->_inserter->_remaps.end()); - - string expected_params; - if (!write_function_forset(out, remaps, 2, 2, expected_params, 2, true, - true, AT_single_arg, RF_pyobject | RF_err_null, - false, false, "index")) { - error_bad_args_return(out, 2, RF_pyobject | RF_err_null, expected_params); - } - out << "}\n\n"; - } - } - - - // Write the getitem functions. - if (ielem.is_mapping()) { - out << - "/**\n" - " * mapping getitem for property " << ielem.get_scoped_name() << "\n" - " */\n" - "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Mapping_Getitem(PyObject *self, PyObject *arg) {\n"; - - // Before we do the has_function: if this is also a sequence, then we have - // to also handle the case here that we were passed an index. - if (ielem.is_sequence()) { - out << - "#if PY_MAJOR_VERSION >= 3\n" - " if (PyLong_CheckExact(arg)) {\n" - "#else\n" - " if (PyLong_CheckExact(arg) || PyInt_CheckExact(arg)) {\n" - "#endif\n" - " return Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem(self, PyLongOrInt_AsSize_t(arg));\n" - " }\n\n"; - } - - if (property->_has_this) { - out << - " " << cClassName << " *local_this = nullptr;\n" - " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n" - " return nullptr;\n" - " }\n"; - } - - if (property->_has_function != nullptr) { - std::set remaps; - remaps.insert(property->_has_function->_remaps.begin(), - property->_has_function->_remaps.end()); - - out << " {\n"; - string expected_params; - write_function_forset(out, remaps, 1, 1, expected_params, 4, true, true, - AT_single_arg, RF_raise_keyerror | RF_err_null, false, true); - out << " }\n"; - } - - std::set remaps; - // Extract only the getters that take one argument. Fish out the ones - // already taken by the sequence getter. - for (FunctionRemap *remap : property->_getter_remaps) { - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - if (min_num_args <= 1 && max_num_args >= 1 && - (!ielem.is_sequence() || !TypeManager::is_integer(remap->_parameters[(size_t)remap->_has_this]._remap->get_new_type()))) { - remaps.insert(remap); - } - } - - string expected_params; - if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true, - AT_single_arg, RF_pyobject | RF_err_null, false, true)) { - error_bad_args_return(out, 2, RF_pyobject | RF_err_null, expected_params); - } - out << "}\n\n"; - - // Write out a setitem if this is not a read-only property. - if (!property->_setter_remaps.empty()) { - out << - "/**\n" - " * mapping setitem for property " << ielem.get_scoped_name() << "\n" - " */\n" - "static int Dtool_" + ClassName + "_" + ielem.get_name() + "_Mapping_Setitem(PyObject *self, PyObject *key, PyObject *value) {\n"; - - if (property->_has_this) { - out << - " " << cClassName << " *local_this = nullptr;\n" - " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \"" - << classNameFromCppName(cClassName, false) << "." << ielem.get_name() << "\")) {\n" - " return -1;\n" - " }\n\n"; - } - - out << " if (value == nullptr) {\n"; - if (property->_deleter != nullptr) { - out << " PyObject *arg = key;\n"; - - if (property->_has_function != nullptr) { - std::set remaps; - remaps.insert(property->_has_function->_remaps.begin(), - property->_has_function->_remaps.end()); - - out << " {\n"; - string expected_params; - write_function_forset(out, remaps, 1, 1, expected_params, 6, true, true, - AT_single_arg, RF_raise_keyerror | RF_int, false, true); - out << " }\n"; - } - - std::set remaps; - remaps.insert(property->_deleter->_remaps.begin(), - property->_deleter->_remaps.end()); - - string expected_params; - if (!write_function_forset(out, remaps, 1, 1, - expected_params, 4, true, true, AT_single_arg, - RF_int, false, false)) { - out << " return -1;\n"; - } - } else { - out << "#ifdef NDEBUG\n" - " Dtool_Raise_TypeError(\"can't delete attribute\");\n" - "#else\n" - " Dtool_Raise_TypeError(\"can't delete " << ielem.get_name() << "[] attribute\");\n" - "#endif\n" - " return -1;\n"; - } - out << " }\n"; - - if (property->_clear_function != nullptr) { - out << " if (value == Py_None) {\n" - << " local_this->" << property->_clear_function->_ifunc.get_name() << "(key);\n" - << " return 0;\n" - << " }\n"; - } - - std::set remaps; - remaps.insert(property->_setter_remaps.begin(), - property->_setter_remaps.end()); - - // We have to create an args tuple only to unpack it later, ugh. - out << " PyObject *args = PyTuple_New(2);\n" - << " PyTuple_SET_ITEM(args, 0, Py_NewRef(key));\n" - << " PyTuple_SET_ITEM(args, 1, Py_NewRef(value));\n"; - - string expected_params; - if (!write_function_forset(out, remaps, 2, 2, - expected_params, 2, true, true, AT_varargs, - RF_int | RF_decref_args, false, false)) { - error_bad_args_return(out, 2, RF_int | RF_decref_args, expected_params); - } - out << "}\n\n"; - } - - if (property->_getkey_function != nullptr) { - out << - "/**\n" - " * mapping key-getter for property " << ielem.get_scoped_name() << "\n" - " */\n" - "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Mapping_Getkey(PyObject *self, Py_ssize_t index) {\n"; - - if (property->_has_this) { - out << - " " << cClassName << " *local_this = nullptr;\n" - " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n" - " return nullptr;\n" - " }\n"; - } - - // We need to raise IndexError if we're out of bounds. - if (len_remap != nullptr) { - out << " if (index < 0 || index >= (Py_ssize_t)" - << len_remap->get_call_str("local_this", pexprs) << ") {\n"; - out << "#ifdef NDEBUG\n"; - out << " PyErr_SetString(PyExc_IndexError, \"index out of range\");\n"; - out << "#else\n"; - out << " PyErr_SetString(PyExc_IndexError, \"" << ClassName << "." << ielem.get_name() << "[] index out of range\");\n"; - out << "#endif\n"; - out << " return nullptr;\n"; - out << " }\n"; - } - - std::set remaps; - - // Extract only the getters that take one integral argument. - for (FunctionRemap *remap : property->_getkey_function->_remaps) { - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - if (min_num_args <= 1 && max_num_args >= 1 && - TypeManager::is_integer(remap->_parameters[(size_t)remap->_has_this]._remap->get_new_type())) { - remaps.insert(remap); - } - } - - string expected_params; - if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true, true, - AT_no_args, RF_pyobject | RF_err_null, false, true, "index")) { - error_bad_args_return(out, 2, RF_pyobject | RF_err_null, expected_params); - } - out << "}\n\n"; - } - } - - // Now write the actual getter wrapper. It will be a different wrapper - // depending on whether it's a mapping or a sequence. - out << "static PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *) {\n"; - - // Is this property shadowing a static method with the same name? This is a - // special case to handle WindowProperties::make -- see GH #444. - if (property->_has_this) { - for (const Function *func : obj->_methods) { - if (!func->_has_this && func->_ifunc.get_name() == ielem.get_name()) { - string flags; - string fptr = "&" + func->_name; - switch (func->_args_type) { - case AT_keyword_args: - flags = "METH_VARARGS | METH_KEYWORDS"; - fptr = "(PyCFunction) " + fptr; - break; - case AT_varargs: - flags = "METH_VARARGS"; - break; - case AT_single_arg: - flags = "METH_O"; - break; - default: - flags = "METH_NOARGS"; - break; - } - out << " if (self == nullptr) {\n" - << " static PyMethodDef def = {\"" << ielem.get_name() << "\", " - << fptr << ", " << flags << " | METH_STATIC, (const char *)" - << func->_name << "_comment};\n" - << " return PyCFunction_New(&def, nullptr);\n" - << " }\n\n"; - break; - } - } - } - - if (ielem.is_mapping()) { - if (property->_has_this) { - out << " nassertr(self != nullptr, nullptr);\n"; - } - if (property->_setter_remaps.empty()) { - out << " Dtool_MappingWrapper *wrap = Dtool_NewMappingWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n"; - } else { - out << " Dtool_MappingWrapper *wrap = Dtool_NewMutableMappingWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n"; - } - out << " if (wrap != nullptr) {\n" - " wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getitem;\n"; - if (!property->_setter_remaps.empty()) { - if (property->_has_this) { - out << " if (!DtoolInstance_IS_CONST(self)) {\n"; - } else { - out << " {\n"; - } - out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Setitem;\n"; - out << " }\n"; - } - if (property->_length_function != nullptr) { - out << " wrap->_keys._len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n"; - if (property->_getkey_function != nullptr) { - out << " wrap->_keys._getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Mapping_Getkey;\n"; - } - } - out << " }\n" - " return (PyObject *)wrap;\n" - "}\n\n"; - - } else if (ielem.is_sequence()) { - if (property->_has_this) { - out << " nassertr(self != nullptr, nullptr);\n"; - } - if (property->_setter_remaps.empty()) { - out << - " Dtool_SequenceWrapper *wrap = Dtool_NewSequenceWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n" - " if (wrap != nullptr) {\n" - " wrap->_len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n" - " wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n"; - } else { - out << - " Dtool_MutableSequenceWrapper *wrap = Dtool_NewMutableSequenceWrapper(self, \"" << ClassName << "." << ielem.get_name() << "\");\n" - " if (wrap != nullptr) {\n" - " wrap->_len_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Len;\n" - " wrap->_getitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Getitem;\n"; - if (!property->_setter_remaps.empty()) { - if (property->_has_this) { - out << " if (!DtoolInstance_IS_CONST(self)) {\n"; - } else { - out << " {\n"; - } - out << " wrap->_setitem_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_Setitem;\n"; - if (property->_inserter != nullptr) { - out << " wrap->_insert_func = &Dtool_" << ClassName << "_" << ielem.get_name() << "_Sequence_insert;\n"; - } - out << " }\n"; - } - } - out << " }\n" - " return (PyObject *)wrap;\n" - "}\n\n"; - - } else { - // Write out a regular, unwrapped getter. - FunctionRemap *remap = property->_getter_remaps.front(); - - if (remap->_has_this) { - if (remap->_const_method) { - out << " const " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer(self, Dtool_" << ClassName << ", (void **)&local_this)) {\n"; - } else { - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \"" - << classNameFromCppName(cClassName, false) << "." << ielem.get_name() << "\")) {\n"; - } - out << " return nullptr;\n"; - out << " }\n\n"; - } - - if (property->_has_function != nullptr) { - if (remap->_has_this) { - out << " if (!local_this->" << property->_has_function->_ifunc.get_name() << "()) {\n"; - } else { - out << " if (!" << cClassName << "::" << property->_has_function->_ifunc.get_name() << "()) {\n"; - } - out << " return Py_NewRef(Py_None);\n" - << " }\n"; - } - - std::set remaps; - remaps.insert(remap); - - string expected_params; - write_function_forset(out, remaps, 0, 0, - expected_params, 2, false, true, AT_no_args, - RF_pyobject | RF_err_null, false, false); - out << "}\n\n"; - - // Write out a setter if this is not a read-only property. - if (!property->_setter_remaps.empty()) { - out << "static int Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter(PyObject *self, PyObject *arg, void *) {\n"; - if (remap->_has_this) { - out << " " << cClassName << " *local_this = nullptr;\n"; - out << " if (!Dtool_Call_ExtractThisPointer_NonConst(self, Dtool_" << ClassName << ", (void **)&local_this, \"" - << classNameFromCppName(cClassName, false) << "." << ielem.get_name() << "\")) {\n"; - out << " return -1;\n"; - out << " }\n\n"; - } - - out << " if (arg == nullptr) {\n"; - if (property->_deleter != nullptr && remap->_has_this) { - out << " local_this->" << property->_deleter->_ifunc.get_name() << "();\n" - << " return 0;\n"; - } else if (property->_deleter != nullptr) { - out << " " << cClassName << "::" << property->_deleter->_ifunc.get_name() << "();\n" - << " return 0;\n"; - } else { - out << "#ifdef NDEBUG\n" - " Dtool_Raise_TypeError(\"can't delete attribute\");\n" - "#else\n" - " Dtool_Raise_TypeError(\"can't delete " << ielem.get_name() << " attribute\");\n" - "#endif\n" - " return -1;\n"; - } - out << " }\n"; - - if (property->_clear_function != nullptr) { - out << " if (arg == Py_None) {\n"; - if (remap->_has_this) { - out << " local_this->" << property->_clear_function->_ifunc.get_name() << "();\n"; - } else { - out << " " << cClassName << "::" << property->_clear_function->_ifunc.get_name() << "();\n"; - } - out << " return 0;\n" - << " }\n"; - } - - std::set remaps; - - // Extract only the setters that take one argument. - for (FunctionRemap *remap : property->_setter_remaps) { - int min_num_args = remap->get_min_num_args(); - int max_num_args = remap->get_max_num_args(); - if (min_num_args <= 1 && max_num_args >= 1) { - remaps.insert(remap); - } - } - - string expected_params; - if (!write_function_forset(out, remaps, 1, 1, expected_params, 2, true, - true, AT_single_arg, RF_int, false, false)) { - error_bad_args_return(out, 2, RF_int, expected_params); - } - out << "}\n\n"; - } - } -} - -/** - * Records the indicated type, which may be a struct type, along with all of - * its associated methods, if any. - */ -InterfaceMaker::Object *InterfaceMakerPythonNative:: -record_object(TypeIndex type_index) { - if (type_index == 0) { - return nullptr; - } - - Objects::iterator oi = _objects.find(type_index); - if (oi != _objects.end()) { - return (*oi).second; - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - const InterrogateType &itype = idb->get_type(type_index); - - if (!is_cpp_type_legal(itype._cpptype)) { - return nullptr; - } - - Object *object = new Object(itype); - bool inserted = _objects.insert(Objects::value_type(type_index, object)).second; - assert(inserted); - - Function *function; - - int num_constructors = itype.number_of_constructors(); - for (int ci = 0; ci < num_constructors; ci++) { - function = record_function(itype, itype.get_constructor(ci)); - if (is_function_legal(function)) { - object->_constructors.push_back(function); - } - } - - int num_methods = itype.number_of_methods(); - int mi; - for (mi = 0; mi < num_methods; mi++) { - function = record_function(itype, itype.get_method(mi)); - if (is_function_legal(function)) { - object->_methods.push_back(function); - } - } - - int num_casts = itype.number_of_casts(); - for (mi = 0; mi < num_casts; mi++) { - function = record_function(itype, itype.get_cast(mi)); - if (is_function_legal(function)) { - object->_methods.push_back(function); - } - } - - int num_derivations = itype.number_of_derivations(); - for (int di = 0; di < num_derivations; di++) { - TypeIndex d_type_Index = itype.get_derivation(di); - idb->get_type(d_type_Index); - - if (!interrogate_type_is_unpublished(d_type_Index)) { - if (itype.derivation_has_upcast(di)) { - function = record_function(itype, itype.derivation_get_upcast(di)); - if (is_function_legal(function)) { - object->_methods.push_back(function); - } - } - /*if (itype.derivation_has_downcast(di)) { - // Downcasts are methods of the base class, not the child class. - TypeIndex base_type_index = itype.get_derivation(di); - - const InterrogateType &base_type = idb->get_type(base_type_index); - function = record_function(base_type, itype.derivation_get_downcast(di)); - - if (is_function_legal(function)) { - Object *pobject = record_object(base_type_index); - if (pobject != NULL) { - pobject->_methods.push_back(function); - } - } - }*/ - } - } - - int num_elements = itype.number_of_elements(); - for (int ei = 0; ei < num_elements; ei++) { - ElementIndex element_index = itype.get_element(ei); - - Property *property = record_property(itype, element_index); - if (property != nullptr) { - object->_properties.push_back(property); - } else { - // No use exporting a property without a getter. - delete property; - } - } - - int num_make_seqs = itype.number_of_make_seqs(); - for (int msi = 0; msi < num_make_seqs; msi++) { - MakeSeqIndex make_seq_index = itype.get_make_seq(msi); - const InterrogateMakeSeq &imake_seq = idb->get_make_seq(make_seq_index); - - string class_name = itype.get_scoped_name(); - string clean_name = InterrogateBuilder::clean_identifier(class_name); - string wrapper_name = "MakeSeq_" + clean_name + "_" + imake_seq.get_name(); - - MakeSeq *make_seq = new MakeSeq(wrapper_name, imake_seq); - make_seq->_length_getter = record_function(itype, imake_seq.get_length_getter()); - make_seq->_element_getter = record_function(itype, imake_seq.get_element_getter()); - object->_make_seqs.push_back(make_seq); - } - - object->check_protocols(); - - int num_nested = itype.number_of_nested_types(); - for (int ni = 0; ni < num_nested; ni++) { - TypeIndex nested_index = itype.get_nested_type(ni); - record_object(nested_index); - } - return object; -} - -/** - * - */ -InterfaceMaker::Property *InterfaceMakerPythonNative:: -record_property(const InterrogateType &itype, ElementIndex element_index) { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - const InterrogateElement &ielement = idb->get_element(element_index); - if (!ielement.has_getter()) { - // A property needs at the very least a getter. - return nullptr; - } - - Property *property; - { - FunctionIndex func_index = ielement.get_getter(); - if (func_index != 0) { - const InterrogateFunction &ifunc = idb->get_function(func_index); - property = new Property(ielement); - - InterrogateFunction::Instances::const_iterator ii; - for (ii = ifunc._instances->begin(); ii != ifunc._instances->end(); ++ii) { - CPPInstance *cppfunc = (*ii).second; - FunctionRemap *remap = - make_function_remap(itype, ifunc, cppfunc, 0); - - if (remap != nullptr && is_remap_legal(remap)) { - property->_getter_remaps.push_back(remap); - property->_has_this |= remap->_has_this; - } - } - } else { - return nullptr; - } - } - - if (ielement.has_setter()) { - FunctionIndex func_index = ielement.get_setter(); - if (func_index != 0) { - const InterrogateFunction &ifunc = idb->get_function(func_index); - - InterrogateFunction::Instances::const_iterator ii; - for (ii = ifunc._instances->begin(); ii != ifunc._instances->end(); ++ii) { - CPPInstance *cppfunc = (*ii).second; - FunctionRemap *remap = - make_function_remap(itype, ifunc, cppfunc, 0); - - if (remap != nullptr && is_remap_legal(remap)) { - property->_setter_remaps.push_back(remap); - property->_has_this |= remap->_has_this; - } - } - } - } - - if (ielement.has_has_function()) { - FunctionIndex func_index = ielement.get_has_function(); - Function *has_function = record_function(itype, func_index); - if (is_function_legal(has_function)) { - property->_has_function = has_function; - property->_has_this |= has_function->_has_this; - } - } - - if (ielement.has_clear_function()) { - FunctionIndex func_index = ielement.get_clear_function(); - Function *clear_function = record_function(itype, func_index); - if (is_function_legal(clear_function)) { - property->_clear_function = clear_function; - property->_has_this |= clear_function->_has_this; - } - } - - if (ielement.has_del_function()) { - FunctionIndex func_index = ielement.get_del_function(); - Function *del_function = record_function(itype, func_index); - if (is_function_legal(del_function)) { - property->_deleter = del_function; - property->_has_this |= del_function->_has_this; - } - } - - if (ielement.is_sequence() || ielement.is_mapping()) { - FunctionIndex func_index = ielement.get_length_function(); - if (func_index != 0) { - property->_length_function = record_function(itype, func_index); - } - } - - if (ielement.is_sequence() && ielement.has_insert_function()) { - FunctionIndex func_index = ielement.get_insert_function(); - Function *insert_function = record_function(itype, func_index); - if (is_function_legal(insert_function)) { - property->_inserter = insert_function; - property->_has_this |= insert_function->_has_this; - } - } - - if (ielement.is_mapping() && ielement.has_getkey_function()) { - FunctionIndex func_index = ielement.get_getkey_function(); - assert(func_index != 0); - Function *getkey_function = record_function(itype, func_index); - if (is_function_legal(getkey_function)) { - property->_getkey_function = getkey_function; - property->_has_this |= getkey_function->_has_this; - } - } - - return property; -} - -/** - * Walks through the set of functions in the database and generates wrappers - * for each function, storing these in the database. No actual code should be - * output yet; this just updates the database with the wrapper information. - */ -void InterfaceMakerPythonNative:: -generate_wrappers() { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - // We use a while loop rather than a simple for loop, because we might - // increase the number of types recursively during the traversal. - - int ti = 0; - while (ti < idb->get_num_all_types()) { - TypeIndex type_index = idb->get_all_type(ti); - record_object(type_index); - ++ti; - } - - int num_global_elements = idb->get_num_global_elements(); - for (int gi = 0; gi < num_global_elements; ++gi) { - TypeIndex type_index = idb->get_global_element(gi); - record_object(type_index); - } - - int num_functions = idb->get_num_global_functions(); - for (int fi = 0; fi < num_functions; fi++) { - FunctionIndex func_index = idb->get_global_function(fi); - record_function(dummy_type, func_index); - } - - int num_manifests = idb->get_num_global_manifests(); - for (int mi = 0; mi < num_manifests; mi++) { - ManifestIndex manifest_index = idb->get_global_manifest(mi); - const InterrogateManifest &iman = idb->get_manifest(manifest_index); - if (iman.has_getter()) { - FunctionIndex func_index = iman.get_getter(); - record_function(dummy_type, func_index); - } - } - - int num_elements = idb->get_num_global_elements(); - for (int ei = 0; ei < num_elements; ei++) { - ElementIndex element_index = idb->get_global_element(ei); - const InterrogateElement &ielement = idb->get_element(element_index); - if (ielement.has_getter()) { - FunctionIndex func_index = ielement.get_getter(); - record_function(dummy_type, func_index); - } - if (ielement.has_setter()) { - FunctionIndex func_index = ielement.get_setter(); - record_function(dummy_type, func_index); - } - } -} - -/** - - */ -bool InterfaceMakerPythonNative:: -is_cpp_type_legal(CPPType *in_ctype) { - if (in_ctype == nullptr) { - return false; - } - - string name = in_ctype->get_local_name(&parser); - - if (builder.in_ignoretype(name)) { - return false; - } - - if (builder.in_forcetype(name)) { - return true; - } - - // bool answer = false; - CPPType *type = TypeManager::resolve_type(in_ctype); - if (TypeManager::is_rvalue_reference(type)) { - return false; - } - - type = TypeManager::unwrap(type); - - if (TypeManager::is_void(type)) { - return true; - } else if (TypeManager::is_basic_string_char(type)) { - return true; - } else if (TypeManager::is_basic_string_wchar(type)) { - return true; - } else if (TypeManager::is_vector_unsigned_char(in_ctype)) { - return true; - } else if (TypeManager::is_simple(type)) { - return true; - } else if (TypeManager::is_pointer_to_simple(type)) { - return true; - } else if (builder.in_forcetype(type->get_local_name(&parser))) { - return true; - } else if (TypeManager::is_exported(type)) { - return true; - } else if (TypeManager::is_pointer_to_PyObject(in_ctype)) { - return true; - } else if (TypeManager::is_pointer_to_Py_buffer(in_ctype)) { - return true; - } - - // if (answer == false) printf(" -------------------- Bad Type ?? - // %s\n",type->get_local_name().c_str()); - - return false; -} -/** - - */ -bool InterfaceMakerPythonNative:: -isExportThisRun(CPPType *ctype) { - if (builder.in_forcetype(ctype->get_local_name(&parser))) { - return true; - } - - if (!TypeManager::is_exported(ctype)) { - return false; - } - - if (TypeManager::is_local(ctype)) { - return true; - } - - return false; -} - -/** - - */ -bool InterfaceMakerPythonNative:: -isExportThisRun(Function *func) { - if (func == nullptr || !is_function_legal(func)) { - return false; - } - - for (FunctionRemap *remap : func->_remaps) { - return isExportThisRun(remap->_cpptype); - } - - return false; -} - -/** - - */ -bool InterfaceMakerPythonNative:: -is_remap_legal(FunctionRemap *remap) { - if (remap == nullptr) { - return false; - } - - // return must be legal and managable.. - if (!is_cpp_type_legal(remap->_return_type->get_orig_type())) { -// printf(" is_remap_legal Return Is Bad %s\n",remap->_return_type->get_orig_ -// type()->get_fully_scoped_name().c_str()); - // Except if this is a spaceship operator, since we have special handling - // for its return type. - if (remap->_cppfunc->get_simple_name() != "operator <=>") { - return false; - } - } - - // We don't currently support returning pointers, but we accept them as - // function parameters. But const char * is an exception. - if (!remap->_return_type->new_type_is_atomic_string() && - TypeManager::is_pointer_to_simple(remap->_return_type->get_orig_type())) { - return false; - } - - // ouch .. bad things will happen here .. do not even try.. - if (remap->_ForcedVoidReturn) { - return false; - } - - // all non-optional params must be legal - for (size_t pn = 0; pn < remap->_parameters.size(); pn++) { - ParameterRemap *param = remap->_parameters[pn]._remap; - CPPType *orig_type = param->get_orig_type(); - if (param->get_default_value() == nullptr && !is_cpp_type_legal(orig_type)) { - return false; - } - } - - // Don't export global operators. - if (!remap->_has_this && - remap->_cppfunc->get_simple_name().compare(0, 9, "operator ") == 0) { - return false; - } - - // ok all looks ok. - return true; -} - -/** - - */ -int InterfaceMakerPythonNative:: -has_coerce_constructor(CPPStructType *type) { - if (type == nullptr) { - return 0; - } - - // It is convenient to set default-constructability and move-assignability - // as requirement for non-reference-counted objects, since it simplifies the - // implementation and it holds for all classes we need it for. - if (!TypeManager::is_reference_count(type) && - (!type->is_default_constructible() || !type->is_move_assignable())) { - return 0; - } - - CPPScope *scope = type->get_scope(); - if (scope == nullptr) { - return 0; - } - - int result = 0; - - CPPScope::Functions::iterator fgi; - for (fgi = scope->_functions.begin(); fgi != scope->_functions.end(); ++fgi) { - CPPFunctionGroup *fgroup = fgi->second; - for (CPPInstance *inst : fgroup->_instances) { - CPPFunctionType *ftype = inst->_type->as_function_type(); - if (ftype == nullptr) { - continue; - } - if (inst->_storage_class & CPPInstance::SC_explicit) { - // Skip it if it is marked not to allow coercion. - continue; - } - - if (inst->_vis > min_vis) { - // Not published. - continue; - } - - CPPParameterList::Parameters ¶ms = ftype->_parameters->_parameters; - if (params.size() == 0) { - // It's useless if it doesn't take any parameters. - continue; - } - - if (ftype->_flags & CPPFunctionType::F_constructor) { - if (ftype->_flags & (CPPFunctionType::F_copy_constructor | - CPPFunctionType::F_move_constructor)) { - // Skip a copy and move constructor. - continue; - } else { - return 2; - } - - } else if (fgroup->_name == "make" && (inst->_storage_class & CPPInstance::SC_static) != 0) { - if (TypeManager::is_const_pointer_or_ref(ftype->_return_type)) { - result = 1; - } else { - return 2; - } - } - } - } - - return result; -} - -/** - - */ -bool InterfaceMakerPythonNative:: -is_remap_coercion_possible(FunctionRemap *remap) { - if (remap == nullptr) { - return false; - } - - size_t pn = 0; - if (remap->_has_this) { - // Skip the "this" parameter. It's never coercible. - ++pn; - } - while (pn < remap->_parameters.size()) { - CPPType *type = remap->_parameters[pn]._remap->get_new_type(); - - if (TypeManager::is_char_pointer(type)) { - } else if (TypeManager::is_wchar_pointer(type)) { - } else if (TypeManager::is_pointer_to_PyObject(type)) { - } else if (TypeManager::is_pointer_to_Py_buffer(type)) { - } else if (TypeManager::is_pointer_to_simple(type)) { - } else if (TypeManager::is_pointer(type)) { - // This is a pointer to an object, so we might be able to coerce a - // parameter to it. - CPPType *obj_type = TypeManager::unwrap(TypeManager::resolve_type(type)); - if (has_coerce_constructor(obj_type->as_struct_type()) > 0) { - // It has a coercion constructor, so go for it. - return true; - } - } - ++pn; - } - - return false; -} - -/** - - */ -bool InterfaceMakerPythonNative:: -is_function_legal(Function *func) { - for (FunctionRemap *remap : func->_remaps) { - if (is_remap_legal(remap)) { -// printf(" Function Is Marked Legal %s\n",func->_name.c_str()); - - return true; - } - } - -// printf(" Function Is Marked Illegal %s\n",func->_name.c_str()); - return false; -} - -/** - - */ -bool InterfaceMakerPythonNative:: -IsRunTimeTyped(const InterrogateType &itype) { - TypeIndex ptype_id = itype.get_outer_class(); - if (ptype_id > 0) { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - InterrogateType ptype = idb->get_type(ptype_id); - return IsRunTimeTyped(ptype); - } - - if (itype.get_name() == "TypedObject") { - return true; - } - - return false; -} - -/** - * Returns true if this object has special support for inheriting from Python. - */ -bool InterfaceMakerPythonNative:: -is_python_subclassable(CPPStructType *struct_type) { - if (struct_type != nullptr && !struct_type->is_final() && - IsPandaTypedObject(struct_type) && - TypeManager::is_reference_count(struct_type)) { - - // Make sure the type has a published constructor. - TypeIndex type_index = builder.get_type(struct_type, false); - if (type_index != 0) { - Objects::iterator oi = _objects.find(type_index); - if (oi != _objects.end()) { - Object *obj = (*oi).second; - return !obj->_constructors.empty(); - } - } - } - return false; -} - -/** - * Returns true if the type has a public member named __self__. - */ -bool InterfaceMakerPythonNative:: -has_self_member(CPPStructType *struct_type) { - if (struct_type == nullptr) { - return false; - } - - CPPScope *scope = struct_type->get_scope(); - if (scope != nullptr && scope->_variables.count("__self__")) { - return true; - } - - for (const CPPStructType::Base &base : struct_type->_derivation) { - if (base._base != nullptr) { - CPPStructType *base_type = base._base->as_struct_type(); - if (base_type != nullptr && has_self_member(base_type)) { - return true; - } - } - } - return false; -} - -/** - - */ -bool InterfaceMakerPythonNative:: -DoesInheritFromIsClass(const CPPStructType *inclass, const std::string &name) { - if (inclass == nullptr) { - return false; - } - - std::string scoped_name = inclass->get_fully_scoped_name(); - if (scoped_name == name) { - return true; - } - - for (const CPPStructType::Base &base : inclass->_derivation) { - CPPStructType *base_type = TypeManager::resolve_type(base._base)->as_struct_type(); - if (base_type != nullptr) { - if (DoesInheritFromIsClass(base_type, name)) { - return true; - } - } - } - return false; -} - -/** - - */ -bool InterfaceMakerPythonNative:: -has_get_class_type_function(CPPType *type) { - while (type->get_subtype() == CPPDeclaration::ST_typedef) { - type = type->as_typedef_type()->_type; - } - - CPPStructType *struct_type = type->as_struct_type(); - if (struct_type == nullptr) { - return false; - } - - CPPScope *scope = struct_type->get_scope(); - - return scope->_functions.find("get_class_type") != scope->_functions.end(); -} - -/** - * - */ -bool InterfaceMakerPythonNative:: -has_init_type_function(CPPType *type) { - while (type->get_subtype() == CPPDeclaration::ST_typedef) { - type = type->as_typedef_type()->_type; - } - - CPPStructType *struct_type = type->as_struct_type(); - if (struct_type == nullptr) { - return false; - } - - CPPScope *scope = struct_type->get_scope(); - CPPScope::Functions::const_iterator it = scope->_functions.find("init_type"); - if (it == scope->_functions.end()) { - return false; - } - const CPPFunctionGroup *group = it->second; - - for (const CPPInstance *cppinst : group->_instances) { - const CPPFunctionType *cppfunc = cppinst->_type->as_function_type(); - - if (cppfunc != nullptr && - cppfunc->_parameters != nullptr && - cppfunc->_parameters->_parameters.size() == 0 && - (cppinst->_storage_class & CPPInstance::SC_static) != 0) { - return true; - } - } - - return false; -} - -/** - * Returns -1 if the class does not define write() (and therefore cannot - * support a __str__ function). - * - * Returns 1 if the class defines write(ostream). - * - * Returns 2 if the class defines write(ostream, int). - * - * Note that if you want specific behavior for Python str(), you should just - * define a __str__ function, which maps directly to the appropriate type - * slot. - */ -int InterfaceMakerPythonNative:: -NeedsAStrFunction(const InterrogateType &itype_class) { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - int num_methods = itype_class.number_of_methods(); - int mi; - for (mi = 0; mi < num_methods; ++mi) { - FunctionIndex func_index = itype_class.get_method(mi); - const InterrogateFunction &ifunc = idb->get_function(func_index); - if (ifunc.get_name() == "write") { - if (ifunc._instances != nullptr) { - InterrogateFunction::Instances::const_iterator ii; - for (ii = ifunc._instances->begin(); - ii != ifunc._instances->end(); - ++ii) { - CPPInstance *cppinst = (*ii).second; - CPPFunctionType *cppfunc = cppinst->_type->as_function_type(); - - if (cppfunc != nullptr) { - if (cppfunc->_parameters != nullptr && - cppfunc->_return_type != nullptr && - TypeManager::is_void(cppfunc->_return_type)) { - if (cppfunc->_parameters->_parameters.size() == 1) { - CPPInstance *inst1 = cppfunc->_parameters->_parameters[0]; - if (TypeManager::is_pointer_to_ostream(inst1->_type)) { - // write(ostream) - return 1; - } - } - - if (cppfunc->_parameters->_parameters.size() == 2) { - CPPInstance *inst1 = cppfunc->_parameters->_parameters[0]; - if (TypeManager::is_pointer_to_ostream(inst1->_type)) { - inst1 = cppfunc->_parameters->_parameters[1]; - if (inst1->_initializer != nullptr) { - // write(ostream, int = 0) - return 1; - } - - if (TypeManager::is_integer(inst1->_type)) { - // write(ostream, int) - return 2; - } - } - } - } - } - } - } - } - } - - return -1; -} - -/** - * Returns -1 if the class does not define output() or python_repr() (and - * therefore cannot support a __repr__ function). - * - * Returns 1 if the class defines python_repr(ostream, string). - * - * Returns 2 if the class defines output(ostream). - * - * Returns 3 if the class defines an extension function for - * python_repr(ostream, string). - * - * Note that defining python_repr is deprecated in favor of defining a - * __repr__ that returns a string, which maps directly to the appropriate type - * slot. - */ -int InterfaceMakerPythonNative:: -NeedsAReprFunction(const InterrogateType &itype_class) { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - int num_methods = itype_class.number_of_methods(); - int mi; - for (mi = 0; mi < num_methods; ++mi) { - FunctionIndex func_index = itype_class.get_method(mi); - const InterrogateFunction &ifunc = idb->get_function(func_index); - if (ifunc.get_name() == "python_repr") { - if (ifunc._instances != nullptr) { - InterrogateFunction::Instances::const_iterator ii; - for (ii = ifunc._instances->begin(); - ii != ifunc._instances->end(); - ++ii) { - CPPInstance *cppinst = (*ii).second; - CPPFunctionType *cppfunc = cppinst->_type->as_function_type(); - - if (cppfunc != nullptr) { - if (cppfunc->_parameters != nullptr && - cppfunc->_return_type != nullptr && - TypeManager::is_void(cppfunc->_return_type)) { - if (cppfunc->_parameters->_parameters.size() == 2) { - CPPInstance *inst1 = cppfunc->_parameters->_parameters[0]; - if (TypeManager::is_pointer_to_ostream(inst1->_type)) { - inst1 = cppfunc->_parameters->_parameters[1]; - if (TypeManager::is_string(inst1->_type) || - TypeManager::is_char_pointer(inst1->_type)) { - // python_repr(ostream, string) - if ((cppinst->_storage_class & CPPInstance::SC_extension) != 0) { - return 3; - } else { - return 1; - } - } - } - } - } - } - } - } - } - } - - for (mi = 0; mi < num_methods; ++mi) { - FunctionIndex func_index = itype_class.get_method(mi); - const InterrogateFunction &ifunc = idb->get_function(func_index); - if (ifunc.get_name() == "output") { - if (ifunc._instances != nullptr) { - InterrogateFunction::Instances::const_iterator ii; - for (ii = ifunc._instances->begin(); - ii != ifunc._instances->end(); - ++ii) { - CPPInstance *cppinst = (*ii).second; - CPPFunctionType *cppfunc = cppinst->_type->as_function_type(); - - if (cppfunc != nullptr) { - if (cppfunc->_parameters != nullptr && - cppfunc->_return_type != nullptr && - TypeManager::is_void(cppfunc->_return_type)) { - if (cppfunc->_parameters->_parameters.size() == 1) { - CPPInstance *inst1 = cppfunc->_parameters->_parameters[0]; - if (TypeManager::is_pointer_to_ostream(inst1->_type)) { - // output(ostream) - return 2; - } - } - - if (cppfunc->_parameters->_parameters.size() >= 2) { - CPPInstance *inst1 = cppfunc->_parameters->_parameters[0]; - if (TypeManager::is_pointer_to_ostream(inst1->_type)) { - inst1 = cppfunc->_parameters->_parameters[1]; - if (inst1->_initializer != nullptr) { - // output(ostream, foo = bar, ...) - return 2; - } - } - } - } - } - } - } - } - } - - return -1; -} - -/** - * Returns true if the class defines a rich comparison operator. - */ -bool InterfaceMakerPythonNative:: -NeedsARichCompareFunction(const InterrogateType &itype_class) { - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - int num_methods = itype_class.number_of_methods(); - int mi; - for (mi = 0; mi < num_methods; ++mi) { - FunctionIndex func_index = itype_class.get_method(mi); - const InterrogateFunction &ifunc = idb->get_function(func_index); - if (ifunc.get_name() == "operator <") { - return true; - } - if (ifunc.get_name() == "operator <=") { - return true; - } - if (ifunc.get_name() == "operator ==") { - return true; - } - if (ifunc.get_name() == "operator !=") { - return true; - } - if (ifunc.get_name() == "operator >") { - return true; - } - if (ifunc.get_name() == "operator >=") { - return true; - } - } - - if (itype_class._cpptype != nullptr) { - CPPStructType *struct_type = itype_class._cpptype->as_struct_type(); - if (struct_type != nullptr) { - CPPScope *scope = struct_type->get_scope(); - CPPScope::Functions::const_iterator it = scope->_functions.find("operator <=>"); - if (it != scope->_functions.end()) { - return true; - } - } - } - - return false; -} - -/** - * Outputs the indicated string as a single quoted, multi-line string to the - * generated C++ source code. The output point is left on the last line of - * the string, following the trailing quotation mark. - */ -void InterfaceMakerPythonNative:: -output_quoted(ostream &out, int indent_level, const std::string &str, - bool first_line) { - indent(out, (first_line ? indent_level : 0)) - << '"'; - std::string::const_iterator si; - for (si = str.begin(); si != str.end();) { - switch (*si) { - case '"': - case '\\': - out << '\\' << *si; - break; - - case '\n': - out << "\\n\""; - if (++si == str.end()) { - return; - } - out << "\n"; - indent(out, indent_level) - << '"'; - continue; - - case '\t': - out << "\\t"; - break; - - default: - if (!isprint(*si)) { - out << "\\" << oct << std::setw(3) << std::setfill('0') << (unsigned int)(*si) - << dec; - } else { - out << *si; - } - } - ++si; - } - out << '"'; -} diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.h b/dtool/src/interrogate/interfaceMakerPythonNative.h deleted file mode 100644 index aec04a66524..00000000000 --- a/dtool/src/interrogate/interfaceMakerPythonNative.h +++ /dev/null @@ -1,232 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPythonNative.h - */ - -#ifndef INTERFACEMAKERPYTHONNATIVE_H -#define INTERFACEMAKERPYTHONNATIVE_H -#include -#include -#include "dtoolbase.h" - -#include "interfaceMakerPython.h" -#include "interrogate_interface.h" -#include "cppStructType.h" - -class FunctionRemap; - -/** - * An InterfaceMaker for generating complex Python function wrappers around - * C++ code. - */ -class InterfaceMakerPythonNative : public InterfaceMakerPython { -public: - InterfaceMakerPythonNative(InterrogateModuleDef *def); - virtual ~InterfaceMakerPythonNative(); - - - virtual void write_prototypes(std::ostream &out, std::ostream *out_h); - void write_prototypes_class(std::ostream &out, std::ostream *out_h, Object *obj) ; - void write_prototypes_class_external(std::ostream &out, Object *obj); - - virtual void write_functions(std::ostream &out); - - virtual void write_module(std::ostream &out, std::ostream *out_h, InterrogateModuleDef *def); - virtual void write_module_support(std::ostream &out, std::ostream *out_h, InterrogateModuleDef *def); - - void write_module_class(std::ostream &out, Object *cls); - virtual void write_sub_module(std::ostream &out, Object *obj); - - virtual bool synthesize_this_parameter(); - virtual bool separate_overloading(); - - virtual Object *record_object(TypeIndex type_index); - Property *record_property(const InterrogateType &itype, ElementIndex element_index); - -protected: - virtual std::string get_wrapper_prefix(); - virtual std::string get_unique_prefix(); - virtual void record_function_wrapper(InterrogateFunction &ifunc, - FunctionWrapperIndex wrapper_index); - - virtual void generate_wrappers(); - -private: - // This enum defines the various prototypes that must be generated for the - // specialty functions that Python requires, especially for the slotted - // functions. - enum WrapperType { - WT_none, - WT_no_params, - WT_one_param, - WT_binary_operator, - WT_setattr, - WT_getattr, - WT_sequence_getitem, - WT_sequence_setitem, - WT_sequence_size, - WT_mapping_setitem, - WT_inquiry, - WT_getbuffer, - WT_releasebuffer, - WT_iter_next, - WT_ternary_operator, - WT_inplace_binary_operator, - WT_inplace_ternary_operator, - WT_traverse, - WT_compare, - WT_hash, - WT_new, - }; - - // This enum is passed to the wrapper generation functions to indicate what - // sort of values the wrapper function is expected to return. - enum ReturnFlags { - // -1 on failure, 0 on success. - RF_int = 0x100, - - // Like RF_int, but special case that it returns -1, 0, or 1. - RF_compare = RF_int | 0x200, - - // Returns the actual return value as PyObject*. - RF_pyobject = 0x010, - - // Returns a reference to self. - RF_self = 0x020, - - // Assign to the coerced argument, in the case of a coercion constructor. - RF_coerced = 0x040, - - // Don't automatically map NULL to None - RF_preserve_null = 0x080, - - // These indicate what should be returned on error. - RF_err_notimplemented = 0x002, - RF_err_null = 0x004, - RF_err_false = 0x008, - - // Decref temporary args object before returning. - RF_decref_args = 0x1000, - - // This raises a KeyError on falsey (or -1) return value. - RF_raise_keyerror = 0x4000, - - // Invert boolean return value. - RF_invert_bool = 0x8000, - - // Used inside a rich comparison function. - RF_richcompare_zero = 0x10000, - }; - - class SlottedFunctionDef { - public: - std::string _answer_location; - WrapperType _wrapper_type; - int _min_version = 0; - std::string _wrapper_name; - std::set _remaps; - bool _keep_method; - }; - - typedef std::map SlottedFunctions; - - static bool get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap, SlottedFunctionDef &def); - static void write_function_slot(std::ostream &out, int indent_level, - const SlottedFunctions &slots, - const std::string &slot, const std::string &def = "nullptr"); - - void write_prototype_for_name(std::ostream &out, Function *func, const std::string &name); - void write_prototype_for(std::ostream &out, Function *func); - void write_function_for_top(std::ostream &out, Object *obj, Function *func); - - void write_function_for_name(std::ostream &out, Object *obj, - const Function::Remaps &remaps, - const std::string &name, std::string &expected_params, - bool coercion_allowed, - ArgsType args_type, int return_flags); - void write_coerce_constructor(std::ostream &out, Object *obj, bool is_const); - - int collapse_default_remaps(std::map > &map_sets, - int max_required_args); - - bool write_function_forset(std::ostream &out, - const std::set &remaps, - int min_num_args, int max_num_args, - std::string &expected_params, int indent_level, - bool coercion_allowed, bool report_errors, - ArgsType args_type, int return_flags, - bool check_exceptions = true, - bool verify_const = true, - const std::string &first_expr = std::string()); - - bool write_function_instance(std::ostream &out, FunctionRemap *remap, - int min_num_args, int max_num_args, - std::string &expected_params, int indent_level, - bool coercion_allowed, bool report_errors, - ArgsType args_type, int return_flags, - bool check_exceptions = true, - const std::string &first_pexpr = std::string()); - - void error_return(std::ostream &out, int indent_level, int return_flags); - void error_bad_args_return(std::ostream &out, int indent_level, int return_flags, - const std::string &expected_params); - void error_raise_return(std::ostream &out, int indent_level, int return_flags, - const std::string &exc_type, const std::string &message, - const std::string &format_args = ""); - void pack_return_value(std::ostream &out, int indent_level, FunctionRemap *remap, - std::string return_expr, int return_flags); - - void write_make_seq(std::ostream &out, Object *obj, const std::string &ClassName, - const std::string &cClassName, MakeSeq *make_seq); - void write_getset(std::ostream &out, Object *obj, Property *property); - - void write_class_prototypes(std::ostream &out) ; - void write_class_declarations(std::ostream &out, std::ostream *out_h, Object *obj); - void write_class_details(std::ostream &out, Object *obj); - -public: - bool is_remap_legal(FunctionRemap *remap); - int has_coerce_constructor(CPPStructType *type); - bool is_remap_coercion_possible(FunctionRemap *remap); - bool is_function_legal(Function *func); - bool is_cpp_type_legal(CPPType *ctype); - bool isExportThisRun(CPPType *ctype); - bool isExportThisRun(Function *func); - bool isFunctionWithThis( Function *func); - bool IsRunTimeTyped(const InterrogateType &itype); - bool is_python_subclassable(CPPStructType *type); - bool has_self_member(CPPStructType *type); - - // comunicates the cast capabilites among methods.. - struct CastDetails { - CPPStructType *_structType; - std::string _to_class_name; - std::string _up_cast_string; - bool _can_downcast; - bool _is_legal_py_class; - }; - - void get_valid_child_classes(std::map &answer, CPPStructType *inclass, const std::string &upcast_seed = "", bool can_downcast = true); - bool DoesInheritFromIsClass(const CPPStructType * inclass, const std::string &name); - bool IsPandaTypedObject(CPPStructType * inclass) { return DoesInheritFromIsClass(inclass,"TypedObject"); }; - void write_python_instance(std::ostream &out, int indent_level, const std::string &return_expr, bool owns_memory, const InterrogateType &itype, bool is_const); - bool has_get_class_type_function(CPPType *type); - bool has_init_type_function(CPPType *type); - int NeedsAStrFunction(const InterrogateType &itype_class); - int NeedsAReprFunction(const InterrogateType &itype_class); - bool NeedsARichCompareFunction(const InterrogateType &itype_class); - - void output_quoted(std::ostream &out, int indent_level, const std::string &str, - bool first_line=true); - - // stash the forward declarations for this compile pass.. - std::set _external_imports; -}; - -#endif diff --git a/dtool/src/interrogate/interfaceMakerPythonObj.cxx b/dtool/src/interrogate/interfaceMakerPythonObj.cxx deleted file mode 100644 index 4182b0c9a16..00000000000 --- a/dtool/src/interrogate/interfaceMakerPythonObj.cxx +++ /dev/null @@ -1,658 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPythonObj.cxx - * @author drose - * @date 2001-09-19 - */ - -#include "interfaceMakerPythonObj.h" -#include "interrogateBuilder.h" -#include "interrogate.h" -#include "functionRemap.h" -#include "parameterRemapUnchanged.h" -#include "typeManager.h" -#include "functionWriterPtrFromPython.h" -#include "functionWriterPtrToPython.h" - -#include "interrogateDatabase.h" -#include "interrogateType.h" -#include "interrogateFunction.h" -#include "cppFunctionType.h" - -using std::ostream; -using std::string; - -/** - * - */ -InterfaceMakerPythonObj:: -InterfaceMakerPythonObj(InterrogateModuleDef *def) : - InterfaceMakerPython(def) -{ -} - -/** - * - */ -InterfaceMakerPythonObj:: -~InterfaceMakerPythonObj() { -} - -/** - * Generates the list of function prototypes corresponding to the functions - * that will be output in write_functions(). - */ -void InterfaceMakerPythonObj:: -write_prototypes(ostream &out, ostream *out_h) { - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - write_prototype_for(out, func); - } - - out << "\n"; - InterfaceMakerPython::write_prototypes(out,out_h); -} - -/** - * Generates the list of functions that are appropriate for this interface. - * This function is called *before* write_prototypes(), above. - */ -void InterfaceMakerPythonObj:: -write_functions(ostream &out) { - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - write_function_for(out, func); - } - - InterfaceMakerPython::write_functions(out); - - // Finally, generate all the make-class-wrapper functions. - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - - write_class_wrapper(out, object); - } -} - -/** - * Generates whatever additional code is required to support a module file. - */ -void InterfaceMakerPythonObj:: -write_module(ostream &out,ostream *out_h, InterrogateModuleDef *def) { - InterfaceMakerPython::write_module(out,out_h, def); - - out << "static PyMethodDef python_obj_funcs[] = {\n"; - - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - Object *object = (*oi).second; - - Functions::iterator fi; - for (fi = object->_constructors.begin(); - fi != object->_constructors.end(); - ++fi) { - Function *func = (*fi); - out << " { \"" << func->_ifunc.get_name() << "\", &" << func->_name - << ", METH_VARARGS, nullptr },\n"; - } - } - out << " { nullptr, nullptr, 0, nullptr }\n" - << "};\n\n" - - << "#if PY_MAJOR_VERSION >= 3\n" - << "static struct PyModuleDef python_obj_module = {\n" - << " PyModuleDef_HEAD_INIT,\n" - << " \"" << def->library_name << "\",\n" - << " nullptr,\n" - << " -1,\n" - << " python_obj_funcs,\n" - << " nullptr, nullptr, nullptr, nullptr\n" - << "};\n\n" - - << "#define INIT_FUNC PyObject *PyInit_" << def->library_name << "\n" - << "#else\n" - << "#define INIT_FUNC void init" << def->library_name << "\n" - << "#endif\n\n" - - << "#ifdef _WIN32\n" - << "extern \"C\" __declspec(dllexport) INIT_FUNC();\n" - << "#elif __GNUC__ >= 4\n" - << "extern \"C\" __attribute__((visibility(\"default\"))) INIT_FUNC();\n" - << "#else\n" - << "extern \"C\" INIT_FUNC();\n" - << "#endif\n\n" - - << "INIT_FUNC() {\n" - << "#if PY_MAJOR_VERSION >= 3\n" - << " return PyModule_Create(&python_obj_module);\n" - << "#else\n" - << " Py_InitModule(\"" << def->library_name << "\", python_obj_funcs);\n" - << "#endif\n" - << "}\n\n"; -} - -/** - * This method should be overridden and redefined to return true for - * interfaces that require the implicit "this" parameter, if present, to be - * passed as the first parameter to any wrapper functions. - */ -bool InterfaceMakerPythonObj:: -synthesize_this_parameter() { - return true; -} - -/** - * Returns the name of the InterfaceMaker function generated to define the - * Python class for the indicated struct type. - */ -string InterfaceMakerPythonObj:: -get_builder_name(CPPType *struct_type) { - return "get_python_class_" + - InterrogateBuilder::clean_identifier(struct_type->get_local_name(&parser)); -} - -/** - * Returns the prefix string used to generate wrapper function names. - */ -string InterfaceMakerPythonObj:: -get_wrapper_prefix() { - return "wpo_"; -} - -/** - * Writes a function that will define the Python class. - */ -void InterfaceMakerPythonObj:: -write_class_wrapper(ostream &out, InterfaceMaker::Object *object) { - CPPType *struct_type = object->_itype._cpptype; - if (struct_type == nullptr) { - return; - } - - string name = get_builder_name(struct_type); - string python_name = - InterrogateBuilder::clean_identifier(struct_type->get_simple_name()); - - out << "/*\n" - << " * Generate unique Python class for " - << struct_type->get_local_name(&parser) << "\n" - << " */\n" - << "PyObject *\n" - << name << "() {\n" - << " static PyObject *wrapper = nullptr;\n" - << " static PyMethodDef methods[] = {\n"; - - int methods_size = 0; - int class_methods_size = 0; - - Functions::iterator fi; - for (fi = object->_methods.begin(); fi != object->_methods.end(); ++fi) { - Function *func = (*fi); - if (func->_has_this) { - out << " { \"" << func->_ifunc.get_name() << "\", &" << func->_name - << ", METH_VARARGS },\n"; - methods_size++; - } - } - - out << " };\n" - << " static const int methods_size = " << methods_size << ";\n\n" - << " static PyMethodDef class_methods[] = {\n"; - - for (fi = object->_methods.begin(); fi != object->_methods.end(); ++fi) { - Function *func = (*fi); - if (!func->_has_this) { - out << " { \"" << func->_ifunc.get_name() << "\", &" << func->_name - << ", METH_VARARGS },\n"; - class_methods_size++; - } - } - - out << " };\n" - << " static const int class_methods_size = " << class_methods_size << ";\n\n" - << " if (wrapper == nullptr) {\n" - << " int i;\n" - << " PyObject *bases = PyTuple_New(0);\n" - << " PyObject *dict = PyDict_New();\n" - << "#if PY_MAJOR_VERSION >= 3\n" - << " PyObject *name = PyUnicode_FromString(\"" << python_name << "\");\n" - << "#else\n" - << " PyObject *name = PyString_FromString(\"" << python_name << "\");\n" - << "#endif\n" - << " wrapper = PyClass_New(bases, dict, name);\n" - << " for (i = 0; i < methods_size; ++i) {\n" - << " PyObject *function, *method;\n" - << " function = PyCFunction_New(&methods[i], nullptr);\n" - << " method = PyMethod_New(function, nullptr, wrapper);\n" - << " PyDict_SetItemString(dict, methods[i].ml_name, method);\n" - << " }\n" - << " for (i = 0; i < class_methods_size; ++i) {\n" - << " PyObject *function;\n" - << " function = PyCFunction_New(&class_methods[i], nullptr);\n" - << " PyDict_SetItemString(dict, class_methods[i].ml_name, function);\n" - << " }\n" - << " }\n" - << " return wrapper;\n" - << "}\n\n"; -} - -/** - * Writes the prototype for the indicated function. - */ -void InterfaceMakerPythonObj:: -write_prototype_for(ostream &out, InterfaceMaker::Function *func) { - out << "static PyObject *" - << func->_name << "(PyObject *self, PyObject *args);\n"; -} - -/** - * Writes the definition for a function that will call the indicated C++ - * function or method. - */ -void InterfaceMakerPythonObj:: -write_function_for(ostream &out, InterfaceMaker::Function *func) { - Function::Remaps::const_iterator ri; - out << "/*\n" - << " * Python object wrapper for\n"; - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - out << " * "; - remap->write_orig_prototype(out, 0); - out << "\n"; - } - out << " */\n"; - - out << "static PyObject *" - << func->_name << "(PyObject *, PyObject *args) {\n"; - - // Now write out each instance of the overloaded function. - string expected_params = "Arguments must match one of:"; - - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - expected_params += "\\n "; - write_function_instance(out, 2, func, remap, expected_params); - } - - // If we get here in the generated code, none of the parameters were valid. - // Generate an error exception. (We don't rely on the error already - // generated by ParseTuple(), because it only reports the error for one - // flavor of the function, whereas we might accept multiple flavors for the - // different overloaded C++ function signatures. - - out << " PyErr_SetString(PyExc_TypeError, \"" << expected_params << "\");\n" - << " return nullptr;\n"; - - out << "}\n\n"; -} - -/** - * Writes out the part of a function that handles a single instance of an - * overloaded function. - */ -void InterfaceMakerPythonObj:: -write_function_instance(ostream &out, int indent_level, - InterfaceMaker::Function *func, - FunctionRemap *remap, string &expected_params) { - indent(out, indent_level) << "{\n"; - indent(out, indent_level + 2) << "/* "; - remap->write_orig_prototype(out, 0); - out << " */\n\n"; - - string format_specifiers; - string parameter_list; - vector_string pexprs; - string extra_convert; - string extra_param_check; - string extra_cleanup; - - // Make one pass through the parameter list. We will output a one-line - // temporary variable definition for each parameter, while simultaneously - // building the ParseTuple() function call and also the parameter expression - // list for call_function(). - - expected_params += remap->_cppfunc->get_simple_name(); - expected_params += "("; - - int pn; - for (pn = 0; pn < (int)remap->_parameters.size(); pn++) { - if (pn != 0) { - expected_params += ", "; - } - - indent(out, indent_level + 2); - CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type(); - CPPType *type = remap->_parameters[pn]._remap->get_new_type(); - string param_name = remap->get_parameter_name(pn); - - // This is the string to convert our local variable to the appropriate C++ - // type. Normally this is just a cast. - string pexpr_string = - "(" + type->get_local_name(&parser) + ")" + param_name; - - if (remap->_parameters[pn]._remap->new_type_is_atomic_string()) { - if (TypeManager::is_char_pointer(orig_type)) { - out << "char *" << param_name; - format_specifiers += "s"; - parameter_list += ", &" + param_name; - - } else { - out << "char *" << param_name - << "_str; Py_ssize_t " << param_name << "_len"; - format_specifiers += "s#"; - parameter_list += ", &" + param_name - + "_str, &" + param_name + "_len"; - pexpr_string = "basic_string(" + - param_name + "_str, " + - param_name + "_len)"; - } - expected_params += "string"; - - } else if (TypeManager::is_bool(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - pexpr_string = "(PyObject_IsTrue(" + param_name + ")!=0)"; - expected_params += "bool"; - - } else if (TypeManager::is_unsigned_longlong(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; - extra_param_check += "|| (" + param_name + "_long == nullptr)"; - pexpr_string = "PyLong_AsUnsignedLongLong(" + param_name + "_long)"; - extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; - expected_params += "long"; - - } else if (TypeManager::is_longlong(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; - extra_param_check += "|| (" + param_name + "_long == nullptr)"; - pexpr_string = "PyLong_AsLongLong(" + param_name + "_long)"; - extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; - expected_params += "long"; - - } else if (TypeManager::is_unsigned_integer(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - extra_convert += " PyObject *" + param_name + "_uint = PyNumber_Long(" + param_name + ");"; - extra_param_check += "|| (" + param_name + "_uint == nullptr)"; - pexpr_string = "(unsigned int)PyLong_AsUnsignedLong(" + param_name + "_uint)"; - extra_cleanup += " Py_XDECREF(" + param_name + "_uint);"; - expected_params += "unsigned int"; - - } else if (TypeManager::is_integer(type)) { - out << "int " << param_name; - format_specifiers += "i"; - parameter_list += ", &" + param_name; - expected_params += "integer"; - - } else if (TypeManager::is_float(type)) { - out << "double " << param_name; - format_specifiers += "d"; - parameter_list += ", &" + param_name; - expected_params += "float"; - - } else if (TypeManager::is_char_pointer(type)) { - out << "char *" << param_name; - format_specifiers += "s"; - parameter_list += ", &" + param_name; - expected_params += "string"; - - } else if (TypeManager::is_pointer(type)) { - FunctionWriterPtrFromPython *writer = get_ptr_from_python(type); - writer->get_pointer_type()->output_instance(out, param_name, &parser); - format_specifiers += "O&"; - parameter_list += ", &" + writer->get_name() + ", &" + param_name; - expected_params += writer->get_type()->get_preferred_name(); - - } else { - // Ignore a parameter. - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - expected_params += "any"; - } - - if (remap->_parameters[pn]._has_name) { - expected_params += " " + remap->_parameters[pn]._name; - } - - out << ";\n"; - pexprs.push_back(pexpr_string); - } - expected_params += ")"; - - indent(out, indent_level + 2) - << "if (PyArg_ParseTuple(args, \"" << format_specifiers - << "\"" << parameter_list << ")) {\n"; - - if (!extra_convert.empty()) { - indent(out, indent_level + 3) - << extra_convert << "\n"; - } - - if (!extra_param_check.empty()) { - indent(out, indent_level + 4) - << "if (" << extra_param_check.substr(3) << ") {\n"; - if (!extra_cleanup.empty()) { - indent(out, indent_level + 5) - << extra_cleanup << "\n"; - } - indent(out, indent_level + 6) - << "PyErr_SetString(PyExc_TypeError, \"Invalid parameters.\");\n"; - indent(out, indent_level + 6) - << "return nullptr;\n"; - indent(out, indent_level + 4) - << "}\n"; - } - - if (track_interpreter) { - indent(out, indent_level + 4) - << "in_interpreter = 0;\n"; - } - - if (!remap->_void_return && - remap->_return_type->new_type_is_atomic_string()) { - // Treat strings as a special case. We don't want to format the return - // expression. - string return_expr = - remap->call_function(out, indent_level + 4, false, "param0", pexprs); - - CPPType *type = remap->_return_type->get_orig_type(); - indent(out, indent_level + 4); - type->output_instance(out, "return_value", &parser); - out << " = " << return_expr << ";\n"; - - if (track_interpreter) { - indent(out, indent_level + 4) - << "in_interpreter = 1;\n"; - } - if (!extra_cleanup.empty()) { - indent(out, indent_level + 3) - << extra_cleanup << "\n"; - } - - return_expr = manage_return_value(out, indent_level + 4, remap, "return_value"); - test_assert(out, indent_level + 4); - pack_return_value(out, indent_level + 4, remap, return_expr); - - } else { - string return_expr = - remap->call_function(out, indent_level + 4, true, "param0", pexprs); - if (return_expr.empty()) { - if (track_interpreter) { - indent(out, indent_level + 4) - << "in_interpreter = 1;\n"; - } - if (!extra_cleanup.empty()) { - indent(out, indent_level + 3) - << extra_cleanup << "\n"; - } - test_assert(out, indent_level + 4); - indent(out, indent_level + 4) - << "return Py_BuildValue(\"\");\n"; - - } else { - CPPType *type = remap->_return_type->get_temporary_type(); - indent(out, indent_level + 4); - type->output_instance(out, "return_value", &parser); - out << " = " << return_expr << ";\n"; - if (track_interpreter) { - indent(out, indent_level + 4) - << "in_interpreter = 1;\n"; - } - if (!extra_cleanup.empty()) { - indent(out, indent_level + 3) - << extra_cleanup << "\n"; - } - - return_expr = manage_return_value(out, indent_level + 4, remap, "return_value"); - test_assert(out, indent_level + 4); - pack_return_value(out, indent_level + 4, remap, remap->_return_type->temporary_to_return(return_expr)); - } - } - - indent(out, indent_level + 2) << "}\n"; - indent(out, indent_level + 2) - << "PyErr_Clear();\n"; // Clear the error generated by ParseTuple() - indent(out, indent_level) - << "}\n"; -} - -/** - * Outputs a command to pack the indicated expression, of the return_type - * type, as a Python return value. - */ -void InterfaceMakerPythonObj:: -pack_return_value(ostream &out, int indent_level, - FunctionRemap *remap, string return_expr) { - CPPType *orig_type = remap->_return_type->get_orig_type(); - CPPType *type = remap->_return_type->get_new_type(); - - if (remap->_return_type->new_type_is_atomic_string()) { - if (TypeManager::is_char_pointer(orig_type)) { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyUnicode_FromString(" << return_expr << ");\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyString_FromString(" << return_expr << ");\n"; - out << "#endif\n"; - - } else { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyUnicode_FromStringAndSize(" - << return_expr << ".data(), (Py_ssize_t)" << return_expr << ".length());\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyString_FromStringAndSize(" - << return_expr << ".data(), (Py_ssize_t)" << return_expr << ".length());\n"; - out << "#endif\n"; - } - - } else if (TypeManager::is_bool(type)) { - indent(out, indent_level) - << "return PyBool_FromLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_unsigned_longlong(type)) { - indent(out, indent_level) - << "return PyLong_FromUnsignedLongLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_longlong(type)) { - indent(out, indent_level) - << "return PyLong_FromLongLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_unsigned_integer(type)) { - indent(out, indent_level) - << "return PyLong_FromUnsignedLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_integer(type)) { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyLong_FromLong(" << return_expr << ");\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyInt_FromLong(" << return_expr << ");\n"; - out << "#endif\n"; - - } else if (TypeManager::is_float(type)) { - indent(out, indent_level) - << "return PyFloat_FromDouble(" << return_expr << ");\n"; - - } else if (TypeManager::is_char_pointer(type)) { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyUnicode_FromString(" << return_expr << ");\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyString_FromString(" << return_expr << ");\n"; - out << "#endif\n"; - - } else if (TypeManager::is_pointer(type)) { - bool caller_manages = remap->_return_value_needs_management; - - FunctionWriterPtrToPython *writer = get_ptr_to_python(type); - indent(out, indent_level) - << "return " << writer->get_name() << "((" - << writer->get_pointer_type()->get_local_name(&parser) << ")" - << return_expr << ", " << caller_manages << ");\n"; - - } else { - // Return None. - indent(out, indent_level) - << "return Py_BuildValue(\"\");\n"; - } -} - -/** - * Returns a FunctionWriter pointer suitable for converting from a Python - * wrapper of the indicated type to the corresponding C++ pointer. - */ -FunctionWriterPtrFromPython *InterfaceMakerPythonObj:: -get_ptr_from_python(CPPType *type) { - PtrConverter::iterator ci; - ci = _from_python.find(type); - if (ci != _from_python.end()) { - // We've previously used this type. - return (FunctionWriterPtrFromPython *)(*ci).second; - } - - FunctionWriter *writer = - _function_writers.add_writer(new FunctionWriterPtrFromPython(type)); - _from_python.insert(PtrConverter::value_type(type, writer)); - return (FunctionWriterPtrFromPython *)writer; -} - -/** - * Returns a FunctionWriter pointer suitable for converting from a C++ pointer - * of the indicated type to the corresponding Python wrapper. - */ -FunctionWriterPtrToPython *InterfaceMakerPythonObj:: -get_ptr_to_python(CPPType *type) { - PtrConverter::iterator ci; - ci = _to_python.find(type); - if (ci != _to_python.end()) { - // We've previously used this type. - return (FunctionWriterPtrToPython *)(*ci).second; - } - - FunctionWriter *writer = - _function_writers.add_writer(new FunctionWriterPtrToPython(type)); - _to_python.insert(PtrConverter::value_type(type, writer)); - return (FunctionWriterPtrToPython *)writer; -} diff --git a/dtool/src/interrogate/interfaceMakerPythonObj.h b/dtool/src/interrogate/interfaceMakerPythonObj.h deleted file mode 100644 index be7e0d99138..00000000000 --- a/dtool/src/interrogate/interfaceMakerPythonObj.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPythonObj.h - * @author drose - * @date 2001-09-19 - */ - -#ifndef INTERFACEMAKERPYTHONOBJ_H -#define INTERFACEMAKERPYTHONOBJ_H - -#include "dtoolbase.h" - -#include "interfaceMakerPython.h" -#include "interrogate_interface.h" - -#include - -class InterrogateType; -class InterrogateFunction; -class FunctionRemap; -class CPPInstance; -class FunctionWriterPtrFromPython; -class FunctionWriterPtrToPython; - -/** - * An InterfaceMaker suitable for generating object-oriented Python code, that - * can be imported and used directly by Python. - */ -class InterfaceMakerPythonObj : public InterfaceMakerPython { -public: - InterfaceMakerPythonObj(InterrogateModuleDef *def); - virtual ~InterfaceMakerPythonObj(); - - virtual void write_prototypes(std::ostream &out,std::ostream *out_h); - virtual void write_functions(std::ostream &out); - - virtual void write_module(std::ostream &out,std::ostream *out_h, InterrogateModuleDef *def); - - virtual bool synthesize_this_parameter(); - - static std::string get_builder_name(CPPType *struct_type); - -protected: - virtual std::string get_wrapper_prefix(); - -private: - void write_class_wrapper(std::ostream &out, Object *object); - void write_prototype_for(std::ostream &out, Function *func); - void write_function_for(std::ostream &out, Function *func); - void write_function_instance(std::ostream &out, int indent_level, Function *func, - FunctionRemap *remap, std::string &expected_params); - - void pack_return_value(std::ostream &out, int indent_level, - FunctionRemap *remap, std::string return_expr); - - FunctionWriterPtrFromPython *get_ptr_from_python(CPPType *type); - FunctionWriterPtrToPython *get_ptr_to_python(CPPType *type); - - typedef std::map PtrConverter; - PtrConverter _from_python; - PtrConverter _to_python; -}; - -#endif diff --git a/dtool/src/interrogate/interfaceMakerPythonSimple.cxx b/dtool/src/interrogate/interfaceMakerPythonSimple.cxx deleted file mode 100644 index cda042efd71..00000000000 --- a/dtool/src/interrogate/interfaceMakerPythonSimple.cxx +++ /dev/null @@ -1,523 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPythonSimple.cxx - * @author drose - * @date 2001-10-01 - */ - -#include "interfaceMakerPythonSimple.h" -#include "interrogateBuilder.h" -#include "interrogate.h" -#include "functionRemap.h" -#include "parameterRemapUnchanged.h" -#include "typeManager.h" - -#include "interrogateDatabase.h" -#include "interrogateType.h" -#include "interrogateFunction.h" -#include "cppFunctionType.h" - -using std::ostream; -using std::string; - -/** - * - */ -InterfaceMakerPythonSimple:: -InterfaceMakerPythonSimple(InterrogateModuleDef *def) : - InterfaceMakerPython(def) -{ -} - -/** - * - */ -InterfaceMakerPythonSimple:: -~InterfaceMakerPythonSimple() { -} - -/** - * Generates the list of function prototypes corresponding to the functions - * that will be output in write_functions(). - */ -void InterfaceMakerPythonSimple:: -write_prototypes(ostream &out,ostream *out_h) { - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - write_prototype_for(out, func); - } - - out << "\n"; - InterfaceMakerPython::write_prototypes(out,out_h); -} - -/** - * Generates the list of functions that are appropriate for this interface. - * This function is called *before* write_prototypes(), above. - */ -void InterfaceMakerPythonSimple:: -write_functions(ostream &out) { - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - write_function_for(out, func); - } - - InterfaceMakerPython::write_functions(out); -} - -/** - * Generates whatever additional code is required to support a module file. - */ -void InterfaceMakerPythonSimple:: -write_module(ostream &out,ostream *out_h, InterrogateModuleDef *def) { - InterfaceMakerPython::write_module(out,out_h, def); - - out << "static PyMethodDef python_simple_funcs[] = {\n"; - - FunctionsByIndex::iterator fi; - for (fi = _functions.begin(); fi != _functions.end(); ++fi) { - Function *func = (*fi).second; - Function::Remaps::const_iterator ri; - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - out << " { \"" << remap->_reported_name << "\", &" - << remap->_wrapper_name << ", METH_VARARGS, nullptr },\n"; - } - } - out << " { nullptr, nullptr, 0, nullptr }\n" - << "};\n\n" - - << "#if PY_MAJOR_VERSION >= 3\n" - << "static struct PyModuleDef python_simple_module = {\n" - << " PyModuleDef_HEAD_INIT,\n" - << " \"" << def->module_name << "\",\n" - << " nullptr,\n" - << " -1,\n" - << " python_simple_funcs,\n" - << " nullptr, nullptr, nullptr, nullptr\n" - << "};\n\n" - - << "#define INIT_FUNC PyObject *PyInit_" << def->library_name << "\n" - << "#else\n" - << "#define INIT_FUNC void init" << def->library_name << "\n" - << "#endif\n\n" - - << "#ifdef _WIN32\n" - << "extern \"C\" __declspec(dllexport) INIT_FUNC();\n" - << "#elif __GNUC__ >= 4\n" - << "extern \"C\" __attribute__((visibility(\"default\"))) INIT_FUNC();\n" - << "#else\n" - << "extern \"C\" INIT_FUNC();\n" - << "#endif\n\n" - - << "INIT_FUNC() {\n" - << "#if PY_MAJOR_VERSION >= 3\n" - << " return PyModule_Create(&python_simple_module);\n" - << "#else\n" - << " Py_InitModule(\"" << def->library_name << "\", python_simple_funcs);\n" - << "#endif\n" - << "}\n\n"; -} - -/** - * This method should be overridden and redefined to return true for - * interfaces that require the implicit "this" parameter, if present, to be - * passed as the first parameter to any wrapper functions. - */ -bool InterfaceMakerPythonSimple:: -synthesize_this_parameter() { - return true; -} - -/** - * Returns the prefix string used to generate wrapper function names. - */ -string InterfaceMakerPythonSimple:: -get_wrapper_prefix() { - return "_inP"; -} - -/** - * Returns the prefix string used to generate unique symbolic names, which are - * not necessarily C-callable function names. - */ -string InterfaceMakerPythonSimple:: -get_unique_prefix() { - return "p"; -} - -/** - * Associates the function wrapper with its function in the appropriate - * structures in the database. - */ -void InterfaceMakerPythonSimple:: -record_function_wrapper(InterrogateFunction &ifunc, - FunctionWrapperIndex wrapper_index) { - ifunc._python_wrappers.push_back(wrapper_index); -} - -/** - * Writes the prototype for the indicated function. - */ -void InterfaceMakerPythonSimple:: -write_prototype_for(ostream &out, InterfaceMaker::Function *func) { - Function::Remaps::const_iterator ri; - - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - if (!output_function_names) { - // If we're not saving the function names, don't export it from the - // library. - out << "static "; - } else { - out << "extern \"C\" "; - } - out << "PyObject *" - << remap->_wrapper_name << "(PyObject *self, PyObject *args);\n"; - } -} - -/** - * Writes the definition for a function that will call the indicated C++ - * function or method. - */ -void InterfaceMakerPythonSimple:: -write_function_for(ostream &out, InterfaceMaker::Function *func) { - Function::Remaps::const_iterator ri; - - for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - write_function_instance(out, func, remap); - } -} - -/** - * Writes out the particular function that handles a single instance of an - * overloaded function. - */ -void InterfaceMakerPythonSimple::write_function_instance(ostream &out, InterfaceMaker::Function *func, - FunctionRemap *remap) { - out << "/*\n" - << " * Python simple wrapper for\n" - << " * "; - remap->write_orig_prototype(out, 0); - out << "\n" - << " */\n"; - - if (!output_function_names) { - // If we're not saving the function names, don't export it from the - // library. - out << "static "; - } - - out << "PyObject *\n" - << remap->_wrapper_name << "(PyObject *, PyObject *args) {\n"; - - if (generate_spam) { - write_spam_message(out, remap); - } - - string format_specifiers; - string parameter_list; - string container; - vector_string pexprs; - string extra_convert; - string extra_param_check; - string extra_cleanup; - - // Make one pass through the parameter list. We will output a one-line - // temporary variable definition for each parameter, while simultaneously - // building the ParseTuple() function call and also the parameter expression - // list for call_function(). - - int pn; - for (pn = 0; pn < (int)remap->_parameters.size(); ++pn) { - indent(out, 2); - CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type(); - CPPType *type = remap->_parameters[pn]._remap->get_new_type(); - string param_name = remap->get_parameter_name(pn); - - // This is the string to convert our local variable to the appropriate C++ - // type. Normally this is just a cast. - string pexpr_string = - "(" + type->get_local_name(&parser) + ")" + param_name; - - if (remap->_parameters[pn]._remap->new_type_is_atomic_string()) { - if (TypeManager::is_char_pointer(orig_type)) { - out << "char *" << param_name; - format_specifiers += "s"; - parameter_list += ", &" + param_name; - - } else if (TypeManager::is_wstring(orig_type)) { - out << "Py_UNICODE *" << param_name - << "_str; Py_ssize_t " << param_name << "_len"; - format_specifiers += "u#"; - parameter_list += ", &" + param_name - + "_str, &" + param_name + "_len"; - pexpr_string = "basic_string((wchar_t *)" + - param_name + "_str, " + - param_name + "_len)"; - - } else { - out << "char *" << param_name - << "_str; Py_ssize_t " << param_name << "_len"; - format_specifiers += "s#"; - parameter_list += ", &" + param_name - + "_str, &" + param_name + "_len"; - pexpr_string = "basic_string(" + - param_name + "_str, " + - param_name + "_len)"; - } - - } else if (TypeManager::is_bool(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - pexpr_string = "(PyObject_IsTrue(" + param_name + ")!=0)"; - - } else if (TypeManager::is_unsigned_longlong(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; - extra_param_check += "|| (" + param_name + "_long == nullptr)"; - pexpr_string = "PyLong_AsUnsignedLongLong(" + param_name + "_long)"; - extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; - - } else if (TypeManager::is_longlong(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");"; - extra_param_check += "|| (" + param_name + "_long == nullptr)"; - pexpr_string = "PyLong_AsLongLong(" + param_name + "_long)"; - extra_cleanup += " Py_XDECREF(" + param_name + "_long);"; - - } else if (TypeManager::is_unsigned_integer(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - extra_convert += " PyObject *" + param_name + "_uint = PyNumber_Long(" + param_name + ");"; - extra_param_check += "|| (" + param_name + "_uint == nullptr)"; - pexpr_string = "(unsigned int)PyLong_AsUnsignedLong(" + param_name + "_uint)"; - extra_cleanup += " Py_XDECREF(" + param_name + "_uint);"; - - } else if (TypeManager::is_integer(type)) { - out << "int " << param_name; - format_specifiers += "i"; - parameter_list += ", &" + param_name; - - } else if (TypeManager::is_float(type)) { - out << "double " << param_name; - format_specifiers += "d"; - parameter_list += ", &" + param_name; - - } else if (TypeManager::is_char_pointer(type)) { - out << "char *" << param_name; - format_specifiers += "s"; - parameter_list += ", &" + param_name; - - } else if (TypeManager::is_pointer_to_PyObject(type)) { - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - pexpr_string = param_name; - - } else if (TypeManager::is_pointer(type)) { - out << "Py_ssize_t " << param_name; - format_specifiers += "n"; - parameter_list += ", &" + param_name; - - } else { - // Ignore a parameter. - out << "PyObject *" << param_name; - format_specifiers += "O"; - parameter_list += ", &" + param_name; - } - - out << ";\n"; - if (remap->_has_this && pn == 0) { - // The "this" parameter gets passed in separately. - container = pexpr_string; - } - pexprs.push_back(pexpr_string); - } - - out << " if (PyArg_ParseTuple(args, \"" << format_specifiers - << "\"" << parameter_list << ")) {\n"; - - if (!extra_convert.empty()) { - out << " " << extra_convert << "\n"; - } - - if (!extra_param_check.empty()) { - out << " if (" << extra_param_check.substr(3) << ") {\n"; - if (!extra_cleanup.empty()) { - out << " " << extra_cleanup << "\n"; - } - out << " PyErr_SetString(PyExc_TypeError, \"Invalid parameters.\");\n" - << " return nullptr;\n" - << " }\n"; - } - - if (track_interpreter) { - out << " in_interpreter = 0;\n"; - } - - if (!remap->_void_return && - remap->_return_type->new_type_is_atomic_string()) { - // Treat strings as a special case. We don't want to format the return - // expression. - string return_expr = remap->call_function(out, 4, false, container, pexprs); - CPPType *type = remap->_return_type->get_orig_type(); - out << " "; - type->output_instance(out, "return_value", &parser); - out << " = " << return_expr << ";\n"; - - if (track_interpreter) { - out << " in_interpreter = 1;\n"; - } - if (!extra_cleanup.empty()) { - out << " " << extra_cleanup << "\n"; - } - - return_expr = manage_return_value(out, 4, remap, "return_value"); - test_assert(out, 4); - pack_return_value(out, 4, remap, return_expr); - - } else { - string return_expr = remap->call_function(out, 4, true, container, pexprs); - if (return_expr.empty()) { - if (track_interpreter) { - out << " in_interpreter = 1;\n"; - } - if (!extra_cleanup.empty()) { - out << " " << extra_cleanup << "\n"; - } - test_assert(out, 4); - out << " return Py_BuildValue(\"\");\n"; - - } else { - CPPType *type = remap->_return_type->get_temporary_type(); - out << " "; - type->output_instance(out, "return_value", &parser); - out << " = " << return_expr << ";\n"; - if (track_interpreter) { - out << " in_interpreter = 1;\n"; - } - if (!extra_cleanup.empty()) { - out << " " << extra_cleanup << "\n"; - } - - return_expr = manage_return_value(out, 4, remap, "return_value"); - test_assert(out, 4); - pack_return_value(out, 4, remap, remap->_return_type->temporary_to_return(return_expr)); - } - } - - out << " }\n"; - - out << " return nullptr;\n"; - out << "}\n\n"; -} - -/** - * Outputs a command to pack the indicated expression, of the return_type - * type, as a Python return value. - */ -void InterfaceMakerPythonSimple:: -pack_return_value(ostream &out, int indent_level, - FunctionRemap *remap, string return_expr) { - CPPType *orig_type = remap->_return_type->get_orig_type(); - CPPType *type = remap->_return_type->get_new_type(); - - if (remap->_return_type->new_type_is_atomic_string()) - { - if (TypeManager::is_char_pointer(orig_type)) { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyUnicode_FromString(" << return_expr << ");\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyString_FromString(" << return_expr << ");\n"; - out << "#endif\n"; - - } else if (TypeManager::is_wstring(orig_type)) { - indent(out, indent_level) - << "return PyUnicode_FromWideChar(" - << return_expr << ".data(), (int)" << return_expr << ".length());\n"; - - } else { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyUnicode_FromStringAndSize(" - << return_expr << ".data(), (Py_ssize_t)" << return_expr << ".length());\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyString_FromStringAndSize(" - << return_expr << ".data(), (Py_ssize_t)" << return_expr << ".length());\n"; - out << "#endif\n"; - } - - } else if (TypeManager::is_bool(type)) { - indent(out, indent_level) - << "return PyBool_FromLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_unsigned_longlong(type)) - { - indent(out, indent_level) - << "return PyLong_FromUnsignedLongLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_longlong(type)) - { - indent(out, indent_level) - << "return PyLong_FromLongLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_unsigned_integer(type)) { - indent(out, indent_level) - << "return PyLong_FromUnsignedLong(" << return_expr << ");\n"; - - } else if (TypeManager::is_integer(type)) { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyLong_FromLong(" << return_expr << ");\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyInt_FromLong(" << return_expr << ");\n"; - out << "#endif\n"; - - } else if (TypeManager::is_float(type)) { - indent(out, indent_level) - << "return PyFloat_FromDouble(" << return_expr << ");\n"; - - } else if (TypeManager::is_char_pointer(type)) { - out << "#if PY_MAJOR_VERSION >= 3\n"; - indent(out, indent_level) - << "return PyUnicode_FromString(" << return_expr << ");\n"; - out << "#else\n"; - indent(out, indent_level) - << "return PyString_FromString(" << return_expr << ");\n"; - out << "#endif\n"; - - } else if (TypeManager::is_pointer_to_PyObject(type)) { - indent(out, indent_level) - << "return " << return_expr << ";\n"; - - } else if (TypeManager::is_pointer(type)) { - indent(out, indent_level) - << "return PyLong_FromVoidPtr((void*)" << return_expr << ");\n"; - - } else { - // Return None. - indent(out, indent_level) - << "return Py_BuildValue(\"\");\n"; - } -} diff --git a/dtool/src/interrogate/interfaceMakerPythonSimple.h b/dtool/src/interrogate/interfaceMakerPythonSimple.h deleted file mode 100644 index 18cfc4d590c..00000000000 --- a/dtool/src/interrogate/interfaceMakerPythonSimple.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interfaceMakerPythonSimple.h - * @author drose - * @date 2001-10-01 - */ - -#ifndef INTERFACEMAKERPYTHONSIMPLE_H -#define INTERFACEMAKERPYTHONSIMPLE_H - -#include "dtoolbase.h" - -#include "interfaceMakerPython.h" -#include "interrogate_interface.h" - -class FunctionRemap; - -/** - * An InterfaceMaker for generating simple Python function wrappers around C++ - * code. This allows the C++ code to be called by Python, but not necessarily - * in a user-friendly or object-oriented way. - * - * You probably want to use InterfaceMakerPythonObj for a full object-oriented - * solution. This InterfaceMaker is primarily useful as a stopgap for our old - * Python-based FFI system. - */ -class InterfaceMakerPythonSimple : public InterfaceMakerPython { -public: - InterfaceMakerPythonSimple(InterrogateModuleDef *def); - virtual ~InterfaceMakerPythonSimple(); - - virtual void write_prototypes(std::ostream &out,std::ostream *out_h); - virtual void write_functions(std::ostream &out); - - virtual void write_module(std::ostream &out,std::ostream *out_h, InterrogateModuleDef *def); - - virtual bool synthesize_this_parameter(); - -protected: - virtual std::string get_wrapper_prefix(); - virtual std::string get_unique_prefix(); - - virtual void - record_function_wrapper(InterrogateFunction &ifunc, - FunctionWrapperIndex wrapper_index); - -private: - void write_prototype_for(std::ostream &out, Function *func); - void write_function_for(std::ostream &out, Function *func); - void write_function_instance(std::ostream &out, Function *func, - FunctionRemap *remap); - - void pack_return_value(std::ostream &out, int indent_level, - FunctionRemap *remap, std::string return_expr); -}; - -#endif diff --git a/dtool/src/interrogate/interrogate.cxx b/dtool/src/interrogate/interrogate.cxx deleted file mode 100644 index d0c2bc96d44..00000000000 --- a/dtool/src/interrogate/interrogate.cxx +++ /dev/null @@ -1,638 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate.cxx - * @author drose - * @date 2000-07-31 - */ - -#include "interrogate.h" -#include "interrogateBuilder.h" - -#include "interrogateDatabase.h" -#include "cppGlobals.h" -#include "pnotify.h" -#include "panda_getopt_long.h" -#include "preprocess_argv.h" -#include - -using std::cerr; -using std::string; - -CPPParser parser; - -Filename output_code_filename; -Filename output_include_filename; -Filename output_data_filename; -Filename source_file_directory; -string output_data_basename; -bool output_module_specific = false; -bool output_function_pointers = false; -bool output_function_names = false; -bool convert_strings = false; -bool manage_reference_counts = false; -bool watch_asserts = false; -bool true_wrapper_names = false; -bool build_c_wrappers = false; -bool build_python_wrappers = false; -bool build_python_obj_wrappers = false; -bool build_python_native = false; -bool track_interpreter = false; -bool save_unique_names = false; -bool no_database = false; -bool generate_spam = false; -bool left_inheritance_requires_upcast = true; -bool mangle_names = true; -CPPVisibility min_vis = V_published; -string library_name; -string module_name; - -// Short command-line options. -static const char *short_options = "I:S:D:F:vh"; - -// Long command-line options. -enum CommandOptions { - CO_oc = 256, - CO_od, - CO_srcdir, - CO_module, - CO_library, - CO_do_module, - CO_fptrs, - CO_fnames, - CO_string, - CO_refcount, - CO_assert, - CO_true_names, - CO_c, - CO_python, - CO_python_obj, - CO_python_native, - CO_track_interpreter, - CO_unique_names, - CO_nodb, - CO_longlong, - CO_promiscuous, - CO_spam, - CO_noangles, - CO_nomangle, - CO_help, -}; - -static struct option long_options[] = { - { "oc", required_argument, nullptr, CO_oc }, - { "od", required_argument, nullptr, CO_od }, - { "srcdir", required_argument, nullptr, CO_srcdir }, - { "module", required_argument, nullptr, CO_module }, - { "library", required_argument, nullptr, CO_library }, - { "do-module", no_argument, nullptr, CO_do_module }, - { "fptrs", no_argument, nullptr, CO_fptrs }, - { "fnames", no_argument, nullptr, CO_fnames }, - { "string", no_argument, nullptr, CO_string }, - { "refcount", no_argument, nullptr, CO_refcount }, - { "assert", no_argument, nullptr, CO_assert }, - { "true-names", no_argument, nullptr, CO_true_names }, - { "c", no_argument, nullptr, CO_c }, - { "python", no_argument, nullptr, CO_python }, - { "python-obj", no_argument, nullptr, CO_python_obj }, - { "python-native", no_argument, nullptr, CO_python_native }, - { "track-interpreter", no_argument, nullptr, CO_track_interpreter }, - { "unique-names", no_argument, nullptr, CO_unique_names }, - { "nodb", no_argument, nullptr, CO_nodb }, - { "longlong", required_argument, nullptr, CO_longlong }, - { "promiscuous", no_argument, nullptr, CO_promiscuous }, - { "spam", no_argument, nullptr, CO_spam }, - { "noangles", no_argument, nullptr, CO_noangles }, - { "nomangle", no_argument, nullptr, CO_nomangle }, - { "help", no_argument, nullptr, CO_help }, - { nullptr } -}; - -void -show_usage() { - cerr - << "\nUsage:\n" - << " interrogate [opts] file.C [file.C ...]\n" - << " interrogate -h\n\n"; -} - -void show_help() { - show_usage(); - cerr - << "Interrogate is a program to parse a body of C++ code and build up a table\n" - << "of classes, methods, functions, and symbols found, for the purposes of\n" - << "calling into the codebase via a non-C++ scripting language like Scheme,\n" - << "Smalltalk, or Python.\n\n" - - << "In addition to identifying all the classes and their relationships,\n" - << "interrogate will generate a wrapper function for each callable function.\n" - << "The wrapper functions will be callable directly from the scripting language,\n" - << "with no understanding of C++ necessary; these wrapper functions will in turn\n" - << "call the actual C++ functions or methods.\n\n" - - << "Most exportable features of C++ are supported, including templates, default\n" - << "parameters, and function overloading.\n\n" - - << "Options:\n\n" - - << " -oc output.C\n" - << " Specify the name of the file to which generated code will be written.\n" - << " This includes all of the function wrappers, as well as those tables\n" - << " which must be compiled into the library.\n\n" - - << " -od output.in\n" - << " Specify the name of the file to which the non-compiled data tables\n" - << " will be written. This file describes the relationships between\n" - << " all the types and the functions, and associates the function wrappers\n" - << " above with this data. This file will be opened and read at runtime\n" - << " when the scripting language first calls some interrogate query\n" - << " function.\n\n" - - << " -srcdir directory\n" - << " Specify the name of the directory to which the source filenames are\n" - << " relative.\n\n" - - << " -module module_name\n" - << " Defines the name of the module this data is associated with. This\n" - << " is strictly a code-organizational tool. Conceptually, a module is\n" - << " the highest level of grouping for interrogate data; a module may\n" - << " contain several libraries. If this is omitted, no module name is\n" - << " specified.\n\n" - - << " Sometimes, depending on the type of wrappers being generated, there\n" - << " may be additional code that needs to be generated on the module\n" - << " level, above that which was already generated at the library level.\n" - << " Python, for instance, generates the table of python-callable function\n" - << " wrappers at the module level. Use the program interrogate-module\n" - << " to generate the appropriate code at the module level.\n\n" - - << " -library library_name\n" - << " Defines the name of the library this data is associated with. This\n" - << " is another code-organizational tool. Typically, there will be one\n" - << " invocation of interrogate for each library, and there will be\n" - << " multiple libraries per module. If this is omitted, no library name\n" - << " is specified.\n\n" - - << " -do-module\n" - << " Generate whatever module-level code should be generated immediately,\n" - << " rather than waiting for a special interrogate-module pass.\n" - << " This, of course, prohibits grouping several libraries together\n" - << " into a single module.\n\n" - - << " -fptrs\n" - << " Make void* pointers to the function wrappers directly available. A\n" - << " scripting language will be able to call the interrogate functions\n" - << " directly by pointer.\n\n" - - << " -fnames\n" - << " Make the names of the function wrappers public symbols so that the\n" - << " scripting language will be able to call the interrogate functions\n" - << " by name.\n\n" - - << " Either or both of -fptrs and/or -fnames may be specified. If both are\n" - << " omitted, the default is -fnames.\n\n" - - << " -string\n" - << " Treat char* and basic_string as special cases, and map\n" - << " parameters of these types to type atomic string. The scripting\n" - << " language will see only functions that receive and return strings,\n" - << " not pointers to character or structures of basic_string.\n" - << " If C calling convention wrappers are being generated, the atomic\n" - << " string type means type char*. In any other calling convention, the\n" - << " atomic string type is whatever the native string type is.\n\n" - - << " -refcount\n" - << " Treat classes that inherit from a class called ReferenceCount as a\n" - << " special case. Any wrapper function that returns a pointer to\n" - << " one of these classes will automatically increment the reference\n" - << " count by calling ref() on the object first, and any destructors\n" - << " that are generated will call unref_delete() on the object instead of\n" - << " simply delete.\n\n" - << " Furthermore, parameters of type PointerTo or ConstPointerTo\n" - << " will automatically be mapped to N * and const N *, respectively.\n\n" - - << " -assert\n" - << " Generate code in each wrapper that will check the state of the assert\n" - << " flag and trigger an exception in the scripting language when a\n" - << " C++ assertion fails. Presently, this only has meaning to the Python\n" - << " wrappers.\n\n" - - << " -true-names\n" - << " Use the actual name of the function being wrapped as the name of\n" - << " the generated wrapper function, instead of an ugly hash name.\n" - << " This means the wrapper functions may be called directly using a\n" - << " meaningful name (especially if -fnames is also given), but it\n" - << " also means that C++ function overloading (including default values\n" - << " for parameters) cannot be used, as it will lead to multiple wrapper\n" - << " functions with the same name.\n\n" - - << " -c\n" - << " Generate function wrappers using the C calling convention. Any\n" - << " scripting language that can call a C function should be able to\n" - << " make advantage of the interrogate database.\n\n" - << " -python\n" - << " Generate function wrappers using the Python calling convention.\n" - << " The shared library will be directly loadable as a Python module\n" - << " (especially if the module definitions are made available either by\n" - << " running interrogate-module later, or by specifying -do-module on\n" - << " the command line now). However, C++ objects and methods will be\n" - << " converted into an object handle and a list of independent Python\n" - << " functions.\n\n" - << " -python-obj\n" - << " Generate Python function wrappers that convert C++ objects to true\n" - << " python objects, with all methods converted to Python methods. This\n" - << " is currently experimental.\n\n" - << " -python-native\n" - << " Generate Python function wrappers that convert C++ objects to true\n" - << " python objects, with all methods converted to Python methods. This\n" - << " is currently experimental.\n\n" - - << " Any combination of -c, -python, or -python-obj may be specified. If all\n" - << " are omitted, the default is -c.\n\n" - - << " -track-interpreter\n" - << " Generate code within each wrapper function to adjust the global\n" - << " variable \"in_interpreter\" to indicated whether code is running\n" - << " within the Panda C++ environment or within the high-level language.\n" - - << " -unique-names\n" - << " Compile a table into the library (i.e. generate code into the -oc\n" - << " file) that defines a lookup of each function wrapper by its unique\n" - << " name. This makes it possible to consistently identify function\n" - << " wrappers between sessions, at the cost of having this additional\n" - << " table in memory.\n\n" - - << " -nodb\n" - << " Do not build a full interrogate database, but just generate function\n" - << " wrappers. It is assumed that the user will know how to call the\n" - << " function wrappers already, from some external source. This is most\n" - << " useful in conjunction with -true-names.\n\n" - - << " -promiscuous\n" - << " Export *all* public symbols, functions, and classes seen, even those\n" - << " not explicitly marked to be published.\n\n" - - << " -spam\n" - << " Generate wrapper functions that report each invocation to Notify.\n" - << " This can sometimes be useful for tracking down bugs.\n\n" - - << " -noangles\n" - << " Treat #include the same as #include \"file\". This means -I\n" - << " and -S are equivalent.\n\n" - - << " -nomangle\n" - << " Do not generate camelCase equivalents of functions.\n\n"; -} - -// handle commandline -D options -static void -predefine_macro(CPPParser& parser, const string& inoption) { - string macro_name, macro_def; - - size_t eq = inoption.find('='); - if (eq != string::npos) { - macro_name = inoption.substr(0, eq); - macro_def = inoption.substr(eq + 1); - } else { - macro_name = inoption; - } - - CPPManifest *macro = new CPPManifest(parser, macro_name, macro_def); - parser._manifests[macro->_name] = macro; -} - -int -main(int argc, char **argv) { - preprocess_argv(argc, argv); - string command_line; - int i; - for (i = 0; i < argc; i++) { - if (i > 0) { - command_line += ' '; - } - command_line += string(argv[i]); - } - - Filename fn; - extern char *optarg; - extern int optind; - int flag; - - flag = getopt_long_only(argc, argv, short_options, long_options, nullptr); - while (flag != EOF) { - switch (flag) { - case 'I': - fn = Filename::from_os_specific(optarg); - fn.make_absolute(); - parser._quote_include_path.append_directory(fn); - parser._quote_include_kind.push_back(CPPFile::S_alternate); - break; - - case 'S': - fn = Filename::from_os_specific(optarg); - fn.make_absolute(); - parser._angle_include_path.append_directory(fn); - parser._quote_include_path.append_directory(fn); - parser._quote_include_kind.push_back(CPPFile::S_system); - break; - - case 'D': - predefine_macro(parser, optarg); - break; - - case 'F': - // This is just a compile directive which we ignore. - break; - - case 'v': - parser.set_verbose(parser.get_verbose() + 1); - break; - - case CO_oc: - output_code_filename = Filename::from_os_specific(optarg); - output_code_filename.make_absolute(); - break; - - case CO_od: - output_data_filename = Filename::from_os_specific(optarg); - output_data_filename.make_absolute(); - break; - - case CO_srcdir: - source_file_directory = Filename::from_os_specific(optarg); - source_file_directory.make_absolute(); - break; - - case CO_module: - module_name = optarg; - break; - - case CO_library: - library_name = optarg; - break; - - case CO_do_module: - output_module_specific = true; - break; - - case CO_fptrs: - output_function_pointers = true; - break; - - case CO_fnames: - output_function_names = true; - break; - - case CO_string: - convert_strings = true; - break; - - case CO_refcount: - manage_reference_counts = true; - break; - - case CO_assert: - watch_asserts = true; - break; - - case CO_true_names: - true_wrapper_names = true; - break; - - case CO_c: - build_c_wrappers = true; - break; - - case CO_python: - build_python_wrappers = true; - break; - - case CO_python_obj: - build_python_obj_wrappers = true; - break; - - case CO_python_native: - build_python_native = true; - break; - - case CO_track_interpreter: - track_interpreter = true; - break; - - case CO_unique_names: - save_unique_names = true; - break; - - case CO_nodb: - no_database = true; - break; - - case CO_longlong: - cerr << "Warning: ignoring deprecated -longlong option.\n"; - cpp_longlong_keyword = optarg; - break; - - case CO_promiscuous: - min_vis = V_public; - break; - - case CO_spam: - generate_spam = true; - break; - - case CO_noangles: - parser._noangles = true; - break; - - case CO_nomangle: - mangle_names = false; - break; - - case 'h': - case CO_help: - show_help(); - exit(0); - - default: - exit(1); - } - flag = getopt_long_only(argc, argv, short_options, long_options, nullptr); - } - - argc -= (optind-1); - argv += (optind-1); - - if (argc < 2) { - show_usage(); - exit(1); - } - - // If requested, change directory to the source-file directory. - if (source_file_directory != "") { - if (!source_file_directory.chdir()) { - cerr << "Could not change directory to " << source_file_directory << "\n"; - exit(1); - } - } - -// if(!output_code_filename.empty()) { output_include_filename = -// output_code_filename.get_fullpath_wo_extension() +".h"; printf(" Include -// File Will be Set to %s \n",output_include_filename.c_str()); } - - output_code_filename.set_text(); - output_data_filename.set_text(); -// output_include_filename.set_text(); - output_data_basename = output_data_filename.get_basename(); - - if (output_function_names && true_wrapper_names) { - cerr - << "Cannot simultaneously export function names and report\n" - << "true wrapper names--wrapper names will clash with the\n" - << "wrapped functions!\n"; - exit(1); - } - - if (!build_c_wrappers && !build_python_wrappers && - !build_python_obj_wrappers &&!build_python_native) { - build_c_wrappers = true; - } - - // Add all of the .h files we are explicitly including to the parser. - for (i = 1; i < argc; ++i) { - Filename filename = Filename::from_os_specific(argv[i]); - filename.make_absolute(); - parser._explicit_files.insert(filename); - } - - // Now go through them again and feed them into the C++ parser. - for (i = 1; i < argc; ++i) { - Filename filename = Filename::from_os_specific(argv[i]); - if (!parser.parse_file(filename)) { - cerr << "interrogate failed to parse file: '" << argv[i] << "'\n"; - exit(1); - } - builder.add_source_file(filename.to_os_generic()); - } - - // Now that we've parsed all the source code, change the way things are - // output from now on so we can compile our generated code using VC++. - // Sheesh. - - // Actually, don't do this any more, since it bitches some of the logic - // (particularly with locating alt names), and it shouldn't be necessary - // with modern VC++. cppparser_output_class_keyword = false; - - // Now look for the .N files. - for (i = 1; i < argc; ++i) { - Filename filename = Filename::from_os_specific(argv[i]); - Filename nfilename = filename; - nfilename.set_extension("N"); - nfilename.set_text(); - pifstream nfile; - if (nfilename.open_read(nfile)) { - builder.read_command_file(nfile); - } - } - - builder.build(); - - // Make up a file identifier. This is just some bogus number that should be - // the same in both the compiled-in code and in the database, so we can - // check synchronicity at load time. - // We allow overriding this value by setting SOURCE_DATE_EPOCH to support - // reproducible builds. - int file_identifier; -#ifdef _MSC_VER - char source_date_epoch[64]; - size_t source_date_epoch_size = 0; - if (getenv_s(&source_date_epoch_size, source_date_epoch, - sizeof(source_date_epoch), "SOURCE_DATE_EPOCH"), source_date_epoch_size > 1) { -#else - const char *source_date_epoch = getenv("SOURCE_DATE_EPOCH"); - if (source_date_epoch != nullptr && source_date_epoch[0] != 0) { -#endif - file_identifier = atoi(source_date_epoch); - } else { - file_identifier = time(nullptr); - } - InterrogateModuleDef *def = builder.make_module_def(file_identifier); - - pofstream * the_output_include = nullptr; - pofstream output_include; - - - if (1==2 && !output_include_filename.empty()) - { - output_include_filename.open_write(output_include); - - output_include << "#ifndef " << output_include_filename.get_basename_wo_extension() << "__HH__\n"; - output_include << "#define " << output_include_filename.get_basename_wo_extension() << "__HH__\n"; - - output_include - << "/*\n" - << " * This file was generated by:\n" - << " * " << command_line << "\n" - << " *\n" - << " */\n\n"; - - - if (output_include.fail()) - { - nout << "Unable to write to " << output_include_filename << "\n"; - exit(-1); - } - the_output_include = &output_include; - } - - int status = 0; - - // Now output all of the wrapper functions. - if (!output_code_filename.empty()) - { - pofstream output_code; - output_code_filename.open_write(output_code); - - output_code - << "/*\n" - << " * This file was generated by:\n" - << " * " << command_line << "\n" - << " *\n" - << " */\n\n"; - - if (the_output_include != nullptr) { - output_code << "#include \"" << output_include_filename << "\"\n"; - *the_output_include << "#include \"" << output_include_filename.get_fullpath_wo_extension() << "_pynative.h\"\n"; - } - - if (output_code.fail()) { - nout << "Unable to write to " << output_code_filename << "\n"; - status = -1; - } else { - builder.write_code(output_code, the_output_include, def); - } - } - - if (the_output_include != nullptr) { - *the_output_include << "#endif // #define " << output_include_filename.get_basename_wo_extension() << "__HH__\n"; - } - - // And now output the bulk of the database. - if (!output_data_filename.empty()) { - pofstream output_data; - output_data_filename.open_write(output_data); - - if (output_data.fail()) { - nout << "Unable to write to " << output_data_filename << "\n"; - status = -1; - } else { - InterrogateDatabase::get_ptr()->write(output_data, def); - } - } - - return status; -} diff --git a/dtool/src/interrogate/interrogate.h b/dtool/src/interrogate/interrogate.h deleted file mode 100644 index a40a1ed26e8..00000000000 --- a/dtool/src/interrogate/interrogate.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate.h - * @author drose - * @date 2000-07-31 - */ - -#ifndef INTERROGATE_H -#define INTERROGATE_H - -#include "dtoolbase.h" - -#include "cppParser.h" -#include "cppVisibility.h" -#include "filename.h" - -extern CPPParser parser; - -// A few global variables that control the interrogate process. -extern Filename output_code_filename; -extern Filename output_data_filename; -extern std::string output_data_basename; -extern bool output_module_specific; -extern bool output_function_pointers; -extern bool output_function_names; -extern bool convert_strings; -extern bool manage_reference_counts; -extern bool watch_asserts; -extern bool true_wrapper_names; -extern bool build_c_wrappers; -extern bool build_python_wrappers; -extern bool build_python_obj_wrappers; -extern bool build_python_native; -extern bool track_interpreter; -extern bool save_unique_names; -extern bool no_database; -extern bool generate_spam; -extern bool left_inheritance_requires_upcast; -extern bool mangle_names; -extern CPPVisibility min_vis; -extern std::string library_name; -extern std::string module_name; - -#endif diff --git a/dtool/src/interrogate/interrogateBuilder.cxx b/dtool/src/interrogate/interrogateBuilder.cxx deleted file mode 100644 index 45222f6a9c0..00000000000 --- a/dtool/src/interrogate/interrogateBuilder.cxx +++ /dev/null @@ -1,3214 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateBuilder.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "interrogateBuilder.h" -#include "interrogate.h" -#include "parameterRemap.h" -#include "typeManager.h" -#include "functionWriters.h" -#include "interfaceMakerC.h" -#include "interfaceMakerPythonObj.h" -#include "interfaceMakerPythonSimple.h" -#include "interfaceMakerPythonNative.h" -#include "functionRemap.h" - -#include "interrogateType.h" -#include "interrogateDatabase.h" -#include "indexRemapper.h" -#include "cppParser.h" -#include "cppDeclaration.h" -#include "cppFunctionGroup.h" -#include "cppFunctionType.h" -#include "cppParameterList.h" -#include "cppInstance.h" -#include "cppSimpleType.h" -#include "cppPointerType.h" -#include "cppReferenceType.h" -#include "cppArrayType.h" -#include "cppConstType.h" -#include "cppExtensionType.h" -#include "cppStructType.h" -#include "cppExpression.h" -#include "cppTypedefType.h" -#include "cppTypeDeclaration.h" -#include "cppEnumType.h" -#include "cppCommentBlock.h" -#include "cppMakeProperty.h" -#include "cppMakeSeq.h" -#include "pnotify.h" - -#include -#include - -using std::cerr; -using std::istream; -using std::map; -using std::ostream; -using std::ostringstream; -using std::string; - -InterrogateBuilder builder; -std::string EXPORT_IMPORT_PREFIX; - -/** - * Adds the given source filename to the list of files that we are scanning. - * Those source files that appear to be header files will be #included in the - * generated code file. - */ -void InterrogateBuilder:: -add_source_file(const string &filename) { - if (filename.empty()) { - return; - } - - _include_files[filename] = '"'; -} - -/** - * Reads a .N file that might contain control information for the interrogate - * process. - */ -void InterrogateBuilder:: -read_command_file(istream &in) { - string line; - std::getline(in, line); - while (!in.fail() && !in.eof()) { - // Strip out the comment. - size_t hash = line.find('#'); - if (hash != string::npos) { - line = line.substr(0, hash); - } - - // Skip leading whitespace. - size_t p = 0; - while (p < line.length() && isspace(line[p])) { - p++; - } - - if (p < line.length()) { - // Get the first word. - size_t q = p; - while (q < line.length() && !isspace(line[q])) { - q++; - } - string command = line.substr(p, q - p); - - // Get the rest. - p = q; - while (p < line.length() && isspace(line[p])) { - p++; - } - // Except for the trailing whitespace. - q = line.length(); - while (q > p && isspace(line[q - 1])) { - q--; - } - string params = line.substr(p, q - p); - - do_command(command, params); - } - std::getline(in, line); - } -} - -/** - * Executes a single command as read from the .N file. - */ -void InterrogateBuilder:: -do_command(const string &command, const string ¶ms) { - - if (command == "forcevisible") { - CPPType *type = parser.parse_type(params); - if (type == nullptr) { - nout << "Unknown type: allowtype " << params << "\n"; - } else { - type = type->resolve_type(&parser, &parser); - type->_vis = min_vis; - } - - } else if (command == "forcetype") { - // forcetype explicitly exports the given type. - CPPType *type = parser.parse_type(params); - if (type == nullptr) { - nout << "Unknown type: forcetype " << params << "\n"; - } else { - type = type->resolve_type(&parser, &parser); - type->_forcetype = true; - _forcetype.insert(type->get_local_name(&parser)); - } - - } else if (command == "renametype") { - // rename exports the type as the indicated name. We strip off the last - // word as the new name; the new name may not contain spaces (although the - // original type name may). - - size_t space = params.rfind(' '); - if (space == string::npos) { - nout << "No new name specified for renametype " << params << "\n"; - } else { - string orig_name = params.substr(0, space); - string new_name = params.substr(space + 1); - - CPPType *type = parser.parse_type(orig_name); - if (type == nullptr) { - nout << "Unknown type: renametype " << orig_name << "\n"; - } else { - type = type->resolve_type(&parser, &parser); - _renametype[type->get_local_name(&parser)] = new_name; - } - } - - } else if (command == "ignoretype") { - // ignoretype explicitly ignores the given type. - CPPType *type = parser.parse_type(params); - if (type == nullptr) { - nout << "Unknown type: ignoretype " << params << "\n"; - } else { - type = type->resolve_type(&parser, &parser); - _ignoretype.insert(type->get_local_name(&parser)); - } - - } else if (command == "defconstruct") { - // defining the parameters that are implicitly supplied to the generated - // default constructor. Especially useful for linmath objects, whose - // default constructor in C++ is uninitialized, but whose Python-level - // constructor should initialize to 0. - - size_t space = params.find(' '); - if (space == string::npos) { - nout << "No constructor specified for defconstruct " << params << "\n"; - } else { - string class_name = params.substr(0, space); - string constructor = params.substr(space + 1); - - CPPType *type = parser.parse_type(class_name); - if (type == nullptr) { - nout << "Unknown type: defconstruct " << class_name << "\n"; - } else { - type = type->resolve_type(&parser, &parser); - _defconstruct[type->get_local_name(&parser)] = constructor; - } - } - - } else if (command == "ignoreinvolved") { - _ignoreinvolved.insert(params); - - } else if (command == "ignorefile") { - insert_param_list(_ignorefile, params); - - } else if (command == "ignoremember") { - insert_param_list(_ignoremember, params); - - } else if (command == "noinclude") { - insert_param_list(_noinclude, params); - - } else if (command == "forceinclude") { - size_t nchars = params.size(); - if (nchars >= 2 && params[0] == '"' && params[nchars-1] == '"') { - string incfile = params.substr(1, nchars - 2); - _include_files[incfile] = '"'; - - } else if (nchars >= 2 && params[0] == '<' && params[nchars-1] == '>') { - string incfile = params.substr(1, nchars - 2); - _include_files[incfile] = '<'; - - } else { - nout << "Ignoring invalid forceinclude " << params << "\n" - "Expected to be in one of the following forms:\n" - " forceinclude \"file.h\"\n" - " forceinclude \n"; - } - } else { - nout << "Ignoring " << command << " " << params << "\n"; - } -} - -/** - * Builds all of the interrogate data. - */ -void InterrogateBuilder:: -build() { - _library_hash_name = hash_string(library_name, 5); - - // Make sure we have the complete set of #includes we need. - CPPParser::Includes::const_iterator ii; - for (ii = parser._quote_includes.begin(); - ii != parser._quote_includes.end(); - ++ii) { - const string &filename = (*ii); - _include_files[filename] = '"'; - } - for (ii = parser._angle_includes.begin(); - ii != parser._angle_includes.end(); - ++ii) { - const string &filename = (*ii); - _include_files[filename] = '<'; - } - - // First, get all the types that were explicitly forced. - Commands::const_iterator ci; - for (ci = _forcetype.begin(); - ci != _forcetype.end(); - ++ci) { - CPPType *type = parser.parse_type(*ci); - if (type == nullptr) { - cerr << "Failure to parse forcetype " << *ci << "\n"; - } - assert(type != nullptr); - get_type(type, true); - } - - // Now go through all of the top-level declarations in the file(s). - - CPPScope::Declarations::const_iterator di; - for (di = parser._declarations.begin(); - di != parser._declarations.end(); - ++di) { - if ((*di)->get_subtype() == CPPDeclaration::ST_instance) { - CPPInstance *inst = (*di)->as_instance(); - if (inst->_type->get_subtype() == CPPDeclaration::ST_function) { - // Here's a function declaration. - scan_function(inst); - } else { - // Here's a data element declaration. - scan_element(inst, nullptr, &parser); - } - - } else if ((*di)->get_subtype() == CPPDeclaration::ST_typedef) { - CPPTypedefType *tdef = (*di)->as_typedef_type(); - - if (tdef->_type->get_subtype() == CPPDeclaration::ST_struct) { - // A typedef counts as a declaration. This lets us pick up most - // template instantiations. - CPPStructType *struct_type = - tdef->_type->resolve_type(&parser, &parser)->as_struct_type(); - scan_struct_type(struct_type); - } - - scan_typedef_type(tdef); - - } else if ((*di)->get_subtype() == CPPDeclaration::ST_type_declaration) { - CPPType *type = (*di)->as_type_declaration()->_type; - - type->_vis = (*di)->_vis; - - if (type->get_subtype() == CPPDeclaration::ST_struct) { - CPPStructType *struct_type = - type->as_type()->resolve_type(&parser, &parser)->as_struct_type(); - scan_struct_type(struct_type); - - } else if (type->get_subtype() == CPPDeclaration::ST_enum) { - CPPEnumType *enum_type = - type->as_type()->resolve_type(&parser, &parser)->as_enum_type(); - scan_enum_type(enum_type); - } - } - } - - CPPPreprocessor::Manifests::const_iterator mi; - for (mi = parser._manifests.begin(); mi != parser._manifests.end(); ++mi) { - CPPManifest *manifest = (*mi).second; - scan_manifest(manifest); - } - - // Now that we've gone through all the code and generated all the functions - // and types, build the function wrappers. make_wrappers(); -} - -/** - * Generates all the code necessary to the indicated output stream. - */ -void InterrogateBuilder:: -write_code(ostream &out_code,ostream * out_include, InterrogateModuleDef *def) { - typedef std::vector InterfaceMakers; - InterfaceMakers makers; - - if (build_c_wrappers) { - InterfaceMaker *maker = new InterfaceMakerC(def); - makers.push_back(maker); - } - - if (build_python_wrappers) { - InterfaceMaker *maker = new InterfaceMakerPythonSimple(def); - makers.push_back(maker); - } - - if (build_python_obj_wrappers) { - InterfaceMaker *maker = new InterfaceMakerPythonObj(def); - makers.push_back(maker); - } - - if (build_python_native) { - InterfaceMakerPythonNative *maker = new InterfaceMakerPythonNative(def); - makers.push_back(maker); - } - - EXPORT_IMPORT_PREFIX = std::string("EXPCL_") + def->module_name; - for (size_t i = 0; i < EXPORT_IMPORT_PREFIX.size(); i++) { - EXPORT_IMPORT_PREFIX[i] = toupper(EXPORT_IMPORT_PREFIX[i]); - } - - InterfaceMakers::iterator mi; - // First, make all the wrappers. - for (mi = makers.begin(); mi != makers.end(); ++mi) { - (*mi)->generate_wrappers(); - } - - // Now generate all the function bodies to a temporary buffer. By - // generating these first, we ensure that we know all of the pointers we'll - // be using ahead of time (and can therefore generate correct prototypes). - ostringstream function_bodies; - for (mi = makers.begin(); mi != makers.end(); ++mi) { - (*mi)->write_functions(function_bodies); - } - - // Now, begin the actual output. Start with the #include lines. - if (!no_database) { - out_code << "#include \"dtoolbase.h\"\n" - << "#include \"interrogate_request.h\"\n" - << "#include \"dconfig.h\"\n"; - } - - ostringstream declaration_bodies; - - if (watch_asserts) { - declaration_bodies << "#include \"pnotify.h\"\n"; - } - - declaration_bodies << "#include \n"; - - if (build_python_native) { - declaration_bodies << "#include \"py_panda.h\"\n"; - declaration_bodies << "#include \"extension.h\"\n"; - declaration_bodies << "#include \"dcast.h\"\n"; - } - declaration_bodies << "\n"; - - IncludeFiles::const_iterator ifi; - for (ifi = _include_files.begin(); - ifi != _include_files.end(); - ++ifi) { - const string &filename = (*ifi).first; - char delimiter = (*ifi).second; - if (should_include(filename)) { - if (delimiter == '"') { - declaration_bodies << "#include \"" << filename << "\"\n"; - } else { - declaration_bodies << "#include <" << filename << ">\n"; - } - } - } - declaration_bodies << "\n"; - - for (mi = makers.begin(); mi != makers.end(); ++mi) { - (*mi)->write_includes(declaration_bodies); - } - - if (generate_spam) { - declaration_bodies << "#include \"config_interrogatedb.h\"\n" - << "#include \"notifyCategoryProxy.h\"\n\n" - << "NotifyCategoryDeclNoExport(in_" << library_name << ");\n" - << "NotifyCategoryDef(in_" << library_name << ", interrogatedb_cat);\n\n"; - } - - declaration_bodies << "\n"; - - // And now the prototypes. - for (mi = makers.begin(); mi != makers.end(); ++mi) { - (*mi)->write_prototypes(declaration_bodies,out_include); - } - declaration_bodies << "\n"; - -// if(out_include != NULL) (*out_include) << declaration_bodies.str(); else - out_code << declaration_bodies.str(); - - // Followed by the function bodies. - out_code << function_bodies.str() << "\n"; - - for (mi = makers.begin(); mi != makers.end(); ++mi) { - (*mi)->write_module_support(out_code, out_include, def); - } - - if (output_module_specific) { - // Output whatever stuff we should output if this were a module. - for (mi = makers.begin(); mi != makers.end(); ++mi) { - (*mi)->write_module(out_code, out_include, def); - } - } - - // Now collect all the function wrappers. - std::vector remaps; - for (mi = makers.begin(); mi != makers.end(); ++mi) { - (*mi)->get_function_remaps(remaps); - } - - // Make sure all of the function wrappers appear first in the set of - // indices, and that they occupy consecutive index numbers, so we can build - // a simple array of function pointers by index. - remap_indices(remaps); - - // Get the function wrappers in index-number order. - int num_wrappers = 0; - map wrappers_by_index; - - std::vector::iterator ri; - for (ri = remaps.begin(); ri != remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - wrappers_by_index[remap->_wrapper_index] = remap; - num_wrappers++; - } - - if (output_function_pointers) { - // Write out the table of function pointers. - out_code << "static void *_in_fptrs[" << num_wrappers << "] = {\n"; - int next_index = 1; - map::iterator ii; - for (ii = wrappers_by_index.begin(); - ii != wrappers_by_index.end(); - ++ii) { - int this_index = (*ii).first; - while (next_index < this_index) { - out_code << " (void *)0,\n"; - next_index++; - } - assert(next_index == this_index); - FunctionRemap *remap = (*ii).second; - - out_code << " (void *)&" << remap->_wrapper_name << ",\n"; - next_index++; - } - while (next_index < num_wrappers + 1) { - out_code << " (void *)0,\n"; - next_index++; - } - out_code << "};\n\n"; - } - - if (save_unique_names) { - // Write out the table of unique names, in no particular order. - out_code << "static InterrogateUniqueNameDef _in_unique_names[" - << num_wrappers << "] = {\n"; - for (ri = remaps.begin(); ri != remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - out_code << " { \"" - << remap->_unique_name << "\", " - << remap->_wrapper_index - 1 << " },\n"; - } - out_code << "};\n\n"; - } - - if (!no_database) { - // Now build the module definition structure to add ourselves to the - // global interrogate database. - out_code << "static InterrogateModuleDef _in_module_def = {\n" - << " " << def->file_identifier << ", /* file_identifier */\n" - << " \"" << def->library_name << "\", /* library_name */\n" - << " \"" << def->library_hash_name << "\", /* library_hash_name */\n" - << " \"" << def->module_name << "\", /* module_name */\n"; - if (def->database_filename != nullptr) { - out_code << " \"" << def->database_filename - << "\", /* database_filename */\n"; - } else { - out_code << " (const char *)0, /* database_filename */\n"; - } - - if (save_unique_names) { - out_code << " _in_unique_names,\n" - << " " << num_wrappers << ", /* num_unique_names */\n"; - } else { - out_code << " nullptr, /* unique_names */\n" - << " 0, /* num_unique_names */\n"; - } - - if (output_function_pointers) { - out_code << " _in_fptrs,\n" - << " " << num_wrappers << ", /* num_fptrs */\n"; - } else { - out_code << " nullptr, /* fptrs */\n" - << " 0, /* num_fptrs */\n"; - } - - out_code << " 1, /* first_index */\n" - << " " << InterrogateDatabase::get_ptr()->get_next_index() - << " /* next_index */\n" - << "};\n\n"; - - // And now write the static-init code that tells the interrogate database - // to load up this module. - out_code << "Configure(_in_configure_" << library_name << ");\n" - << "ConfigureFn(_in_configure_" << library_name << ") {\n" - << " interrogate_request_module(&_in_module_def);\n" - << "}\n\n"; - } -} - -/** - * Allocates and returns a new InterrogateModuleDef structure that reflects - * the data we have just build, or at least that subset of the - * InterrogateModuleDef data that we have available at this time. - * - * The data in this structure may include pointers that reference directly - * into the InterrogateBuilder object; thus, this structure is only valid for - * as long as the builder itself remains in scope. - */ -InterrogateModuleDef *InterrogateBuilder:: -make_module_def(int file_identifier) { - InterrogateModuleDef *def = new InterrogateModuleDef; - memset(def, 0, sizeof(InterrogateModuleDef)); - - def->file_identifier = file_identifier; - def->library_name = library_name.c_str(); - def->library_hash_name = _library_hash_name.c_str(); - def->module_name = module_name.c_str(); - if (!output_data_filename.empty()) { - def->database_filename = output_data_basename.c_str(); - } - - return def; -} - -/** - * Adjusts the given string to remove any characters we don't want to export - * as part of an identifier name. Returns the cleaned string. - * - * This replaces any consecutive invalid characters with an underscore. - */ -string InterrogateBuilder:: -clean_identifier(const string &name) { - string result; - - bool last_invalid = false; - - string::const_iterator ni; - for (ni = name.begin(); ni != name.end(); ++ni) { - if (isalnum(*ni)) { - if (last_invalid) { - result += '_'; - last_invalid = false; - } - result += (*ni); - } else { - last_invalid = true; - } - } - - return result; -} - -/** - * Removes the leading "::", if present, from a fully-scoped name. Sometimes - * CPPParser throws this on, and sometimes it doesn't. - */ -string InterrogateBuilder:: -descope(const string &name) { - if (name.length() >= 2 && name.substr(0, 2) == "::") { - return name.substr(2); - } - return name; -} - -/** - * Returns the FunctionIndex for the destructor appropriate to destruct an - * instance of the indicated type, or 0 if no suitable destructor exists. - */ -FunctionIndex InterrogateBuilder:: -get_destructor_for(CPPType *type) { - TypeIndex type_index = get_type(type, false); - - const InterrogateType &itype = - InterrogateDatabase::get_ptr()->get_type(type_index); - - return itype.get_destructor(); -} - -/** - * Returns the name of the type as it should be reported to the database. - * This is either the name indicated by the user via a renametype command, or - * the "preferred name" of the type itself (i.e. the typedef name within the - * C++ code), or failing that, the type's true name. - */ -string InterrogateBuilder:: -get_preferred_name(CPPType *type) { - string true_name = type->get_local_name(&parser); - string name = in_renametype(true_name); - if (!name.empty()) { - return name; - } - return type->get_preferred_name(); -} - -/** - * Hashes an arbitrary string into a four-character string using only the - * characters legal in a C identifier. - */ -string InterrogateBuilder:: -hash_string(const string &name, int shift_offset) { - unsigned int hash = 0; - - unsigned int shift = 0; - string::const_iterator ni; - for (ni = name.begin(); ni != name.end(); ++ni) { - unsigned int c = (unsigned char)*ni; - unsigned int shifted_c = (c << shift) & 0xffffff; - if (shift > 16) { - // We actually want a circular shift, not an arithmetic shift. - shifted_c |= ((c >> (24 - shift)) & 0xff) ; - } - hash = (hash + shifted_c) & 0xffffff; - shift = (shift + shift_offset) % 24; - } - - // Now multiply the hash by a biggish prime number and apply the high-order - // bits back at the bottom, to scramble up the bits a bit. This helps - // reduce hash conflicts from names that are similar to each other, by - // separating adjacent hash codes. - const unsigned int prime = 4999; - unsigned long long product = (unsigned long long)hash * prime; - hash = (product ^ (product >> 24)) & 0xffffff; - - // Also add in the additional_number, times some prime factor. hash = (hash - // + additional_number * 1657) & 0xffffff; - - // Now turn the hash code into a four-character string. For each six bits, - // we choose a character in the set [A-Za-z0-9_]. Note that there are only - // 63 characters to choose from; we have to duplicate '_' for values 62 and - // 63. This introduces a small additional chance of hash conflicts. No big - // deal, since we have to resolve hash conflicts anyway. - - string result; - for (int i = 0; i < 4; i++) { - unsigned int value = (hash & 0x3f); - hash >>= 6; - if (value < 26) { - result += (char)('A' + value); - - } else if (value < 52) { - result += (char)('a' + value - 26); - - } else if (value < 62) { - result += (char)('0' + value - 52); - - } else { - result += '_'; - } - } - - return result; -} - -/** - * Inserts a list of space-separated parameters into the given command - * parameter list. - */ -void InterrogateBuilder:: -insert_param_list(InterrogateBuilder::Commands &commands, - const string ¶ms) { - size_t p = 0; - while (p < params.length()) { - while (p < params.length() && isspace(params[p])) { - p++; - } - size_t q = p; - while (q < params.length() && !isspace(params[q])) { - q++; - } - if (p < q) { - commands.insert(params.substr(p, q - p)); - } - p = q; - } -} - -/** - * Returns true if the indicated name is one that the user identified with a - * forcetype command. - */ -bool InterrogateBuilder:: -in_forcetype(const string &name) const { - return (_forcetype.count(name) != 0); -} - -/** - * If the user requested an explicit name for this type via the renametype - * command, returns that name; otherwise, returns the empty string. - */ -string InterrogateBuilder:: -in_renametype(const string &name) const { - CommandParams::const_iterator pi; - pi = _renametype.find(name); - if (pi != _renametype.end()) { - return (*pi).second; - } - return string(); -} - -/** - * Returns true if the indicated name is one that the user identified with an - * ignoretype command. - */ -bool InterrogateBuilder:: -in_ignoretype(const string &name) const { - return (_ignoretype.count(name) != 0); -} - -/** - * If the user requested an explicit default constructor for this type via the - * defconstruct command, returns that string; otherwise, returns the empty - * string. - */ -string InterrogateBuilder:: -in_defconstruct(const string &name) const { - CommandParams::const_iterator pi; - pi = _defconstruct.find(name); - if (pi != _defconstruct.end()) { - return (*pi).second; - } - return string(); -} - -/** - * Returns true if the indicated name is one that the user identified with an - * ignoreinvolved command. - */ -bool InterrogateBuilder:: -in_ignoreinvolved(const string &name) const { - return (_ignoreinvolved.count(name) != 0); -} -/** - * Returns true if the indicated type involves some type name that the user - * identified with an ignoreinvolved command. - */ -bool InterrogateBuilder:: -in_ignoreinvolved(CPPType *type) const { - switch (type->get_subtype()) { - case CPPDeclaration::ST_pointer: - { - CPPPointerType *ptr = type->as_pointer_type(); - return in_ignoreinvolved(ptr->_pointing_at); - } - - case CPPDeclaration::ST_array: - { - CPPArrayType *ary = type->as_array_type(); - return in_ignoreinvolved(ary->_element_type); - } - - case CPPDeclaration::ST_reference: - { - CPPReferenceType *ref = type->as_reference_type(); - return in_ignoreinvolved(ref->_pointing_at); - } - - case CPPDeclaration::ST_const: - { - CPPConstType *cnst = type->as_const_type(); - return in_ignoreinvolved(cnst->_wrapped_around); - } - - case CPPDeclaration::ST_function: - { - CPPFunctionType *ftype = type->as_function_type(); - if (in_ignoreinvolved(ftype->_return_type)) { - return true; - } - const CPPParameterList::Parameters ¶ms = - ftype->_parameters->_parameters; - CPPParameterList::Parameters::const_iterator pi; - for (pi = params.begin(); pi != params.end(); ++pi) { - if (in_ignoreinvolved((*pi)->_type)) { - return true; - } - } - return false; - } - - case CPPDeclaration::ST_typedef: - { - if (in_ignoreinvolved(type->get_simple_name())) { - return true; - } - CPPTypedefType *tdef = type->as_typedef_type(); - return in_ignoreinvolved(tdef->_type); - } - - default: - return in_ignoreinvolved(type->get_simple_name()); - } -} - -/** - * Returns true if the indicated name is one that the user identified with an - * ignorefile command. - */ -bool InterrogateBuilder:: -in_ignorefile(const string &name) const { - return (_ignorefile.count(name) != 0); -} - -/** - * Returns true if the indicated name is one that the user identified with an - * ignoremember command. - */ -bool InterrogateBuilder:: -in_ignoremember(const string &name) const { - return (_ignoremember.count(name) != 0); -} - -/** - * Returns true if the indicated filename is one that the user identified with - * a noinclude command. - */ -bool InterrogateBuilder:: -in_noinclude(const string &name) const { - return (_noinclude.count(name) != 0); -} - -/** - * Returns true if the indicated filename is a valid file to explicitly - * #include in the generated .cxx file, false otherwise. - */ -bool InterrogateBuilder:: -should_include(const string &filename) const { - // Don't directly include any .cxx or .I files, except for extensions. - if (CPPFile::is_c_or_i_file(filename)) { - return false; - } - - // Also, don't include any files specifically forbidden in a .N file. - if (in_noinclude(filename)) { - return false; - } - - // Much as I hate to do it, I'm going to code in a special-case for two - // particularly nasty header files that we probably don't want to actually - // ever include. - if (filename == "winbase.h" || filename == "windows.h") { - return false; - } - - // Finally, don't include *_src.h or *_src.cxx. These are special - // "template" files that should not generally be included directly. - if (filename.length() > 6 && filename.substr(filename.length() - 6) == "_src.h") { - return false; - } - if (filename.length() > 8 && filename.substr(filename.length() - 8) == "_src.cxx") { - return false; - } - - // Ignore Objective-C files too. - if (filename.length() > 3 && filename.substr(filename.length() - 3) == ".mm") { - return false; - } - - // Otherwise, no problem. - return true; -} - -/** - * Recursively looks for the first inherited version of this function in the - * derivation chain of this class. Returns true if this function is declared - * published, or false if it is not published, or if it can't be found. - */ -bool InterrogateBuilder:: -is_inherited_published(CPPInstance *function, CPPStructType *struct_type) { - nassertr(struct_type->_derivation.size() == 1, false); - CPPStructType *base = struct_type->_derivation[0]._base->as_struct_type(); - nassertr(base != nullptr, false); - - CPPScope *base_scope = base->get_scope(); - CPPDeclaration *symbol = base_scope->find_symbol(function->get_simple_name(), true); - if (symbol == nullptr) { - // Couldn't find the inherited function. - return false; - } - - CPPFunctionGroup *fgroup = symbol->as_function_group(); - if (fgroup == nullptr) { - // Weird, it wasn't a function. - return false; - } - - CPPFunctionGroup::Instances::iterator ii; - for (ii = fgroup->_instances.begin(); ii != fgroup->_instances.end(); ++ii) { - CPPInstance *inst = (*ii); - if (inst->_vis != V_published) { - // Some flavors of the method are not published. Take no chances. - return false; - } - } - // It appears that all flavors of the inherited method are published. - return true; -} - -/** - * Resequences all of the index numbers so that function wrappers start at 1 - * and occupy consecutive positions, and everything else follows. This allows - * us to build a table of function wrappers by index number. - * - * The "remaps" member is a list of FunctionRemap pointers. The collision in - * naming is unfortunate; the FunctionRemap objects are so named because they - * remap synthesized function wrappers to actual C++ methods and functions. - * It has nothing to do with the remapping of index numbers, which is the - * purpose of this function. - */ -void InterrogateBuilder:: -remap_indices(std::vector &remaps) { - IndexRemapper index_remap; - InterrogateDatabase::get_ptr()->remap_indices(1, index_remap); - - TypesByName::iterator ti; - for (ti = _types_by_name.begin(); ti != _types_by_name.end(); ++ti) { - (*ti).second = index_remap.map_from((*ti).second); - } - - FunctionsByName::iterator fi; - for (fi = _functions_by_name.begin(); - fi != _functions_by_name.end(); - ++fi) { - (*fi).second = index_remap.map_from((*fi).second); - } - - std::vector::iterator ri; - for (ri = remaps.begin(); ri != remaps.end(); ++ri) { - FunctionRemap *remap = (*ri); - remap->_wrapper_index = index_remap.map_from(remap->_wrapper_index); - } -} - -/** - * Adds the indicated global function to the database, if warranted. - */ -void InterrogateBuilder:: -scan_function(CPPFunctionGroup *fgroup) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - scan_function(function); - } -} - -/** - * Adds the indicated global function to the database, if warranted. - */ -void InterrogateBuilder:: -scan_function(CPPInstance *function) { - assert(function != nullptr); - assert(function->_type != nullptr && function->_type->as_function_type() != nullptr); - - CPPFunctionType *ftype = function->_type->resolve_type(&parser, &parser)->as_function_type(); - assert(ftype != nullptr); - - CPPScope *scope = &parser; - if (function->is_scoped()) { - scope = function->get_scope(&parser, &parser); - if (scope == nullptr) { - // Invalid scope. - nout << "Invalid scope: " << *function->_ident << "\n"; - return; - } - - if (scope->get_struct_type() != nullptr) { - // Wait, this is a method, not a function. This must be the declaration - // for the method (since it's appearing out-of-scope). We don't need to - // define a new method for it, but we'd like to update the comment, if - // we have a comment. - update_function_comment(function, scope); - return; - } - } - - if (function->is_template()) { - // The function is a template function, not a true function. - return; - } - - if (function->_file.is_c_file()) { - // This function declaration appears in a .C file. We can only export - // functions whose prototypes appear in an .h file. - - string function_name = TypeManager::get_function_name(function); - - // Still, we can update the comment, at least. - update_function_comment(function, scope); - return; - } - - if (function->_file._source != CPPFile::S_local || - in_ignorefile(function->_file._filename_as_referenced)) { - // The function is defined in some other package or in an ignorable file. - return; - } - - if (function->_vis > min_vis) { - // The function is not marked to be exported. - return; - } - - if ((function->_storage_class & (CPPInstance::SC_static | CPPInstance::SC_deleted)) != 0) { - // The function is static or deleted, so can't be exported. - return; - } - - if (TypeManager::involves_protected(ftype)) { - // We can't export the function because it involves parameter types that - // are protected or private. - return; - } - - if (in_ignoreinvolved(ftype)) { - // The function or its parameters involves something that the user - // requested we ignore. - return; - } - - if (TypeManager::involves_rvalue_reference(ftype)) { - return; - } - - get_function(function, "", - nullptr, scope, - InterrogateFunction::F_global); -} - -/** - * Adds the indicated struct type to the database, if warranted. - */ -void InterrogateBuilder:: -scan_struct_type(CPPStructType *type) { - if (type == nullptr) { - return; - } - - if (type->is_template()) { - // The type is a template declaration, not a true type. - return; - } - - if (type->_file.is_c_file()) { - // This type declaration appears in a .C file. We can only export types - // defined in a .h file. - return; - } - - if (type->_file._source != CPPFile::S_local || - in_ignorefile(type->_file._filename_as_referenced)) { - // The type is defined in some other package or in an ignorable file. - return; - } - - // Check if any of the members are exported. If none of them are, and the - // type itself is not marked for export, then never mind. - if (type->_vis > min_vis) { - CPPScope *scope = type->_scope; - - bool any_exported = false; - CPPScope::Declarations::const_iterator di; - for (di = scope->_declarations.begin(); - di != scope->_declarations.end() && !any_exported; - ++di) { - if ((*di)->_vis <= min_vis) { - any_exported = true; - break; - } - } - - if (!any_exported) { - return; - } - } - - get_type(type, true); -} - -/** - * Adds the indicated enum type to the database, if warranted. - */ -void InterrogateBuilder:: -scan_enum_type(CPPEnumType *type) { - if (type == nullptr) { - return; - } - - if (type->is_template()) { - // The type is a template declaration, not a true type. - return; - } - - if (type->_file.is_c_file()) { - // This type declaration appears in a .C file. We can only export types - // defined in a .h file. - return; - } - - if (type->_file._source != CPPFile::S_local || - in_ignorefile(type->_file._filename_as_referenced)) { - // The type is defined in some other package or in an ignorable file. - return; - } - - if (type->_vis > min_vis) { - // The type is not marked to be exported. - return; - } - - get_type(type, true); -} - -/** - * Adds the indicated typedef type to the database, if warranted. - */ -void InterrogateBuilder:: -scan_typedef_type(CPPTypedefType *type) { - if (type == nullptr) { - return; - } - - if (type->is_template()) { - // The type is a template declaration, not a true type. - return; - } - - if (type->_file.is_c_file()) { - // This type declaration appears in a .C file. We can only export types - // defined in a .h file. - return; - } - - if (type->_file._source != CPPFile::S_local || - in_ignorefile(type->_file._filename_as_referenced)) { - // The type is defined in some other package or in an ignorable file. - return; - } - -/* - * Do we require explicitly placing BEGIN_PUBLISHEND_PUBLISH blocks around - * typedefs for them to be exported? My thinking is that we shoudn't, for - * now, since we don't require it for structs either (we only require it to - * have published methods). if (type->_vis > min_vis) { The wrapped type is - * not marked to be exported. return; } - */ - - // Find out what this typedef points to. - CPPType *wrapped_type = type->_type; - bool forced = in_forcetype(wrapped_type->get_local_name(&parser)); - - while (wrapped_type->get_subtype() == CPPDeclaration::ST_typedef) { - wrapped_type = wrapped_type->as_typedef_type()->_type; - forced = forced || in_forcetype(wrapped_type->get_local_name(&parser)); - } - - CPPStructType *struct_type = wrapped_type->as_struct_type(); - if (struct_type == nullptr) { - // We only export typedefs to structs, for now. - return; - } - - // Always export typedefs pointing to forced types. - if (!forced) { - if (wrapped_type->_file._source != CPPFile::S_local || - in_ignorefile(wrapped_type->_file._filename_as_referenced)) { - // The wrapped type is defined in some other package or in an ignorable - // file. - return; - } - - // Check if any of the wrapped type's members are published. If none of - // them are, and the wrapped type itself is not marked for export, then - // never mind. - if (struct_type->_vis > min_vis) { - CPPScope *scope = struct_type->_scope; - - bool any_exported = false; - CPPScope::Declarations::const_iterator di; - for (di = scope->_declarations.begin(); - di != scope->_declarations.end() && !any_exported; - ++di) { - if ((*di)->_vis <= min_vis) { - any_exported = true; - break; - } - } - - if (!any_exported) { - return; - } - } - } - - get_type(type, true); -} - -/** - * Adds the indicated manifest constant to the database, if warranted. - */ -void InterrogateBuilder:: -scan_manifest(CPPManifest *manifest) { - if (manifest == nullptr) { - return; - } - - if (manifest->_loc.file.is_c_file()) { - // This #define appears in a .C file. We can only export manifests - // defined in a .h file. - return; - } - - if (manifest->_loc.file._source != CPPFile::S_local || - in_ignorefile(manifest->_loc.file._filename_as_referenced)) { - // The manifest is defined in some other package or in an ignorable file. - return; - } - - if (manifest->_vis > min_vis) { - // The manifest is not marked for export. - return; - } - - if (manifest->_has_parameters) { - // We can't export manifest functions. - return; - } - - InterrogateManifest imanifest; - imanifest._name = manifest->_name; - imanifest._definition = manifest->expand(); - - CPPType *type = manifest->determine_type(); - if (type != nullptr) { - imanifest._flags |= InterrogateManifest::F_has_type; - imanifest._type = get_type(type, false); - - CPPExpression *expr = manifest->_expr; - CPPExpression::Result result = expr->evaluate(); - if (result._type == CPPExpression::RT_integer) { - // We have an integer-valued expression. - imanifest._flags |= InterrogateManifest::F_has_int_value; - imanifest._int_value = result.as_integer(); - - } else { - // We have a more complex expression. Generate a getter function. - FunctionIndex getter = - get_getter(type, manifest->_name, nullptr, &parser, - nullptr); - - if (getter != 0) { - imanifest._flags |= InterrogateManifest::F_has_getter; - imanifest._getter = getter; - } - } - } - - ManifestIndex index = - InterrogateDatabase::get_ptr()->get_next_index(); - InterrogateDatabase::get_ptr()->add_manifest(index, imanifest); -} - -/** - * Adds the indicated data element to the database, if warranted. - */ -ElementIndex InterrogateBuilder:: -scan_element(CPPInstance *element, CPPStructType *struct_type, - CPPScope *scope) { - if (element == nullptr) { - return 0; - } - - if (element->is_template()) { - // The element is a template element, not a true element. - return 0; - } - - if (element->is_scoped()) { - if (element->get_scope(scope, &parser) != scope) { - // This is an element defined out-of-scope. It's probably the - // definition for a data member. Ignore it. - return 0; - } - } - - if (element->_file.is_c_file()) { - // This element declaration appears in a .C file. We can only export - // elements declared in a .h file. - return 0; - } - - if (struct_type == nullptr && - (element->_file._source != CPPFile::S_local || - in_ignorefile(element->_file._filename_as_referenced))) { - // The element is defined in some other package or in an ignorable file. - return 0; - } - - if (element->_vis > min_vis) { - // The element is not marked for export. - return 0; - } - - if ((element->_storage_class & CPPInstance::SC_static) != 0) { - // The element is static, so can't be exported. - return 0; - } - - // Make sure the element knows what its scope is. - if (element->_ident->_native_scope != scope) { - element = new CPPInstance(*element); - element->_ident = new CPPIdentifier(*element->_ident); - element->_ident->_native_scope = scope; - } - - CPPType *element_type = TypeManager::resolve_type(element->_type, scope); - CPPType *parameter_type = element_type; - - InterrogateElement ielement; - ielement._name = element->get_local_name(scope); - ielement._scoped_name = descope(element->get_local_name(&parser)); - - // See if there happens to be a comment before the element. - if (element->_leading_comment != nullptr) { - ielement._comment = trim_blanks(element->_leading_comment->_comment); - } - - ielement._type = get_type(TypeManager::unwrap_reference(element_type), false); - if (ielement._type == 0) { - // If we can't understand what type it is, forget it. - return 0; - } - - if (!TypeManager::involves_protected(element_type)) { - // We can only generate a getter and a setter if we can talk about the - // type it is. - - if (parameter_type->as_struct_type() != nullptr && - !parameter_type->is_trivial()) { - // Wrap the type in a const reference. - parameter_type = TypeManager::wrap_const_reference(parameter_type); - } - - // Generate a getter and setter function for the element. - FunctionIndex getter = - get_getter(parameter_type, element->get_local_name(scope), - struct_type, scope, element); - if (getter != 0) { - ielement._flags |= InterrogateElement::F_has_getter; - ielement._getter = getter; - } - - if (TypeManager::is_assignable(element_type)) { - FunctionIndex setter = - get_setter(parameter_type, element->get_local_name(scope), - struct_type, scope, element); - if (setter != 0) { - ielement._flags |= InterrogateElement::F_has_setter; - ielement._setter = setter; - } - } - } - - if (struct_type == nullptr) { - // This is a global data element: not a data member. - ielement._flags |= InterrogateElement::F_global; - } - - ElementIndex index = - InterrogateDatabase::get_ptr()->get_next_index(); - InterrogateDatabase::get_ptr()->add_element(index, ielement); - - return index; -} - -/** - * Adds a function to return the value for the indicated expression. Returns - * the new function index. - */ -FunctionIndex InterrogateBuilder:: -get_getter(CPPType *expr_type, string expression, - CPPStructType *struct_type, CPPScope *scope, - CPPInstance *element) { - // Make up a name for the function. - string fname = clean_identifier("get_" + expression); - - // Unroll the "const" from the expr_type, since that doesn't matter for a - // return type. - while (expr_type->as_const_type() != nullptr) { - expr_type = expr_type->as_const_type()->_wrapped_around; - assert(expr_type != nullptr); - } - - // We can't return an array from a function, but we can decay it into a - // pointer. - while (expr_type->get_subtype() == CPPDeclaration::ST_array) { - expr_type = CPPType::new_type(new CPPPointerType(expr_type->as_array_type()->_element_type)); - } - - // Make up a CPPFunctionType. - CPPParameterList *params = new CPPParameterList; - CPPFunctionType *ftype = new CPPFunctionType(expr_type, params, 0); - - // Now make up an instance for the function. - CPPInstance *function = new CPPInstance(ftype, fname); - function->_ident->_native_scope = scope; - - int getter_flags = InterrogateFunction::F_getter; - - if (struct_type != nullptr) { - // This is a data member for some class. - assert(element != nullptr); - assert(scope != nullptr); - - if ((element->_storage_class & CPPInstance::SC_static) != 0) { - // This is a static data member; therefore, the synthesized getter is - // also static. - function->_storage_class |= CPPInstance::SC_static; - - // And the expression is fully scoped. - expression = element->get_local_name(&parser); - - } else { - // This is a non-static data member, so it has a const synthesized - // getter method. - ftype->_flags |= CPPFunctionType::F_const_method; - - // And the expression is locally scoped. - expression = element->get_local_name(scope); - getter_flags |= InterrogateFunction::F_method; - } - } - - // Now check to see if there's already a function matching this name. If - // there is, we can't define a getter, and we shouldn't mistake this other - // function for a synthesized getter. - string function_name = TypeManager::get_function_name(function); - if (_functions_by_name.count(function_name) != 0) { - return 0; - } - - ostringstream desc; - desc << "getter for "; - if (element != nullptr) { - element->_initializer = nullptr; - element->output(desc, 0, &parser, false); - desc << ";"; - } else { - desc << expression; - } - string description = desc.str(); - - // It's clear; make a getter. - FunctionIndex index = - get_function(function, description, - struct_type, scope, - getter_flags, expression); - - InterrogateDatabase::get_ptr()->update_function(index)._comment = description; - return index; -} - -/** - * Adds a function to return the value for the indicated expression. Returns - * the new function index. - */ -FunctionIndex InterrogateBuilder:: -get_setter(CPPType *expr_type, string expression, - CPPStructType *struct_type, CPPScope *scope, - CPPInstance *element) { - // Make up a name for the function. - string fname = clean_identifier("set_" + expression); - - // Make up a CPPFunctionType. - CPPParameterList *params = new CPPParameterList; - CPPInstance *param0 = new CPPInstance(expr_type, "value"); - params->_parameters.push_back(param0); - CPPType *void_type = TypeManager::get_void_type(); - CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0); - - // Now make up an instance for the function. - CPPInstance *function = new CPPInstance(ftype, fname); - function->_ident->_native_scope = scope; - - int setter_flags = InterrogateFunction::F_setter; - - if (struct_type != nullptr) { - // This is a data member for some class. - assert(element != nullptr); - assert(scope != nullptr); - - if ((element->_storage_class & CPPInstance::SC_static) != 0) { - // This is a static data member; therefore, the synthesized setter is - // also static. - function->_storage_class |= CPPInstance::SC_static; - - // And the expression is fully scoped. - expression = element->get_local_name(&parser); - - } else { - // This is a non-static data member. The expression is locally scoped. - expression = element->get_local_name(scope); - setter_flags |= InterrogateFunction::F_method; - } - } - - // Now check to see if there's already a function matching this name. If - // there is, we can't define a setter, and we shouldn't mistake this other - // function for a synthesized setter. - string function_name = TypeManager::get_function_name(function); - if (_functions_by_name.count(function_name) != 0) { - return 0; - } - - ostringstream desc; - desc << "setter for "; - if (element != nullptr) { - element->_initializer = nullptr; - element->output(desc, 0, &parser, false); - desc << ";"; - } else { - desc << expression; - } - string description = desc.str(); - - // It's clear; make a setter. - FunctionIndex index = - get_function(function, description, - struct_type, scope, - setter_flags, expression); - - InterrogateDatabase::get_ptr()->update_function(index)._comment = description; - return index; -} - -/** - * Adds a function to cast from a pointer of the indicated type to a pointer - * of the indicated type to the database. Returns the new function index. - */ -FunctionIndex InterrogateBuilder:: -get_cast_function(CPPType *to_type, CPPType *from_type, - const string &prefix) { - CPPInstance *function; - CPPStructType *struct_type = from_type->as_struct_type(); - CPPScope *scope = &parser; - - if (struct_type != nullptr) { - // We'll make this a method of the from type. - scope = struct_type->get_scope(); - - // Make up a name for the method. - string fname = - clean_identifier(prefix + "_to_" + get_preferred_name(to_type)); - - // Make up a CPPFunctionType. - CPPType *to_ptr_type = CPPType::new_type(new CPPPointerType(to_type)); - - CPPParameterList *params = new CPPParameterList; - CPPFunctionType *ftype = new CPPFunctionType(to_ptr_type, params, 0); - - // Now make up an instance for the function. - function = new CPPInstance(ftype, fname); - - } else { - // The from type isn't a struct or a class, so this has to be an external - // function. - - // Make up a name for the function. - string fname = - clean_identifier(prefix + "_" + get_preferred_name(from_type) + - "_to_" + get_preferred_name(to_type)); - - // Make up a CPPFunctionType. - CPPType *from_ptr_type = CPPType::new_type(new CPPPointerType(from_type)); - CPPType *to_ptr_type = CPPType::new_type(new CPPPointerType(to_type)); - - CPPInstance *param0 = new CPPInstance(from_ptr_type, "this"); - CPPParameterList *params = new CPPParameterList; - params->_parameters.push_back(param0); - CPPFunctionType *ftype = new CPPFunctionType(to_ptr_type, params, 0); - - // Now make up an instance for the function. - function = new CPPInstance(ftype, fname); - } - - ostringstream desc; - desc << prefix << " from " << *from_type << " to " << *to_type; - string description = desc.str(); - - FunctionIndex index = - get_function(function, description, - struct_type, scope, - InterrogateFunction::F_typecast); - - InterrogateDatabase::get_ptr()->update_function(index)._comment = description; - return index; -} - -/** - * Adds the indicated function to the database, if it is not already present. - * In either case, returns the FunctionIndex of the function within the - * database. - */ -FunctionIndex InterrogateBuilder:: -get_function(CPPInstance *function, string description, - CPPStructType *struct_type, - CPPScope *scope, int flags, - const string &expression) { - - // Get a unique function signature. Make sure we tell the function where - // its native scope is, so we get a fully-scoped signature. - - if (function->_ident->_native_scope != scope) { - function = new CPPInstance(*function); - function->_ident = new CPPIdentifier(*function->_ident); - function->_ident->_native_scope = scope; - } - CPPFunctionType *ftype = - function->_type->resolve_type(scope, &parser)->as_function_type(); - function->_type = ftype; - - if ((ftype->_flags & CPPFunctionType::F_constructor) && - struct_type != nullptr && - struct_type->is_abstract()) { - // This is a constructor for an abstract class; forget it. - return 0; - } - - TypeIndex class_index = 0; - if (struct_type != nullptr) { - class_index = get_type(struct_type, false); - } - - string function_name = TypeManager::get_function_name(function); - string function_signature = TypeManager::get_function_signature(function); - - if (ftype->_flags & CPPFunctionType::F_unary_op) { - // This is a unary operator function. Name it differently so we don't - // consider it an overloaded version of a similarly-named binary operator. - function_name += "unary"; - } - - // First, check to see if it's already there. - FunctionsByName::const_iterator tni = - _functions_by_name.find(function_name); - if (tni != _functions_by_name.end()) { - FunctionIndex index = (*tni).second; - - // It's already here, so update the flags. - InterrogateFunction &ifunction = - InterrogateDatabase::get_ptr()->update_function(index); - - ifunction._flags |= flags; - - // Also, make sure this particular signature is defined. - std::pair result = - ifunction._instances->insert(InterrogateFunction::Instances::value_type(function_signature, function)); - - InterrogateFunction::Instances::iterator ii = result.first; - bool inserted = result.second; - - if (inserted) { - // If we just added the new signature, append the prototype. - ostringstream prototype; - function->output(prototype, 0, &parser, false); - prototype << ";"; - ifunction._prototype += "\n" + prototype.str(); - } - - // Also set the comment. - if (function->_leading_comment != nullptr) { - string comment = trim_blanks(function->_leading_comment->_comment); - if (!ifunction._comment.empty()) { - ifunction._comment += "\n\n"; - } - ifunction._comment += comment; - - // And update the particular wrapper comment. - if ((*ii).second->_leading_comment == nullptr || - function->_leading_comment->_comment.length() > - (*ii).second->_leading_comment->_comment.length()) { - (*ii).second->_leading_comment = function->_leading_comment; - } - } - - return index; - } - - // It isn't here, so we'll have to define it. - FunctionIndex index = - InterrogateDatabase::get_ptr()->get_next_index(); - _functions_by_name[function_name] = index; - - InterrogateFunction *ifunction = new InterrogateFunction; - ifunction->_name = function->get_local_name(scope); - ifunction->_scoped_name = descope(function->get_local_name(&parser)); - ifunction->_instances = new InterrogateFunction::Instances; - - if (function->_leading_comment != nullptr) { - ifunction->_comment = trim_blanks(function->_leading_comment->_comment); - } - - ostringstream prototype; - function->output(prototype, 0, &parser, false); - prototype << ";"; - ifunction->_prototype = prototype.str(); - - if (struct_type != nullptr) { - // The function is a method. - ifunction->_flags |= InterrogateFunction::F_method; - ifunction->_class = class_index; - } - - if (ftype->_flags & CPPFunctionType::F_unary_op) { - // This is a special unary function. - ifunction->_flags |= InterrogateFunction::F_unary_op; - } - - if (ftype->_flags & CPPFunctionType::F_operator_typecast) { - // This is a special typecast operator. - ifunction->_flags |= InterrogateFunction::F_operator_typecast; - } - - if (ftype->_flags & CPPFunctionType::F_constructor) { - // This is a constructor. - ifunction->_flags |= InterrogateFunction::F_constructor; - } - - if (ftype->_flags & CPPFunctionType::F_destructor) { - // This is a destructor. - ifunction->_flags |= InterrogateFunction::F_destructor; - } - - if (function->_storage_class & CPPInstance::SC_virtual) { - // This is a virtual function. - ifunction->_flags |= InterrogateFunction::F_virtual; - } - - ifunction->_flags |= flags; - ifunction->_instances->insert(InterrogateFunction::Instances::value_type(function_signature, function)); - ifunction->_expression = expression; - - InterrogateDatabase::get_ptr()->add_function(index, ifunction); - - return index; -} - -/** - * Adds the indicated make_property or make_seq_property to the database, if - * it is not already present. In either case, returns the ElementIndex - * of the created property within the database. - */ -ElementIndex InterrogateBuilder:: -get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CPPScope *scope) { - // This is needed so we can get a proper unique name for the property. - if (make_property->_ident->_native_scope != scope) { - make_property = new CPPMakeProperty(*make_property); - make_property->_ident = new CPPIdentifier(*make_property->_ident); - make_property->_ident->_native_scope = scope; - } - - string property_name = make_property->get_local_name(&parser); - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - - // First, check to see if it's already there. - ElementIndex index = 0; - PropertiesByName::const_iterator tni = - _properties_by_name.find(property_name); - if (tni != _properties_by_name.end()) { - index = (*tni).second; - const InterrogateElement &ielem = idb->get_element(index); - if (ielem._make_property == make_property) { - // This is the same property. - return index; - } - - // It is possible to have property definitions with the same name, but - // they cannot define conflicting interfaces. - if ((ielem.is_sequence() || ielem.is_mapping()) != - (make_property->_type != CPPMakeProperty::T_normal)) { - cerr << "Conflicting property definitions for " << property_name << "!\n"; - return index; - } - } - - // If we have a length function (ie. this is a sequence property), we should - // find the function that will give us the length. - FunctionIndex length_function = 0; - CPPFunctionGroup *fgroup = make_property->_length_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = function->_type->as_function_type(); - if (ftype != nullptr) { - length_function = get_function(function, "", struct_type, - struct_type->get_scope(), 0); - if (length_function != 0) { - break; - } - } - } - if (length_function == 0) { - cerr << "No instance of length method '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } - - // Find the getter so we can get its return type. - CPPInstance *getter = nullptr; - CPPType *return_type = nullptr; - - // How many arguments we expect the getter to have. - size_t num_args = (size_t)(make_property->_type != CPPMakeProperty::T_normal); - - fgroup = make_property->_get_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = function->_type->as_function_type(); - if (ftype == nullptr) { - continue; - } - - const CPPParameterList::Parameters ¶ms = ftype->_parameters->_parameters; - - size_t expected_num_args = 0; - size_t index_arg = 0; - - if (make_property->_type != CPPMakeProperty::T_normal) { - ++expected_num_args; - } - - if (!params.empty() && params[0]->get_simple_name() == "self" && - TypeManager::is_pointer_to_PyObject(params[0]->_type)) { - // Taking a PyObject *self argument. - expected_num_args += 1; - index_arg += 1; - } - - // The getter must either take no arguments, or all defaults. - if (params.size() == expected_num_args || - (params.size() > expected_num_args && - params[expected_num_args]->_initializer != nullptr)) { - // If this is a sequence getter, it must take an index argument. - if (make_property->_type == CPPMakeProperty::T_sequence && - !TypeManager::is_integer(params[index_arg]->_type)) { - continue; - } - - getter = function; - return_type = ftype->_return_type; - - // The return type of the non-const method probably better represents - // the type of the property we are creating. - if ((ftype->_flags & CPPFunctionType::F_const_method) == 0) { - break; - } - } - } - - if (getter == nullptr || return_type == nullptr) { - cerr << "No instance of getter '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } - - // Find the "hasser". - CPPInstance *hasser = nullptr; - - fgroup = make_property->_has_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = - function->_type->as_function_type(); - if (ftype != nullptr && (TypeManager::is_integer(ftype->_return_type) || - TypeManager::is_pointer(ftype->_return_type))) { - hasser = function; - break; - } - } - - if (hasser == nullptr) { - cerr << "No instance of has-function '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } - - // And the "deleter". - CPPInstance *deleter = nullptr; - - fgroup = make_property->_del_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = function->_type->as_function_type(); - if (ftype != nullptr) { - const CPPParameterList::Parameters ¶ms = ftype->_parameters->_parameters; - if (params.size() == num_args || - (params.size() > num_args && params[num_args]->_initializer != nullptr)) { - deleter = function; - break; - } - } - } - - if (deleter == nullptr) { - cerr << "No instance of delete-function '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } - - // And the "inserter". - CPPInstance *inserter = nullptr; - - fgroup = make_property->_insert_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = function->_type->as_function_type(); - if (ftype != nullptr && ftype->_parameters->_parameters.size() == 2) { - inserter = function; - break; - } - } - - if (inserter == nullptr) { - cerr << "No instance of insert-function '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } - - // And the function that returns a key by index. - CPPInstance *getkey_function = nullptr; - - fgroup = make_property->_get_key_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = function->_type->as_function_type(); - if (ftype != nullptr) { - getkey_function = function; - break; - } - } - - if (getkey_function == nullptr) { - cerr << "No instance of get-key-function '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } - - if (index == 0) { - // It isn't here, so we'll have to define it. - index = idb->get_next_index(); - _properties_by_name[property_name] = index; - - InterrogateElement iproperty; - iproperty._name = make_property->get_simple_name(); - iproperty._scoped_name = descope(make_property->get_local_name(&parser)); - idb->add_element(index, iproperty); - } - - InterrogateElement &iproperty = idb->update_element(index); - - if (return_type != nullptr) { - TypeIndex return_index = get_type(TypeManager::unwrap_reference(return_type), false); - if (iproperty._type != 0 && iproperty._type != return_index) { - cerr << "Property " << property_name << " has inconsistent element type!\n"; - } - iproperty._type = return_index; - } else { - iproperty._type = 0; - } - - if (make_property->_type & CPPMakeProperty::T_sequence) { - iproperty._flags |= InterrogateElement::F_sequence; - iproperty._length_function = length_function; - assert(length_function != 0); - } - - if (make_property->_type & CPPMakeProperty::T_mapping) { - iproperty._flags |= InterrogateElement::F_mapping; - iproperty._length_function = length_function; - } - - if (getter != nullptr) { - iproperty._flags |= InterrogateElement::F_has_getter; - iproperty._getter = get_function(getter, "", struct_type, - struct_type->get_scope(), 0); - nassertr(iproperty._getter, 0); - } - - if (hasser != nullptr) { - iproperty._flags |= InterrogateElement::F_has_has_function; - iproperty._has_function = get_function(hasser, "", struct_type, - struct_type->get_scope(), 0); - nassertr(iproperty._has_function, 0); - } - - if (deleter != nullptr) { - iproperty._flags |= InterrogateElement::F_has_del_function; - iproperty._del_function = get_function(deleter, "", struct_type, - struct_type->get_scope(), 0); - nassertr(iproperty._del_function, 0); - } - - if (inserter != nullptr) { - iproperty._flags |= InterrogateElement::F_has_insert_function; - iproperty._insert_function = get_function(inserter, "", struct_type, - struct_type->get_scope(), 0); - nassertr(iproperty._insert_function, 0); - } - - if (getkey_function != nullptr) { - iproperty._flags |= InterrogateElement::F_has_getkey_function; - iproperty._getkey_function = get_function(getkey_function, "", struct_type, - struct_type->get_scope(), 0); - nassertr(iproperty._getkey_function, 0); - } - - // See if there happens to be a comment before the MAKE_PROPERTY macro. - if (make_property->_leading_comment != nullptr) { - iproperty._comment = trim_blanks(make_property->_leading_comment->_comment); - - } else if (getter->_leading_comment != nullptr) { - // Take the comment from the getter. - iproperty._comment = trim_blanks(getter->_leading_comment->_comment); - } - - // Now look for setters. - fgroup = make_property->_set_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - iproperty._flags |= InterrogateElement::F_has_setter; - iproperty._setter = get_function(function, "", struct_type, - struct_type->get_scope(), 0); - nassertr(iproperty._setter, 0); - break; - } - } - - fgroup = make_property->_clear_function; - if (fgroup != nullptr) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - iproperty._flags |= InterrogateElement::F_has_clear_function; - iproperty._clear_function = get_function(function, "", struct_type, - struct_type->get_scope(), 0); - nassertr(iproperty._clear_function, 0); - break; - } - } - - return index; -} - -/** - * Adds the indicated make_seq to the database, if it is not already present. - * In either case, returns the MakeSeq of the make_seq within the database. - */ -MakeSeqIndex InterrogateBuilder:: -get_make_seq(CPPMakeSeq *make_seq, CPPStructType *struct_type) { - string make_seq_name = make_seq->get_local_name(&parser); - - // First, check to see if it's already there. - MakeSeqsByName::const_iterator tni = - _make_seqs_by_name.find(make_seq_name); - if (tni != _make_seqs_by_name.end()) { - MakeSeqIndex index = (*tni).second; - return index; - } - - FunctionIndex length_getter = 0; - FunctionIndex element_getter = 0; - - CPPFunctionGroup::Instances::const_iterator fi; - CPPFunctionGroup *fgroup = make_seq->_length_getter; - if (fgroup != nullptr) { - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = - function->_type->as_function_type(); - if (ftype != nullptr) { - length_getter = get_function(function, "", struct_type, - struct_type->get_scope(), 0); - if (length_getter != 0) { - break; - } - } - } - if (length_getter == 0) { - cerr << "No instance of length method '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } else { - cerr << "MAKE_SEQ " << make_seq_name << " requires a length method.\n"; - return 0; - } - - fgroup = make_seq->_element_getter; - if (fgroup != nullptr) { - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - CPPFunctionType *ftype = - function->_type->as_function_type(); - if (ftype != nullptr && ftype->_parameters->_parameters.size() >= 1 && - TypeManager::is_integer(ftype->_parameters->_parameters[0]->_type)) { - // It really doesn't matter whether we grab the const or non-const - // version, since they should all return the same function anyway. - element_getter = get_function(function, "", struct_type, - struct_type->get_scope(), 0); - if (element_getter != 0) { - break; - } - } - } - if (element_getter == 0) { - cerr << "No instance of element method '" - << fgroup->_name << "' is suitable!\n"; - return 0; - } - } else { - cerr << "MAKE_SEQ " << make_seq_name << " requires an element method.\n"; - return 0; - } - - InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); - // It isn't here, so we'll have to define it. - MakeSeqIndex index = idb->get_next_index(); - _make_seqs_by_name[make_seq_name] = index; - - InterrogateMakeSeq imake_seq; - imake_seq._name = make_seq->get_simple_name(); - imake_seq._scoped_name = descope(make_seq->get_local_name(&parser)); - - imake_seq._length_getter = length_getter; - imake_seq._element_getter = element_getter; - - // See if there happens to be a comment before the MAKE_SEQ macro. - if (make_seq->_leading_comment != nullptr) { - imake_seq._comment = trim_blanks(make_seq->_leading_comment->_comment); - } - - idb->add_make_seq(index, imake_seq); - - return index; -} - -/** - * Returns a TypeIndex for the "atomic string" type, which is a bogus type - * that might be used if -string is passed to interrogate. It means to - * translate basic_string and char * to whatever atomic string type is - * native to the particular the scripting language we happen to be generating - * wrappers for. - */ -TypeIndex InterrogateBuilder:: -get_atomic_string_type() { - // Make up a true name that can't possibly clash with an actual C++ type - // name. - string true_name = "atomic string"; - - TypesByName::const_iterator tni = _types_by_name.find(true_name); - if (tni != _types_by_name.end()) { - return (*tni).second; - } - - // This is the first time the atomic string has been requested; define it - // now. - - TypeIndex index = InterrogateDatabase::get_ptr()->get_next_index(); - _types_by_name[true_name] = index; - - InterrogateType itype; - itype._flags |= InterrogateType::F_atomic; - itype._atomic_token = AT_string; - itype._true_name = true_name; - itype._scoped_name = true_name; - itype._name = true_name; - - InterrogateDatabase::get_ptr()->add_type(index, itype); - - return index; -} - -/** - * Adds the indicated type to the database, if it is not already present. In - * either case, returns the TypeIndex of the type within the database. - */ -TypeIndex InterrogateBuilder:: -get_type(CPPType *type, bool global) { - if (type->is_template()) { - // Can't do anything with a template type. - return 0; - } - - if (type->get_subtype() == CPPType::ST_tbd) { - type = type->resolve_type(&parser, &parser); - } - - TypeIndex index = 0; - - // First, check to see if it's already there. - string true_name = type->get_local_name(&parser); - - if (true_name.empty()) { - // Whoops, it's an anonymous type. That's okay, because we'll usually - // only encounter them once anyway, so let's go ahead and define it - // without checking _types_by_name first. - - } else { - TypesByName::const_iterator tni = _types_by_name.find(true_name); - if (tni != _types_by_name.end()) { - // It's already here, so update the global flag. - index = (*tni).second; - if (index == 0) { - // This is an invalid type; we don't know anything about it. - return 0; - } - - InterrogateType &itype = InterrogateDatabase::get_ptr()->update_type(index); - if (global) { - itype._flags |= InterrogateType::F_global; - } - - if ((itype._flags & InterrogateType::F_fully_defined) != 0) { - return index; - } - - // But wait--it's not fully defined yet! We'll go ahead and define it - // now. - } - } - - bool forced = in_forcetype(true_name); - - if (index == 0) { - // It isn't already there, so we have to define it. - index = InterrogateDatabase::get_ptr()->get_next_index(); - if (!true_name.empty()) { - _types_by_name[true_name] = index; - } - - InterrogateType itype; - if (global) { - itype._flags |= InterrogateType::F_global; - } - - InterrogateDatabase::get_ptr()->add_type(index, itype); - } - - InterrogateType &itype = - InterrogateDatabase::get_ptr()->update_type(index); - - itype._name = get_preferred_name(type); - - int num_alt_names = type->get_num_alt_names(); - if (num_alt_names != 0) { - itype._alt_names.clear(); - for (int i = 0; i < num_alt_names; ++i) { - string alt_name = type->get_alt_name(i); - itype._alt_names.push_back(alt_name); - } - } - - itype._scoped_name = true_name; - itype._true_name = true_name; - itype._cpptype = type; - - if (type->_declaration != nullptr) { - // This type has a declaration; does the declaration have a comment? - CPPTypeDeclaration *decl = type->_declaration; - if (decl->_leading_comment != nullptr) { - itype._comment = trim_blanks(decl->_leading_comment->_comment); - } - } - - CPPScope *scope = nullptr; - // If it's an extension type or typedef, it might be scoped. - if (CPPTypedefType *td_type = type->as_typedef_type()) { - scope = td_type->_ident->get_scope(&parser, &parser); - - } else if (CPPExtensionType *ext_type = type->as_extension_type()) { - if (ext_type->_ident != nullptr) { - scope = ext_type->_ident->get_scope(&parser, &parser); - - } else if (CPPEnumType *enum_type = ext_type->as_enum_type()) { - // Special case for anonymous enums. - scope = enum_type->_parent_scope; - } - - } - - if (scope != nullptr) { - while (scope->as_template_scope() != nullptr) { - assert(scope->get_parent_scope() != scope); - scope = scope->get_parent_scope(); - assert(scope != nullptr); - } - itype._cppscope = scope; - - if (scope != &parser) { - // We're scoped! - itype._scoped_name = - descope(scope->get_local_name(&parser) + "::" + itype._name); - CPPStructType *struct_type = scope->get_struct_type(); - - if (struct_type != nullptr) { - itype._flags |= InterrogateType::F_nested; - itype._outer_class = get_type(struct_type, false); - } - } - } - - if (type->_attributes.has_attribute("deprecated")) { - itype._flags |= InterrogateType::F_deprecated; - } - - if (forced || !in_ignoretype(true_name)) { - itype._flags |= InterrogateType::F_fully_defined; - - if (type->as_simple_type() != nullptr) { - define_atomic_type(itype, type->as_simple_type()); - - } else if (type->as_pointer_type() != nullptr) { - define_wrapped_type(itype, type->as_pointer_type()); - - } else if (type->as_const_type() != nullptr) { - define_wrapped_type(itype, type->as_const_type()); - - } else if (type->as_struct_type() != nullptr) { - define_struct_type(itype, type->as_struct_type(), index, forced); - - } else if (type->as_enum_type() != nullptr) { - define_enum_type(itype, type->as_enum_type()); - - } else if (type->as_extension_type() != nullptr) { - define_extension_type(itype, type->as_extension_type()); - - } else if (type->as_typedef_type() != nullptr) { - define_typedef_type(itype, type->as_typedef_type()); - - } else if (type->as_array_type() != nullptr) { - define_array_type(itype, type->as_array_type()); - - } else { - nout << "Attempt to define invalid type " << *type - << " (subtype " << type->get_subtype() << ")\n"; - - // Remove the type from the database. - InterrogateDatabase::get_ptr()->remove_type(index); - if (!true_name.empty()) { - _types_by_name[true_name] = 0; - } - index = 0; - } - } - - return index; -} - -/** - * Builds up a definition for the indicated atomic type. - */ -void InterrogateBuilder:: -define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype) { - itype._flags |= InterrogateType::F_atomic; - - switch (cpptype->_type) { - case CPPSimpleType::T_bool: - itype._atomic_token = AT_bool; - break; - - case CPPSimpleType::T_char: - itype._atomic_token = AT_char; - break; - - case CPPSimpleType::T_wchar_t: - itype._atomic_token = AT_int; - break; - - case CPPSimpleType::T_char8_t: - itype._flags |= InterrogateType::F_unsigned; - itype._atomic_token = AT_int; - break; - - case CPPSimpleType::T_char16_t: - itype._flags |= InterrogateType::F_unsigned; - itype._atomic_token = AT_int; - break; - - case CPPSimpleType::T_char32_t: - itype._flags |= InterrogateType::F_unsigned; - itype._atomic_token = AT_int; - break; - - case CPPSimpleType::T_int: - if ((cpptype->_flags & CPPSimpleType::F_longlong) != 0) { - itype._atomic_token = AT_longlong; - } else { - itype._atomic_token = AT_int; - } - break; - - case CPPSimpleType::T_float: - itype._atomic_token = AT_float; - break; - - case CPPSimpleType::T_double: - itype._atomic_token = AT_double; - break; - - case CPPSimpleType::T_void: - itype._atomic_token = AT_void; - break; - - case CPPSimpleType::T_nullptr: - itype._atomic_token = AT_null; - break; - - default: - nout << "Type \"" << *cpptype << "\" has invalid CPPSimpleType: " - << (int)cpptype->_type << "\n"; - itype._atomic_token = AT_not_atomic; - } - - if ((cpptype->_flags & CPPSimpleType::F_longlong) != 0) { - itype._flags |= InterrogateType::F_longlong; - - } else if ((cpptype->_flags & CPPSimpleType::F_long) != 0) { - itype._flags |= InterrogateType::F_long; - } - - if ((cpptype->_flags & CPPSimpleType::F_short) != 0) { - itype._flags |= InterrogateType::F_short; - } - if ((cpptype->_flags & CPPSimpleType::F_unsigned) != 0) { - itype._flags |= InterrogateType::F_unsigned; - } - if ((cpptype->_flags & CPPSimpleType::F_signed) != 0) { - itype._flags |= InterrogateType::F_signed; - } -} - -/** - * Builds up a definition for the indicated wrapped type. - */ -void InterrogateBuilder:: -define_wrapped_type(InterrogateType &itype, CPPPointerType *cpptype) { - itype._flags |= (InterrogateType::F_wrapped | InterrogateType::F_pointer); - itype._wrapped_type = get_type(cpptype->_pointing_at, false); -} - -/** - * Builds up a definition for the indicated wrapped type. - */ -void InterrogateBuilder:: -define_wrapped_type(InterrogateType &itype, CPPConstType *cpptype) { - itype._flags |= (InterrogateType::F_wrapped | InterrogateType::F_const); - itype._wrapped_type = get_type(cpptype->_wrapped_around, false); -} - -/** - * Builds up a definition for the indicated struct type. - */ -void InterrogateBuilder:: -define_struct_type(InterrogateType &itype, CPPStructType *cpptype, - TypeIndex type_index, bool forced) { - if (cpptype->get_simple_name().empty()) { - // If the type has no name, forget it. We don't export anonymous structs. - return; - } - - cpptype = TypeManager::resolve_type(cpptype)->as_struct_type(); - assert(cpptype != nullptr); - bool has_virt_methods = cpptype->is_polymorphic(); - - switch (cpptype->_type) { - case CPPExtensionType::T_class: - itype._flags |= InterrogateType::F_class; - break; - - case CPPExtensionType::T_struct: - itype._flags |= InterrogateType::F_struct; - break; - - case CPPExtensionType::T_union: - itype._flags |= InterrogateType::F_union; - break; - - default: - break; - } - - if (cpptype->is_final()) { - itype._flags |= InterrogateType::F_final; - } - - if (cpptype->_file.is_c_file()) { - // This type declaration appears in a .C file. We can only export types - // defined in a .h file. - return; - } - - if (!forced && - (cpptype->_file._source != CPPFile::S_local || - in_ignorefile(cpptype->_file._filename_as_referenced))) { - // The struct type is defined in some other package or in an ignorable - // file, so don't try to output it. - - // This means we also don't gather any information about its derivations - // or determine if an implicit destructor is necessary. However, this is - // not important, and it causes problems if we do (how many implicit - // destructors do we need, anyway?). - itype._flags &= ~InterrogateType::F_fully_defined; - return; - } - - // Make sure the class declaration within its parent scope isn't private or - // protected. If it is, we can't export any of its members. - if (TypeManager::involves_unpublished(cpptype)) { - itype._flags &= ~InterrogateType::F_fully_defined; - itype._flags |= InterrogateType::F_unpublished; - return; - } - if (TypeManager::involves_protected(cpptype)) { - itype._flags &= ~InterrogateType::F_fully_defined; - return; - } - - // A struct type should always be global. - itype._flags |= InterrogateType::F_global; - - CPPScope *scope = cpptype->_scope; - - CPPStructType::Derivation::const_iterator bi; - for (bi = cpptype->_derivation.begin(); - bi != cpptype->_derivation.end(); - ++bi) { - - const CPPStructType::Base &base = (*bi); - if (base._vis <= V_public) { - CPPType *base_type = TypeManager::resolve_type(base._base, scope); - TypeIndex base_index = get_type(base_type, false); - - if (base_index == 0) { - if (base_type != nullptr) { - nout << *cpptype << " reports a derivation from invalid type " << *base_type << ".\n"; - } else { - nout << *cpptype << " reports a derivation from an invalid type.\n"; - } - - } else { - InterrogateType::Derivation d; - d._flags = 0; - d._base = base_index; - d._upcast = 0; - d._downcast = 0; - - // Do we need to synthesize upcast and downcast functions? - bool generate_casts = false; - - // Function To Generate all castsss Posible.. - if (base._is_virtual) { - // We do in the presence of virtual inheritance. - generate_casts = true; - - } else if (bi != cpptype->_derivation.begin()) { - // Or if we're not talking about the leftmost fork of multiple - // inheritance. - generate_casts = true; - - } else if (cpptype->_derivation.size() != 1 && - left_inheritance_requires_upcast) { - // Or even if we are the leftmost fork of multiple inheritance, if - // the flag is set indicating that this requires a pointer change. - // (For many compilers, this does not require a pointer change.) - generate_casts = true; - - } else if (has_virt_methods && (base_type->as_struct_type() == nullptr || !base_type->as_struct_type()->is_polymorphic())) { - // Finally, if this class has virtual methods, but its parent - // doesn't, then we have to upcast (because this class will require - // space for a virtual function table pointer, while the parent - // class won't). - generate_casts = true; - } - - if (generate_casts) { - d._upcast = get_cast_function(base_type, cpptype, "upcast"); - d._flags |= InterrogateType::DF_upcast; - - if (base._is_virtual) { - // If this is a virtual inheritance, we can't write a downcast. - d._flags |= InterrogateType::DF_downcast_impossible; - } else { - d._downcast = get_cast_function(cpptype, base_type, "downcast"); - d._flags |= InterrogateType::DF_downcast; - } - } - - itype._derivations.push_back(d); - } - } - } - - CPPScope::Declarations::const_iterator di; - for (di = scope->_declarations.begin(); - di != scope->_declarations.end(); - ++di) { - - if ((*di)->get_subtype() == CPPDeclaration::ST_instance) { - CPPInstance *inst = (*di)->as_instance(); - if (inst->_type->get_subtype() == CPPDeclaration::ST_function) { - // Here's a method declaration. - define_method(inst, itype, cpptype, scope); - - } else { - // Here's a data member declaration. - ElementIndex data_member = scan_element(inst, cpptype, scope); - if (data_member != 0) { - itype._elements.push_back(data_member); - } - } - - } else if ((*di)->get_subtype() == CPPDeclaration::ST_type_declaration) { - CPPType *type = (*di)->as_type_declaration()->_type; - - if ((*di)->_vis <= min_vis || in_forcetype(type->get_local_name(&parser))) { - if (type->as_struct_type() != nullptr || - type->as_enum_type() != nullptr) { - // Here's a nested class or enum definition. - type->_vis = (*di)->_vis; - - CPPExtensionType *nested_type = type->as_extension_type(); - assert(nested_type != nullptr); - - // For now, we don't allow anonymous structs. - if (nested_type->_ident != nullptr || - nested_type->as_enum_type() != nullptr) { - TypeIndex nested_index = get_type(nested_type, false); - itype._nested_types.push_back(nested_index); - } - } - } - } else if ((*di)->get_subtype() == CPPDeclaration::ST_enum) { - CPPType *type = (*di)->as_enum_type(); - - // An anonymous enum type. - if (type->_vis <= min_vis) { - TypeIndex nested_index = get_type(type, false); - itype._nested_types.push_back(nested_index); - } - - } else if ((*di)->get_subtype() == CPPDeclaration::ST_typedef) { - CPPTypedefType *type = (*di)->as_typedef_type(); - - // A nested typedef. Unwrap it to find out what it's pointing to. - CPPType *wrapped_type = type->_type; - - while (wrapped_type->get_subtype() == CPPDeclaration::ST_typedef) { - wrapped_type = wrapped_type->as_typedef_type()->_type; - } - - CPPStructType *struct_type = wrapped_type->as_struct_type(); - if (struct_type != nullptr) { - // We only export typedefs to structs, for now. - - if (type->_vis <= min_vis) { - TypeIndex nested_index = get_type(type, false); - itype._nested_types.push_back(nested_index); - } - } - - } else if ((*di)->get_subtype() == CPPDeclaration::ST_make_property) { - ElementIndex element_index = get_make_property((*di)->as_make_property(), cpptype, scope); - if (find(itype._elements.begin(), itype._elements.end(), element_index) == itype._elements.end()) { - itype._elements.push_back(element_index); - } - - } else if ((*di)->get_subtype() == CPPDeclaration::ST_make_seq) { - MakeSeqIndex make_seq_index = get_make_seq((*di)->as_make_seq(), cpptype); - itype._make_seqs.push_back(make_seq_index); - } - } - - // See if we need to generate an implicit default constructor. - CPPFunctionGroup *constructor = cpptype->get_constructor(); - if (constructor == nullptr && cpptype->is_default_constructible()) { - // Make a default constructor. - CPPType *void_type = TypeManager::get_void_type(); - CPPParameterList *params = new CPPParameterList; - CPPFunctionType *ftype = new CPPFunctionType(void_type, params, CPPFunctionType::F_constructor); - - // Now make up an instance for the default constructor. - CPPInstance *function = new CPPInstance(ftype, cpptype->get_simple_name()); - function->_storage_class |= CPPInstance::SC_inline | CPPInstance::SC_defaulted; - function->_vis = V_published; - - FunctionIndex index = get_function(function, "", cpptype, cpptype->get_scope(), - InterrogateFunction::F_constructor); - if (find(itype._constructors.begin(), itype._constructors.end(), - index) == itype._constructors.end()) { - itype._constructors.push_back(index); - } - } - - // See if we need to generate an implicit copy constructor. - CPPInstance *copy_constructor = cpptype->get_copy_constructor(); - if (copy_constructor == nullptr && - cpptype->is_copy_constructible()) { - // Make an implicit copy constructor. - CPPType *const_ref_type = TypeManager::wrap_const_reference(cpptype); - CPPInstance *param = new CPPInstance(const_ref_type, nullptr); - - CPPType *void_type = TypeManager::get_void_type(); - CPPParameterList *params = new CPPParameterList; - params->_parameters.push_back(param); - const int flags = CPPFunctionType::F_constructor | CPPFunctionType::F_copy_constructor; - CPPFunctionType *ftype = new CPPFunctionType(void_type, params, flags); - - // Now make up an instance for the copy constructor. - CPPInstance *function = new CPPInstance(ftype, cpptype->get_simple_name()); - function->_storage_class |= CPPInstance::SC_inline | CPPInstance::SC_defaulted; - function->_vis = V_published; - - FunctionIndex index = get_function(function, "", cpptype, cpptype->get_scope(), - InterrogateFunction::F_constructor); - if (find(itype._constructors.begin(), itype._constructors.end(), - index) == itype._constructors.end()) { - itype._constructors.push_back(index); - } - } - - if (!cpptype->is_destructible()) { - // There's no way to destruct the type. - itype._destructor = 0; - - } else if ((itype._flags & InterrogateType::F_inherited_destructor) != 0) { - // If we have inherited our virtual destructor from our base class, go - // ahead and assign the same function index. - assert(!itype._derivations.empty()); - TypeIndex base_type_index = itype._derivations.front()._base; - InterrogateType &base_type = InterrogateDatabase::get_ptr()-> - update_type(base_type_index); - - itype._destructor = base_type._destructor; - - } else if ((itype._flags & - (InterrogateType::F_true_destructor | - InterrogateType::F_private_destructor | - InterrogateType::F_inherited_destructor | - InterrogateType::F_implicit_destructor)) == 0) { - // If we didn't get a destructor at all, we should make a wrapper for one - // anyway. - string function_name = "~" + cpptype->get_simple_name(); - - // Make up a CPPFunctionType. - CPPType *void_type = TypeManager::get_void_type(); - CPPParameterList *params = new CPPParameterList; - CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0); - ftype->_flags |= CPPFunctionType::F_destructor; - - // Now make up an instance for the destructor. - CPPInstance *function = new CPPInstance(ftype, function_name); - - itype._destructor = get_function(function, "", - cpptype, cpptype->get_scope(), - InterrogateFunction::F_destructor); - itype._flags |= InterrogateType::F_implicit_destructor; - } -} - -/** - * Updates the function definition in the database to include whatever comment - * is associated with this declaration. This is called when we encounted a - * method definition outside of the class or function definition in a C++ - * file; the only new information this might include for us is the comment. - */ -void InterrogateBuilder:: -update_function_comment(CPPInstance *function, CPPScope *scope) { - if (function->_leading_comment == nullptr) { - // No comment anyway. Forget it. - return; - } - - // Get a function name so we can look this method up. - if (function->_ident->_native_scope != scope) { - function = new CPPInstance(*function); - function->_ident = new CPPIdentifier(*function->_ident); - function->_ident->_native_scope = scope; - } - CPPFunctionType *ftype = - function->_type->resolve_type(scope, &parser)->as_function_type(); - function->_type = ftype; - - string function_name = TypeManager::get_function_name(function); - string function_signature = TypeManager::get_function_signature(function); - - if (ftype->_flags & CPPFunctionType::F_unary_op) { - // This is a unary operator function. Name it differently so we don't - // consider it an overloaded version of a similarly-named binary operator. - function_name += "unary"; - } - - // Now look it up. - FunctionsByName::const_iterator tni = - _functions_by_name.find(function_name); - if (tni != _functions_by_name.end()) { - FunctionIndex index = (*tni).second; - - // Here it is! - InterrogateFunction &ifunction = - InterrogateDatabase::get_ptr()->update_function(index); - - // Update the comment. - string comment = trim_blanks(function->_leading_comment->_comment); - if (!ifunction._comment.empty()) { - ifunction._comment += "\n\n"; - } - ifunction._comment += comment; - - // Also update the particular wrapper comment. - InterrogateFunction::Instances::iterator ii = - ifunction._instances->find(function_signature); - if (ii != ifunction._instances->end()) { - if ((*ii).second->_leading_comment == nullptr || - function->_leading_comment->_comment.length() > - (*ii).second->_leading_comment->_comment.length()) { - (*ii).second->_leading_comment = function->_leading_comment; - } - } - } -} - - -/** - * Adds the indicated member function to the struct type, - */ -void InterrogateBuilder:: -define_method(CPPFunctionGroup *fgroup, InterrogateType &itype, - CPPStructType *struct_type, CPPScope *scope) { - CPPFunctionGroup::Instances::const_iterator fi; - for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) { - CPPInstance *function = (*fi); - define_method(function, itype, struct_type, scope); - } -} - -/** - * Adds the indicated member function to the struct type, - */ -void InterrogateBuilder:: -define_method(CPPInstance *function, InterrogateType &itype, - CPPStructType *struct_type, CPPScope *scope) { - assert(function != nullptr); - assert(function->_type != nullptr && - function->_type->as_function_type() != nullptr); - CPPFunctionType *ftype = - function->_type->resolve_type(scope, &parser)->as_function_type(); - - if (function->is_template()) { - // The function is a template function, not a true function. - return; - } - - if (function->_storage_class & CPPInstance::SC_deleted) { - // It was explicitly marked as deleted. - return; - } - - // As a special kludgey extension, we consider a public static method called - // "get_class_type()" to be marked published, even if it is not. This - // allows us to export all of the TypeHandle system stuff without having to - // specifically flag get_class_type() as published. - bool force_publish = false; - if (function->get_simple_name() == "get_class_type" && - (function->_storage_class & CPPInstance::SC_static) != 0 && - function->_vis <= V_public) { - force_publish = true; - } - - if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) { - // A destructor is a special case. If it's public, we export it (even if - // it's not published), but if it's protected or private, we don't export - // it, and we flag it so we don't try to synthesize one later. - if (function->_vis > V_public) { - itype._flags |= InterrogateType::F_private_destructor; - return; - } - force_publish = true; - } - - if (!force_publish && function->_vis > min_vis) { - // The function is not marked to be exported. - return; - } - - if (TypeManager::involves_protected(ftype)) { - // We can't export the function because it involves parameter types that - // are protected or private. - return; - } - - if (in_ignoreinvolved(ftype)) { - // The function or its parameters involves something that the user - // requested we ignore. - if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) { - itype._flags |= InterrogateType::F_private_destructor; - } - return; - } - - if (in_ignoremember(function->get_simple_name())) { - // The user requested us to ignore members of this name. - if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) { - itype._flags |= InterrogateType::F_private_destructor; - } - return; - } - - if ((function->_storage_class & CPPInstance::SC_inherited_virtual) != 0 && - struct_type->_derivation.size() == 1 && - struct_type->_derivation[0]._vis <= V_public && - !struct_type->_derivation[0]._is_virtual) { - // If this function is a virtual function whose first appearance is in - // some base class, we don't need to repeat its definition here, since - // we're already inheriting it properly. However, we may need to make an - // exception in the presence of multiple inheritance. - if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) { - itype._flags |= InterrogateType::F_inherited_destructor; - return; - } - - // Let's make sure the that first appearance of the function is actually - // declared published. - if (is_inherited_published(function, struct_type)) { - return; - } - // If it isn't, we should publish this method anyway. - } - - if (TypeManager::involves_rvalue_reference(ftype)) { - return; - } - - FunctionIndex index = get_function(function, "", struct_type, scope, 0); - if (index != 0) { - if ((ftype->_flags & CPPFunctionType::F_constructor) != 0) { - if (find(itype._constructors.begin(), itype._constructors.end(), - index) == itype._constructors.end()) { - itype._constructors.push_back(index); - } - - } else if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) { - itype._flags |= InterrogateType::F_true_destructor; - itype._destructor = index; - - } else if ((ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) { - if (find(itype._casts.begin(), itype._casts.end(), - index) == itype._casts.end()) { - itype._casts.push_back(index); - } - - } else { - if (find(itype._methods.begin(), itype._methods.end(), - index) == itype._methods.end()) { - itype._methods.push_back(index); - } - - // For an operator [] returning a non-const reference, we synthesize an - // "item-assignment" operator, which does not exist in C++ but does in - // scripting languages. This allows `obj[n] = ...` - if (ftype->_return_type != nullptr && - ftype->_return_type->is_reference() && - !ftype->_return_type->remove_reference()->is_const() && - (ftype->_flags & CPPFunctionType::F_const_method) == 0 && - function->get_simple_name() == "operator []") { - - // Make up a CPPFunctionType with extra parameter. - CPPType *assign_type = TypeManager::wrap_const_reference(ftype->_return_type->remove_reference()); - CPPParameterList *params = new CPPParameterList(*(ftype->_parameters)); - CPPInstance *param1 = new CPPInstance(assign_type, "assign_val"); - params->_parameters.push_back(param1); - CPPType *void_type = TypeManager::get_void_type(); - CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0); - - // Now make up an instance for the function. - CPPInstance *function = new CPPInstance(ftype, "operator []="); - function->_ident->_native_scope = scope; - - FunctionIndex index = get_function(function, "", - struct_type, scope, - InterrogateFunction::F_item_assignment); - if (index != 0) { - if (find(itype._methods.begin(), itype._methods.end(), - index) == itype._methods.end()) { - itype._methods.push_back(index); - } - } - } - } - } -} - -/** - * Builds up a definition for the indicated enum type. - */ -void InterrogateBuilder:: -define_enum_type(InterrogateType &itype, CPPEnumType *cpptype) { - itype._flags |= InterrogateType::F_enum; - - CPPScope *scope = cpptype->_parent_scope; - if (cpptype->_ident != nullptr) { - scope = cpptype->_ident->get_scope(&parser, &parser); - } - - // Make sure the enum declaration within its parent scope isn't private or - // protected. If it is, we can't export any of its members. - if (TypeManager::involves_unpublished(cpptype)) { - itype._flags &= ~InterrogateType::F_fully_defined; - itype._flags |= InterrogateType::F_unpublished; - return; - } - - if (cpptype->is_scoped()) { - itype._flags |= InterrogateType::F_scoped_enum; - } - - int next_value = 0; - - CPPEnumType::Elements::const_iterator ei; - for (ei = cpptype->_elements.begin(); - ei != cpptype->_elements.end(); - ++ei) { - CPPInstance *element = (*ei); - - // Tell the enum element where its native scope is, so we can get a - // properly scoped name. - - if (element->_ident->_native_scope != scope) { - element = new CPPInstance(*element); - element->_ident = new CPPIdentifier(*element->_ident); - element->_ident->_native_scope = scope; - } - - InterrogateType::EnumValue evalue; - evalue._name = element->get_simple_name(); - evalue._scoped_name = descope(element->get_local_name(&parser)); - - if (element->_leading_comment != nullptr) { - evalue._comment = trim_blanks(element->_leading_comment->_comment); - } - - if (element->_initializer != nullptr) { - CPPExpression::Result result = element->_initializer->evaluate(); - - if (result._type == CPPExpression::RT_error) { - nout << "enum value "; - element->output(nout, 0, &parser, true); - nout << " has invalid definition!\n"; - return; - } else { - next_value = result.as_integer(); - } - } - evalue._value = next_value; - itype._enum_values.push_back(evalue); - - next_value++; - } -} - -/** - * Builds up a definition for the indicated typedef. - */ -void InterrogateBuilder:: -define_typedef_type(InterrogateType &itype, CPPTypedefType *cpptype) { - itype._flags |= InterrogateType::F_typedef; - itype._wrapped_type = get_type(cpptype->_type, false); -} - -/** - * Builds up a definition for the indicated wrapped type. - */ -void InterrogateBuilder:: -define_array_type(InterrogateType &itype, CPPArrayType *cpptype) { - itype._flags |= InterrogateType::F_array; - itype._wrapped_type = get_type(cpptype->_element_type, false); - - if (cpptype->_bounds == nullptr) { - // This indicates an unsized array. - itype._array_size = -1; - } else { - itype._array_size = cpptype->_bounds->evaluate().as_integer(); - } -} - -/** - * Builds up a definition for the indicated extension type. - */ -void InterrogateBuilder:: -define_extension_type(InterrogateType &itype, CPPExtensionType *cpptype) { - // An "extension type" as returned by CPPParser is really a forward - // reference to an undefined struct or class type. - itype._flags &= ~InterrogateType::F_fully_defined; - - // But we can at least indicate which of the various extension types it is. - switch (cpptype->_type) { - case CPPExtensionType::T_enum: - case CPPExtensionType::T_enum_class: - case CPPExtensionType::T_enum_struct: - itype._flags |= InterrogateType::F_enum; - break; - - case CPPExtensionType::T_class: - itype._flags |= InterrogateType::F_class; - break; - - case CPPExtensionType::T_struct: - itype._flags |= InterrogateType::F_struct; - break; - - case CPPExtensionType::T_union: - itype._flags |= InterrogateType::F_union; - break; - } -} - -/** - * - */ -string InterrogateBuilder:: -trim_blanks(const string &str) { - size_t start = 0; - while (start < str.length() && isspace(str[start])) { - start++; - } - - size_t end = str.length(); - while (end > start && isspace(str[end - 1])) { - end--; - } - - return str.substr(start, end - start); -} diff --git a/dtool/src/interrogate/interrogateBuilder.h b/dtool/src/interrogate/interrogateBuilder.h deleted file mode 100644 index 1b182d3f560..00000000000 --- a/dtool/src/interrogate/interrogateBuilder.h +++ /dev/null @@ -1,167 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateBuilder.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef INTERROGATEBUILDER_H -#define INTERROGATEBUILDER_H - -#include "dtoolbase.h" - -#include "interrogate_interface.h" -#include "interrogate_request.h" - -#include -#include -#include - -class CPPFunctionGroup; -class CPPInstance; -class CPPType; -class CPPSimpleType; -class CPPPointerType; -class CPPConstType; -class CPPExtensionType; -class CPPStructType; -class CPPEnumType; -class CPPTypedefType; -class CPPArrayType; -class CPPFunctionType; -class CPPScope; -class CPPIdentifier; -class CPPNameComponent; -class CPPManifest; -class CPPMakeProperty; -class CPPMakeSeq; -class InterrogateType; -class InterrogateFunction; -class FunctionRemap; -class InterfaceMaker; - -/** - * This class builds up the InterrogateDatabase based on the data indicated by - * CPPParser after reading the source code. - */ -class InterrogateBuilder { -public: - void add_source_file(const std::string &filename); - void read_command_file(std::istream &in); - void do_command(const std::string &command, const std::string ¶ms); - void build(); - void write_code(std::ostream &out_code, std::ostream *out_include, InterrogateModuleDef *def); - InterrogateModuleDef *make_module_def(int file_identifier); - - static std::string clean_identifier(const std::string &name); - static std::string descope(const std::string &name); - FunctionIndex get_destructor_for(CPPType *type); - - std::string get_preferred_name(CPPType *type); - static std::string hash_string(const std::string &name, int shift_offset); - TypeIndex get_type(CPPType *type, bool global); - -public: - typedef std::set Commands; - typedef std::map CommandParams; - void insert_param_list(InterrogateBuilder::Commands &commands, - const std::string ¶ms); - - bool in_forcetype(const std::string &name) const; - std::string in_renametype(const std::string &name) const; - bool in_ignoretype(const std::string &name) const; - std::string in_defconstruct(const std::string &name) const; - bool in_ignoreinvolved(const std::string &name) const; - bool in_ignoreinvolved(CPPType *type) const; - bool in_ignorefile(const std::string &name) const; - bool in_ignoremember(const std::string &name) const; - bool in_noinclude(const std::string &name) const; - bool should_include(const std::string &filename) const; - - bool is_inherited_published(CPPInstance *function, CPPStructType *struct_type); - - void remap_indices(std::vector &remaps); - void scan_function(CPPFunctionGroup *fgroup); - void scan_function(CPPInstance *function); - void scan_struct_type(CPPStructType *type); - void scan_enum_type(CPPEnumType *type); - void scan_typedef_type(CPPTypedefType *type); - void scan_manifest(CPPManifest *manifest); - ElementIndex scan_element(CPPInstance *element, CPPStructType *struct_type, - CPPScope *scope); - - FunctionIndex get_getter(CPPType *expr_type, std::string expression, - CPPStructType *struct_type, CPPScope *scope, - CPPInstance *element); - FunctionIndex get_setter(CPPType *expr_type, std::string expression, - CPPStructType *struct_type, CPPScope *scope, - CPPInstance *element); - FunctionIndex get_cast_function(CPPType *to_type, CPPType *from_type, - const std::string &prefix); - FunctionIndex - get_function(CPPInstance *function, std::string description, - CPPStructType *struct_type, CPPScope *scope, - int flags, const std::string &expression = std::string()); - - ElementIndex - get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type, CPPScope *scope); - - MakeSeqIndex - get_make_seq(CPPMakeSeq *make_seq, CPPStructType *struct_type); - - TypeIndex get_atomic_string_type(); - - void define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype); - void define_wrapped_type(InterrogateType &itype, CPPPointerType *cpptype); - void define_wrapped_type(InterrogateType &itype, CPPConstType *cpptype); - void define_struct_type(InterrogateType &itype, CPPStructType *cpptype, - TypeIndex type_index, bool forced); - void update_function_comment(CPPInstance *function, CPPScope *scope); - void define_method(CPPFunctionGroup *fgroup, InterrogateType &itype, - CPPStructType *struct_type, CPPScope *scope); - void define_method(CPPInstance *function, InterrogateType &itype, - CPPStructType *struct_type, CPPScope *scope); - void define_enum_type(InterrogateType &itype, CPPEnumType *cpptype); - void define_typedef_type(InterrogateType &itype, CPPTypedefType *cpptype); - void define_array_type(InterrogateType &itype, CPPArrayType *cpptype); - void define_extension_type(InterrogateType &itype, - CPPExtensionType *cpptype); - - static std::string trim_blanks(const std::string &str); - - typedef std::map TypesByName; - typedef std::map FunctionsByName; - typedef std::map MakeSeqsByName; - typedef std::map PropertiesByName; - - TypesByName _types_by_name; - FunctionsByName _functions_by_name; - MakeSeqsByName _make_seqs_by_name; - PropertiesByName _properties_by_name; - - typedef std::map IncludeFiles; - IncludeFiles _include_files; - - Commands _forcetype; - CommandParams _renametype; - Commands _ignoretype; - CommandParams _defconstruct; - Commands _ignoreinvolved; - Commands _ignorefile; - Commands _ignoremember; - Commands _noinclude; - - std::string _library_hash_name; - - friend class FunctionRemap; -}; - -extern InterrogateBuilder builder; - -#endif diff --git a/dtool/src/interrogate/interrogate_composite1.cxx b/dtool/src/interrogate/interrogate_composite1.cxx deleted file mode 100644 index 39f08c9fe43..00000000000 --- a/dtool/src/interrogate/interrogate_composite1.cxx +++ /dev/null @@ -1,14 +0,0 @@ - -#include "interrogateBuilder.cxx" -#include "functionRemap.cxx" -#include "functionWriter.cxx" -#include "functionWriterPtrFromPython.cxx" -#include "functionWriterPtrToPython.cxx" -#include "functionWriters.cxx" -#include "interfaceMaker.cxx" -#include "interfaceMakerC.cxx" -#include "interfaceMakerPython.cxx" -#include "interfaceMakerPythonNative.cxx" -#include "interfaceMakerPythonObj.cxx" -#include "interfaceMakerPythonSimple.cxx" - diff --git a/dtool/src/interrogate/interrogate_composite2.cxx b/dtool/src/interrogate/interrogate_composite2.cxx deleted file mode 100644 index a427cf26744..00000000000 --- a/dtool/src/interrogate/interrogate_composite2.cxx +++ /dev/null @@ -1,19 +0,0 @@ - -#include "interrogate.cxx" -#include "typeManager.cxx" -#include "parameterRemap.cxx" -#include "parameterRemapBasicStringPtrToString.cxx" -#include "parameterRemapBasicStringRefToString.cxx" -#include "parameterRemapBasicStringToString.cxx" -#include "parameterRemapCharStarToString.cxx" -#include "parameterRemapConcreteToPointer.cxx" -#include "parameterRemapConstToNonConst.cxx" -#include "parameterRemapEnumToInt.cxx" -#include "parameterRemapPTToPointer.cxx" -#include "parameterRemapReferenceToConcrete.cxx" -#include "parameterRemapReferenceToPointer.cxx" -#include "parameterRemapThis.cxx" -#include "parameterRemapToString.cxx" -#include "parameterRemapHandleToInt.cxx" -#include "parameterRemapUnchanged.cxx" - diff --git a/dtool/src/interrogate/interrogate_module.cxx b/dtool/src/interrogate/interrogate_module.cxx deleted file mode 100644 index 5b42d1db029..00000000000 --- a/dtool/src/interrogate/interrogate_module.cxx +++ /dev/null @@ -1,621 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate_module.cxx - * @author drose - * @date 2000-08-08 - */ - -// This program generates a module-level file for interrogate. This is a -// higher level than library, and groups several libraries together. -// Presently, the only thing that goes into the module file is a python table, -// but who knows what the future holds. - -#include "interrogate_interface.h" -#include "interrogate_request.h" -#include "load_dso.h" -#include "pnotify.h" -#include "panda_getopt_long.h" -#include "preprocess_argv.h" -#include "vector_string.h" - -#include - -using std::cerr; -using std::string; - -// This contains a big source string determined at compile time. -extern const char interrogate_preamble_python_native[]; - -Filename output_code_filename; -string module_name; -string library_name; -bool build_c_wrappers = false; -bool build_python_wrappers = false; -bool build_python_native_wrappers = false; -bool track_interpreter = false; -vector_string imports; - -// Short command-line options. -static const char *short_options = ""; - -// Long command-line options. -enum CommandOptions { - CO_oc = 256, - CO_module, - CO_library, - CO_c, - CO_python, - CO_python_native, - CO_track_interpreter, - CO_import, -}; - -static struct option long_options[] = { - { "oc", required_argument, nullptr, CO_oc }, - { "module", required_argument, nullptr, CO_module }, - { "library", required_argument, nullptr, CO_library }, - { "c", no_argument, nullptr, CO_c }, - { "python", no_argument, nullptr, CO_python }, - { "python-native", no_argument, nullptr, CO_python_native }, - { "track-interpreter", no_argument, nullptr, CO_track_interpreter }, - { "import", required_argument, nullptr, CO_import }, - { nullptr } -}; - -/* -static string -upcase_string(const string &str) { - string result; - for (string::const_iterator si = str.begin(); - si != str.end(); - ++si) { - result += toupper(*si); - } - return result; -} -*/ - -/** - * Finds a dependency cycle between the given dependency mapping, starting at - * the node that is already placed in the given cycle vector. - */ -static bool find_dependency_cycle(vector_string &cycle, std::map > &dependencies) { - assert(!cycle.empty()); - - const std::set &deps = dependencies[cycle.back()]; - for (auto it = deps.begin(); it != deps.end(); ++it) { - auto it2 = std::find(cycle.begin(), cycle.end(), *it); - if (it2 != cycle.end()) { - // Chop off the part of the chain that is not relevant. - cycle.erase(cycle.begin(), it2); - cycle.push_back(*it); - return true; - } - - // Recurse. - cycle.push_back(*it); - if (find_dependency_cycle(cycle, dependencies)) { - return true; - } - cycle.pop_back(); - } - - return false; -} - -/** - * Given that a direct link has been established between the two libraries, - * finds the two types that make up this relationship and prints out the - * nature of their dependency. - */ -static bool print_dependent_types(const string &lib1, const string &lib2) { - for (int ti = 0; ti < interrogate_number_of_global_types(); ti++) { - TypeIndex thetype = interrogate_get_global_type(ti); - if (interrogate_type_has_module_name(thetype) && - interrogate_type_has_library_name(thetype) && - lib1 == interrogate_type_library_name(thetype) && - module_name == interrogate_type_module_name(thetype)) { - - // Get the dependencies for this library. - int num_derivations = interrogate_type_number_of_derivations(thetype); - for (int di = 0; di < num_derivations; ++di) { - TypeIndex basetype = interrogate_type_get_derivation(thetype, di); - if (interrogate_type_is_global(basetype) && - interrogate_type_has_library_name(basetype) && - interrogate_type_library_name(basetype) == lib2) { - cerr - << " " << interrogate_type_scoped_name(thetype) << " (" - << lib1 << ") inherits from " - << interrogate_type_scoped_name(basetype) << " (" << lib2 << ")\n"; - return true; - } - } - - // It also counts if this is a typedef pointing to another type. - if (interrogate_type_is_typedef(thetype)) { - TypeIndex wrapped = interrogate_type_wrapped_type(thetype); - if (interrogate_type_is_global(wrapped) && - interrogate_type_has_library_name(wrapped) && - interrogate_type_library_name(wrapped) == lib2) { - cerr - << " " << interrogate_type_scoped_name(thetype) << " (" - << lib1 << ") is a typedef to " - << interrogate_type_scoped_name(wrapped) << " (" << lib2 << ")\n"; - } - } - } - } - return false; -} - -int write_python_table_native(std::ostream &out) { - out << "\n#include \"dtoolbase.h\"\n" - << "#include \"interrogate_request.h\"\n\n" - << "#include \"py_panda.h\"\n\n"; - - int count = 0; - - std::map > dependencies; - -// out << "extern \"C\" {\n"; - - // Walk through all of the Python functions. - int num_functions = interrogate_number_of_functions(); - int fi; - for (fi = 0; fi < num_functions; fi++) { - FunctionIndex function_index = interrogate_get_function(fi); - - // Consider only those that belong in the module we asked for. if - // (interrogate_function_has_module_name(function_index) && module_name == - // interrogate_function_module_name(function_index)) { if it has a library - // name add it to set of libraries - if (interrogate_function_has_library_name(function_index)) { - string library_name = interrogate_function_library_name(function_index); - dependencies[library_name]; - } - // } - } - - for (int ti = 0; ti < interrogate_number_of_global_types(); ti++) { - TypeIndex thetype = interrogate_get_global_type(ti); - if (interrogate_type_has_module_name(thetype) && module_name == interrogate_type_module_name(thetype)) { - if (interrogate_type_has_library_name(thetype)) { - string library_name = interrogate_type_library_name(thetype); - std::set &deps = dependencies[library_name]; - - // Get the dependencies for this library. - int num_derivations = interrogate_type_number_of_derivations(thetype); - for (int di = 0; di < num_derivations; ++di) { - TypeIndex basetype = interrogate_type_get_derivation(thetype, di); - if (interrogate_type_is_global(basetype) && - interrogate_type_has_library_name(basetype)) { - string baselib = interrogate_type_library_name(basetype); - if (baselib != library_name) { - deps.insert(std::move(baselib)); - } - } - } - - if (interrogate_type_is_typedef(thetype)) { - TypeIndex wrapped = interrogate_type_wrapped_type(thetype); - if (interrogate_type_is_global(wrapped) && - interrogate_type_has_library_name(wrapped)) { - string wrappedlib = interrogate_type_library_name(wrapped); - if (wrappedlib != library_name) { - deps.insert(std::move(wrappedlib)); - } - } - } - } - } - } - - // Now add the libraries in their proper ordering, based on dependencies. - vector_string libraries; - while (libraries.size() < dependencies.size()) { - // We have this check to make sure we don't enter an infinite loop. - bool added_any = false; - - for (auto it = dependencies.begin(); it != dependencies.end(); ++it) { - const string &library_name = it->first; - std::set &deps = dependencies[library_name]; - - // Remove the dependencies that have already been added from the deps. - if (!deps.empty()) { - for (auto li = libraries.begin(); li != libraries.end(); ++li) { - deps.erase(*li); - } - } - - if (deps.empty()) { - // OK, no remaining dependencies, so we can add this. - if (std::find(libraries.begin(), libraries.end(), library_name) == libraries.end()) { - libraries.push_back(library_name); - added_any = true; - } - } - } - - if (!added_any) { - // Oh dear, we must have hit a circular dependency. Go through the - // remaining libraries to figure it out and print it. - cerr << "Circular dependency between libraries detected:\n"; - for (auto it = dependencies.begin(); it != dependencies.end(); ++it) { - const string &library_name = it->first; - std::set &deps = dependencies[library_name]; - if (deps.empty()) { - continue; - } - - // But since it does indicate a potential architectural flaw, we do - // want to let the user know about this. - vector_string cycle; - cycle.push_back(library_name); - if (!find_dependency_cycle(cycle, dependencies)) { - continue; - } - assert(cycle.size() >= 2); - - // Show the cycle of library dependencies. - auto ci = cycle.begin(); - cerr << " " << *ci; - for (++ci; ci != cycle.end(); ++ci) { - cerr << " -> " << *ci; - } - cerr << "\n"; - - // Now print out the actual types that make up the cycle. - ci = cycle.begin(); - string prev = *ci; - for (++ci; ci != cycle.end(); ++ci) { - print_dependent_types(prev, *ci); - prev = *ci; - } - - // We have to arbitrarily break one of the dependencies in order to be - // able to proceed. Break the first dependency. - dependencies[cycle[0]].erase(cycle[1]); - } - } - } - - vector_string::const_iterator ii; - for (ii = libraries.begin(); ii != libraries.end(); ++ii) { - printf("Referencing Library %s\n", (*ii).c_str()); - out << "extern const struct LibraryDef " << *ii << "_moddef;\n"; - out << "extern void Dtool_" << *ii << "_RegisterTypes();\n"; - out << "extern void Dtool_" << *ii << "_BuildInstants(PyObject *module);\n"; - } - - out.put('\n'); - - out << "#if PY_MAJOR_VERSION >= 3\n" - << "extern \"C\" EXPORT_CLASS PyObject *PyInit_" << library_name << "();\n" - << "#else\n" - << "extern \"C\" EXPORT_CLASS void init" << library_name << "();\n" - << "#endif\n"; - - out << "\n" - << "#if PY_MAJOR_VERSION >= 3\n" - << "static struct PyModuleDef py_" << library_name << "_module = {\n" - << " PyModuleDef_HEAD_INIT,\n" - << " \"" << module_name << "\",\n" - << " nullptr,\n" - << " -1,\n" - << " nullptr,\n" - << " nullptr, nullptr, nullptr, nullptr\n" - << "};\n" - << "\n" - << "PyObject *PyInit_" << library_name << "() {\n"; - - if (track_interpreter) { - out << " in_interpreter = 1;\n"; - } - - vector_string::const_iterator si; - for (si = imports.begin(); si != imports.end(); ++si) { - out << " PyImport_Import(PyUnicode_FromString(\"" << *si << "\"));\n"; - } - - for (ii = libraries.begin(); ii != libraries.end(); ii++) { - out << " Dtool_" << *ii << "_RegisterTypes();\n"; - } - out << "\n"; - - out << " const LibraryDef *defs[] = {"; - for(ii = libraries.begin(); ii != libraries.end(); ii++) { - out << "&" << *ii << "_moddef, "; - } - - out << "nullptr};\n" - << "\n" - << " PyObject *module = Dtool_PyModuleInitHelper(defs, &py_" << library_name << "_module);\n" - << " if (module != nullptr) {\n"; - - for (ii = libraries.begin(); ii != libraries.end(); ii++) { - out << " Dtool_" << *ii << "_BuildInstants(module);\n"; - } - - out << " }\n" - << " return module;\n" - << "}\n" - << "\n" - - << "#else // Python 2 case\n" - << "\n" - << "void init" << library_name << "() {\n"; - - if (track_interpreter) { - out << " in_interpreter = 1;\n"; - } - - for (si = imports.begin(); si != imports.end(); ++si) { - out << " PyImport_Import(PyUnicode_FromString(\"" << *si << "\"));\n"; - } - - for (ii = libraries.begin(); ii != libraries.end(); ii++) { - out << " Dtool_" << *ii << "_RegisterTypes();\n"; - } - out << "\n"; - - out << " const LibraryDef *defs[] = {"; - for(ii = libraries.begin(); ii != libraries.end(); ii++) { - out << "&" << *ii << "_moddef, "; - } - - out << "nullptr};\n" - << "\n" - << " PyObject *module = Dtool_PyModuleInitHelper(defs, \"" << module_name << "\");\n" - << " if (module != nullptr) {\n"; - - for (ii = libraries.begin(); ii != libraries.end(); ii++) { - out << " Dtool_" << *ii << "_BuildInstants(module);\n"; - } - - out << " }\n" - << "}\n" - << "#endif\n" - << "\n"; - - - return count; -} - -int write_python_table(std::ostream &out) { - out << "\n#include \"dtoolbase.h\"\n" - << "#include \"interrogate_request.h\"\n\n" - << "#undef _POSIX_C_SOURCE\n" - << "#include \"Python.h\"\n\n"; - - int count = 0; - - // First, we have to declare extern C prototypes for each of the function - // names. - - out << "extern \"C\" {\n"; - - // Walk through all of the Python functions. - int num_functions = interrogate_number_of_functions(); - int fi; - for (fi = 0; fi < num_functions; fi++) { - FunctionIndex function_index = interrogate_get_function(fi); - - // Consider only those that belong in the module we asked for. - if (interrogate_function_has_module_name(function_index) && - module_name == interrogate_function_module_name(function_index)) { - - // For each function, get all of the python wrappers. - int num_wrappers = - interrogate_function_number_of_python_wrappers(function_index); - - for (int wi = 0; wi < num_wrappers; wi++) { - FunctionWrapperIndex wrapper_index = - interrogate_function_python_wrapper(function_index, wi); - - if (interrogate_wrapper_is_callable_by_name(wrapper_index)) { - count++; - const char *wrapper_name = - interrogate_wrapper_name(wrapper_index); - out << " PyObject *" << wrapper_name - << "(PyObject *self, PyObject *args);\n"; - } - } - } - } - - out << "}\n\n"; - - // Now go back through and build the table of function names. - out << "static PyMethodDef python_methods[" << count + 1 << "] = {\n"; - - // Walk through all of the Python functions. - for (fi = 0; fi < num_functions; fi++) { - FunctionIndex function_index = interrogate_get_function(fi); - - // Consider only those that belong in the module we asked for. - if (interrogate_function_has_module_name(function_index) && - module_name == interrogate_function_module_name(function_index)) { - - // For each function, get all of the python wrappers. - int num_wrappers = - interrogate_function_number_of_python_wrappers(function_index); - for (int wi = 0; wi < num_wrappers; wi++) { - FunctionWrapperIndex wrapper_index = - interrogate_function_python_wrapper(function_index, wi); - - if (interrogate_wrapper_is_callable_by_name(wrapper_index)) { - const char *wrapper_name = - interrogate_wrapper_name(wrapper_index); - out << " { \"" - << wrapper_name << "\", &" - << wrapper_name << ", METH_VARARGS },\n"; - } - } - } - } - - if (library_name.empty()) { - library_name = module_name; - } - - out << " { nullptr, nullptr }\n" - << "};\n\n" - - << "#if PY_MAJOR_VERSION >= 3\n" - << "static struct PyModuleDef python_module = {\n" - << " PyModuleDef_HEAD_INIT,\n" - << " \"" << library_name << "\",\n" - << " nullptr,\n" - << " -1,\n" - << " python_methods,\n" - << " nullptr, nullptr, nullptr, nullptr\n" - << "};\n\n" - - << "#define INIT_FUNC PyObject *PyInit_" << library_name << "\n" - << "#else\n" - << "#define INIT_FUNC void init" << library_name << "\n" - << "#endif\n\n" - - << "#ifdef _WIN32\n" - << "extern \"C\" __declspec(dllexport) INIT_FUNC();\n" - << "#else\n" - << "extern \"C\" INIT_FUNC();\n" - << "#endif\n\n" - - << "INIT_FUNC() {\n"; - - if (track_interpreter) { - out << " in_interpreter = 1;\n"; - } - - out << "#if PY_MAJOR_VERSION >= 3\n" - << " return PyModule_Create(&python_module);\n" - << "#else\n" - << " Py_InitModule(\"" << library_name << "\", python_methods);\n" - << "#endif\n" - << "}\n\n"; - - return count; -} - -int main(int argc, char *argv[]) { - extern char *optarg; - extern int optind; - int flag; - - preprocess_argv(argc, argv); - flag = getopt_long_only(argc, argv, short_options, long_options, nullptr); - while (flag != EOF) { - switch (flag) { - case CO_oc: - output_code_filename = optarg; - break; - - case CO_module: - module_name = optarg; - break; - - case CO_library: - library_name = optarg; - break; - - case CO_c: - build_c_wrappers = true; - break; - - case CO_python: - build_python_wrappers = true; - break; - - case CO_python_native: - build_python_native_wrappers = true; - break; - - case CO_track_interpreter: - track_interpreter = true; - break; - - case CO_import: - imports.push_back(optarg); - break; - - default: - exit(1); - } - flag = getopt_long_only(argc, argv, short_options, long_options, nullptr); - } - - argc -= (optind-1); - argv += (optind-1); - - if (argc < 2) { - nout - << "\nUsage:\n" - << " interrogate-module [opts] libname.in [libname.in ...]\n\n"; - exit(1); - } - - output_code_filename.set_text(); - - if (!build_c_wrappers && !build_python_wrappers && !build_python_native_wrappers) { - build_c_wrappers = true; - } - - for (int i = 1; i < argc; i++) { - string param = argv[i]; - - - if (param.length() > 3 && param.substr(param.length() - 3) == ".in") { - // If the filename ends in ".in", it's an interrogate database file, not - // a shared library--read it directly. - interrogate_request_database(param.c_str()); - - } else { - // Otherwise, assume it's a shared library, and try to load it. - Filename pathname = argv[i]; - pathname.set_type(Filename::T_dso); - nout << "Loading " << pathname << "\n"; - void *dl = load_dso(DSearchPath(), pathname); - if (dl == nullptr) { - nout << "Unable to load: " << load_dso_error() << "\n"; - exit(1); - } - } - } - - // Now output the table. - if (!output_code_filename.empty()) { - pofstream output_code; - - if (!output_code_filename.open_write(output_code)) { - nout << "Unable to write to " << output_code_filename << "\n"; - } else { - - if (build_python_wrappers) { - int count = write_python_table(output_code); - nout << count << " python function wrappers exported.\n"; - } - - if (build_python_native_wrappers) { - write_python_table_native(output_code); - - // Output the support code. - output_code << interrogate_preamble_python_native << "\n"; - } - } - } - - if (interrogate_error_flag()) { - nout << "Error reading interrogate data.\n"; - output_code_filename.unlink(); - exit(1); - } - - return (0); -} diff --git a/dtool/src/interrogate/parameterRemap.I b/dtool/src/interrogate/parameterRemap.I deleted file mode 100644 index dac104e87fa..00000000000 --- a/dtool/src/interrogate/parameterRemap.I +++ /dev/null @@ -1,89 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemap.I - * @author drose - * @date 2000-08-01 - */ - -/** - * - */ -INLINE ParameterRemap:: -ParameterRemap(CPPType *orig_type) : - _orig_type(orig_type), - _new_type(orig_type) -{ - _is_valid = true; - _temporary_type = nullptr; - _default_value = nullptr; -} - -/** - * - */ -INLINE bool ParameterRemap:: -is_valid() const { - return _is_valid; -} - -/** - * Returns the type of the original, C++ parameter or return value. - */ -INLINE CPPType *ParameterRemap:: -get_orig_type() const { - return _orig_type; -} - -/** - * Returns the type of the wrapper's parameter or return value. This is the - * type that will be reported in the interrogate database, and the type that - * the scripting language is expected to deal with. - */ -INLINE CPPType *ParameterRemap:: -get_new_type() const { - return _new_type; -} - -/** - * Returns the type of any temporary variables used to hold the return value - * before returning it. This is normally the same as get_new_type(), but in - * some circumstances it may need to be different. - */ -INLINE CPPType *ParameterRemap:: -get_temporary_type() const { - if (_temporary_type == nullptr) { - return _new_type; - } else { - return _temporary_type; - } -} - -/** - * Returns true if this particular parameter has a default value defined. - */ -INLINE bool ParameterRemap:: -has_default_value() const { - return (_default_value != nullptr); -} - -/** - * Returns the expression corresponding to this parameter's default value. - */ -INLINE CPPExpression *ParameterRemap:: -get_default_value() const { - return _default_value; -} - -/** - * Records a default value to be associated with this parameter. - */ -INLINE void ParameterRemap:: -set_default_value(CPPExpression *expr) { - _default_value = expr; -} diff --git a/dtool/src/interrogate/parameterRemap.cxx b/dtool/src/interrogate/parameterRemap.cxx deleted file mode 100644 index 4794c7c16d6..00000000000 --- a/dtool/src/interrogate/parameterRemap.cxx +++ /dev/null @@ -1,118 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemap.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "parameterRemap.h" - -using std::string; - - -/** - * - */ -ParameterRemap:: -~ParameterRemap() { -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemap:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << variable_name; -} - -/** - * This will be called immediately before get_return_expr(). It outputs - * whatever lines the remapper needs to the function to set up its return - * value, e.g. to declare a temporary variable or something. It should - * return the modified expression. - */ -string ParameterRemap:: -prepare_return_expr(std::ostream &, int, const string &expression) { - return expression; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemap:: -get_return_expr(const string &expression) { - return expression; -} - -/** - * Returns the string that converts the expression stored in the indicated - * temporary variable to the appropriate return value type. This is normally - * a pass-through, but in cases when the temporary variable type must be - * different than the return type (i.e. get_temporary_type() != - * get_new_type()), this might perform some operation. - */ -string ParameterRemap:: -temporary_to_return(const string &temporary) { - return temporary; -} - -/** - * Returns true if the return value represents a value that was newly - * allocated, and hence must be explicitly deallocated later by the caller. - */ -bool ParameterRemap:: -return_value_needs_management() { - return false; -} - -/** - * If return_value_needs_management() returns true, this should return the - * index of the function that should be called when it is time to destruct the - * return value. It will generally be the same as the destructor for the - * class we just returned a pointer to. - */ -FunctionIndex ParameterRemap:: -get_return_value_destructor() { - return 0; -} - -/** - * This is a hack around a problem VC++ has with overly-complex expressions, - * particularly in conjunction with the 'new' operator. If this parameter - * type is one that will probably give VC++ a headache, this should be set - * true to indicate that the code generator should save the return value - * expression into a temporary variable first, and pass the temporary variable - * name in instead. - */ -bool ParameterRemap:: -return_value_should_be_simple() { - return false; -} - - -/** - * Returns true if the type represented by the conversion is now the atomic - * string type. We have to have this crazy method for representing atomic - * string, because there's no such type in C (and hence no corresponding - * CPPType *). - */ -bool ParameterRemap:: -new_type_is_atomic_string() { - return false; -} - -/** - * Returns true if this is the "this" parameter. - */ -bool ParameterRemap:: -is_this() { - return false; -} diff --git a/dtool/src/interrogate/parameterRemap.h b/dtool/src/interrogate/parameterRemap.h deleted file mode 100644 index 9ae351e29c3..00000000000 --- a/dtool/src/interrogate/parameterRemap.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemap.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef PARAMETERREMAP_H -#define PARAMETERREMAP_H - -#include "dtoolbase.h" - -#include "interrogate_interface.h" - -class CPPType; -class CPPExpression; - -/** - * An abstract base class for a number of different kinds of ways to remap - * parameters for passing to wrapper functions. - * - * Certain kinds of function parameters that are legal in C++ (for instance, - * passing by reference, or passing structures as concrete values) are not - * legal for a typical scripting language. We map these types of parameters - * to something equivalent (for instance, a reference becomes a pointer). - * - * For each kind of possible remapping, we define a class derived from - * ParameterRemap that defines the exact nature of the remap. - */ -class ParameterRemap { -public: - INLINE ParameterRemap(CPPType *orig_type); - virtual ~ParameterRemap(); - - INLINE bool is_valid() const; - - INLINE CPPType *get_orig_type() const; - INLINE CPPType *get_new_type() const; - INLINE CPPType *get_temporary_type() const; - INLINE bool has_default_value() const; - INLINE CPPExpression *get_default_value() const; - INLINE void set_default_value(CPPExpression *expr); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string prepare_return_expr(std::ostream &out, int indent_level, - const std::string &expression); - virtual std::string get_return_expr(const std::string &expression); - virtual std::string temporary_to_return(const std::string &temporary); - virtual bool return_value_needs_management(); - virtual FunctionIndex get_return_value_destructor(); - virtual bool return_value_should_be_simple(); - virtual bool new_type_is_atomic_string(); - virtual bool is_this(); - -protected: - bool _is_valid; - - CPPType *_orig_type; - CPPType *_new_type; - CPPType *_temporary_type; - CPPExpression *_default_value; -}; - -#include "parameterRemap.I" - -#endif diff --git a/dtool/src/interrogate/parameterRemapBasicStringPtrToString.cxx b/dtool/src/interrogate/parameterRemapBasicStringPtrToString.cxx deleted file mode 100644 index 07dad4694a0..00000000000 --- a/dtool/src/interrogate/parameterRemapBasicStringPtrToString.cxx +++ /dev/null @@ -1,83 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapBasicStringPtrToString.cxx - * @author drose - * @date 2009-08-11 - */ - -#include "parameterRemapBasicStringPtrToString.h" -#include "interrogate.h" - -using std::string; - -/** - * - */ -ParameterRemapBasicStringPtrToString:: -ParameterRemapBasicStringPtrToString(CPPType *orig_type) : - ParameterRemapToString(orig_type) -{ - static CPPType *const_char_star_type = nullptr; - if (const_char_star_type == nullptr) { - const_char_star_type = parser.parse_type("const char *"); - } - - _new_type = const_char_star_type; -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapBasicStringPtrToString:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << "&std::string(" << variable_name << ")"; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapBasicStringPtrToString:: -get_return_expr(const string &expression) { - return "(" + expression + ")->c_str()"; -} - -/** - * - */ -ParameterRemapBasicWStringPtrToWString:: -ParameterRemapBasicWStringPtrToWString(CPPType *orig_type) : - ParameterRemapToWString(orig_type) -{ - static CPPType *const_wchar_star_type = nullptr; - if (const_wchar_star_type == nullptr) { - const_wchar_star_type = parser.parse_type("const wchar_t *"); - } - - _new_type = const_wchar_star_type; -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapBasicWStringPtrToWString:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << "&std::wstring(" << variable_name << ")"; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapBasicWStringPtrToWString:: -get_return_expr(const string &expression) { - return "(" + expression + ")->c_str()"; -} diff --git a/dtool/src/interrogate/parameterRemapBasicStringPtrToString.h b/dtool/src/interrogate/parameterRemapBasicStringPtrToString.h deleted file mode 100644 index c0c385af5e2..00000000000 --- a/dtool/src/interrogate/parameterRemapBasicStringPtrToString.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapBasicStringPtrToString.h - * @author drose - * @date 2009-08-11 - */ - -#ifndef PARAMETERREMAPBASICSTRINGPTRTOSTRING_H -#define PARAMETERREMAPBASICSTRINGPTRTOSTRING_H - -#include "dtoolbase.h" - -#include "parameterRemapToString.h" - -/** - * Maps a const pointer to a basic_string to an atomic string. - */ -class ParameterRemapBasicStringPtrToString : public ParameterRemapToString { -public: - ParameterRemapBasicStringPtrToString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -/** - * Maps a const pointer to a basic_string to an atomic string. - */ -class ParameterRemapBasicWStringPtrToWString : public ParameterRemapToWString { -public: - ParameterRemapBasicWStringPtrToWString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapBasicStringRefToString.cxx b/dtool/src/interrogate/parameterRemapBasicStringRefToString.cxx deleted file mode 100644 index 90cd3d7e459..00000000000 --- a/dtool/src/interrogate/parameterRemapBasicStringRefToString.cxx +++ /dev/null @@ -1,83 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapBasicStringRefToString.cxx - * @author drose - * @date 2000-08-09 - */ - -#include "parameterRemapBasicStringRefToString.h" -#include "interrogate.h" - -using std::string; - -/** - * - */ -ParameterRemapBasicStringRefToString:: -ParameterRemapBasicStringRefToString(CPPType *orig_type) : - ParameterRemapToString(orig_type) -{ - static CPPType *const_char_star_type = nullptr; - if (const_char_star_type == nullptr) { - const_char_star_type = parser.parse_type("const char *"); - } - - _new_type = const_char_star_type; -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapBasicStringRefToString:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << "std::string(" << variable_name << ")"; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapBasicStringRefToString:: -get_return_expr(const string &expression) { - return "(" + expression + ").c_str()"; -} - -/** - * - */ -ParameterRemapBasicWStringRefToWString:: -ParameterRemapBasicWStringRefToWString(CPPType *orig_type) : - ParameterRemapToWString(orig_type) -{ - static CPPType *const_wchar_star_type = nullptr; - if (const_wchar_star_type == nullptr) { - const_wchar_star_type = parser.parse_type("const wchar_t *"); - } - - _new_type = const_wchar_star_type; -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapBasicWStringRefToWString:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << "std::wstring(" << variable_name << ")"; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapBasicWStringRefToWString:: -get_return_expr(const string &expression) { - return "(" + expression + ").c_str()"; -} diff --git a/dtool/src/interrogate/parameterRemapBasicStringRefToString.h b/dtool/src/interrogate/parameterRemapBasicStringRefToString.h deleted file mode 100644 index 546e5aad978..00000000000 --- a/dtool/src/interrogate/parameterRemapBasicStringRefToString.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapBasicStringRefToString.h - * @author drose - * @date 2000-08-09 - */ - -#ifndef PARAMETERREMAPBASICSTRINGREFTOSTRING_H -#define PARAMETERREMAPBASICSTRINGREFTOSTRING_H - -#include "dtoolbase.h" - -#include "parameterRemapToString.h" - -/** - * Maps a const reference to a basic_string to an atomic string. - */ -class ParameterRemapBasicStringRefToString : public ParameterRemapToString { -public: - ParameterRemapBasicStringRefToString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -/** - * Maps a const reference to a basic_string to an atomic string. - */ -class ParameterRemapBasicWStringRefToWString : public ParameterRemapToWString { -public: - ParameterRemapBasicWStringRefToWString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapBasicStringToString.cxx b/dtool/src/interrogate/parameterRemapBasicStringToString.cxx deleted file mode 100644 index 46ce08c9c79..00000000000 --- a/dtool/src/interrogate/parameterRemapBasicStringToString.cxx +++ /dev/null @@ -1,111 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapBasicStringToString.cxx - * @author drose - * @date 2000-08-09 - */ - -#include "parameterRemapBasicStringToString.h" -#include "interfaceMaker.h" -#include "interrogate.h" - -using std::ostream; -using std::string; - -/** - * - */ -ParameterRemapBasicStringToString:: -ParameterRemapBasicStringToString(CPPType *orig_type) : - ParameterRemapToString(orig_type) -{ - static CPPType *const_char_star_type = nullptr; - if (const_char_star_type == nullptr) { - const_char_star_type = parser.parse_type("const char *"); - } - - _new_type = const_char_star_type; -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapBasicStringToString:: -pass_parameter(ostream &out, const string &variable_name) { - out << "std::string(" << variable_name << ")"; -} - -/** - * This will be called immediately before get_return_expr(). It outputs - * whatever lines the remapper needs to the function to set up its return - * value, e.g. to declare a temporary variable or something. It should - * return the modified expression. - */ -string ParameterRemapBasicStringToString:: -prepare_return_expr(ostream &out, int indent_level, const string &expression) { - InterfaceMaker::indent(out, indent_level) - << "static std::string string_holder = " << expression << ";\n"; - return "string_holder"; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapBasicStringToString:: -get_return_expr(const string &expression) { - return "string_holder.c_str()"; -} - -/** - * - */ -ParameterRemapBasicWStringToWString:: -ParameterRemapBasicWStringToWString(CPPType *orig_type) : - ParameterRemapToWString(orig_type) -{ - static CPPType *const_wchar_star_type = nullptr; - if (const_wchar_star_type == nullptr) { - const_wchar_star_type = parser.parse_type("const wchar_t *"); - } - - _new_type = const_wchar_star_type; -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapBasicWStringToWString:: -pass_parameter(ostream &out, const string &variable_name) { - out << "std::wstring(" << variable_name << ")"; -} - -/** - * This will be called immediately before get_return_expr(). It outputs - * whatever lines the remapper needs to the function to set up its return - * value, e.g. to declare a temporary variable or something. It should - * return the modified expression. - */ -string ParameterRemapBasicWStringToWString:: -prepare_return_expr(ostream &out, int indent_level, const string &expression) { - InterfaceMaker::indent(out, indent_level) - << "static std::wstring string_holder = " << expression << ";\n"; - return "string_holder"; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapBasicWStringToWString:: -get_return_expr(const string &expression) { - return "string_holder.c_str()"; -} diff --git a/dtool/src/interrogate/parameterRemapBasicStringToString.h b/dtool/src/interrogate/parameterRemapBasicStringToString.h deleted file mode 100644 index d27da237964..00000000000 --- a/dtool/src/interrogate/parameterRemapBasicStringToString.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapBasicStringToString.h - * @author drose - * @date 2000-08-09 - */ - -#ifndef PARAMETERREMAPBASICSTRINGTOSTRING_H -#define PARAMETERREMAPBASICSTRINGTOSTRING_H - -#include "dtoolbase.h" - -#include "parameterRemapToString.h" - -/** - * Maps a concrete basic_string to an atomic string. - */ -class ParameterRemapBasicStringToString : public ParameterRemapToString { -public: - ParameterRemapBasicStringToString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string prepare_return_expr(std::ostream &out, int indent_level, - const std::string &expression); - virtual std::string get_return_expr(const std::string &expression); -}; - -/** - * Maps a concrete basic_string to an atomic string. - */ -class ParameterRemapBasicWStringToWString : public ParameterRemapToWString { -public: - ParameterRemapBasicWStringToWString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string prepare_return_expr(std::ostream &out, int indent_level, - const std::string &expression); - virtual std::string get_return_expr(const std::string &expression); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapCharStarToString.cxx b/dtool/src/interrogate/parameterRemapCharStarToString.cxx deleted file mode 100644 index e791fe9c619..00000000000 --- a/dtool/src/interrogate/parameterRemapCharStarToString.cxx +++ /dev/null @@ -1,32 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapCharStarToString.cxx - * @author drose - * @date 2000-08-09 - */ - -#include "parameterRemapCharStarToString.h" - -/** - * - */ -ParameterRemapCharStarToString:: -ParameterRemapCharStarToString(CPPType *orig_type) : - ParameterRemapToString(orig_type) -{ -} - -/** - * - */ -ParameterRemapWCharStarToWString:: -ParameterRemapWCharStarToWString(CPPType *orig_type) : - ParameterRemapToWString(orig_type) -{ -} diff --git a/dtool/src/interrogate/parameterRemapCharStarToString.h b/dtool/src/interrogate/parameterRemapCharStarToString.h deleted file mode 100644 index 8d1d891681c..00000000000 --- a/dtool/src/interrogate/parameterRemapCharStarToString.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapCharStarToString.h - * @author drose - * @date 2000-08-09 - */ - -#ifndef PARAMETERREMAPCHARSTARTOSTRING_H -#define PARAMETERREMAPCHARSTARTOSTRING_H - -#include "dtoolbase.h" - -#include "parameterRemapToString.h" - -/** - * Maps from (char *) or (const char *) to the atomic string type. - */ -class ParameterRemapCharStarToString : public ParameterRemapToString { -public: - ParameterRemapCharStarToString(CPPType *orig_type); -}; - -/** - * Maps from (wchar_t *) or (const wchar_ *) to the atomic wide-string type. - */ -class ParameterRemapWCharStarToWString : public ParameterRemapToWString { -public: - ParameterRemapWCharStarToWString(CPPType *orig_type); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapConcreteToPointer.cxx b/dtool/src/interrogate/parameterRemapConcreteToPointer.cxx deleted file mode 100644 index 9f217076cb7..00000000000 --- a/dtool/src/interrogate/parameterRemapConcreteToPointer.cxx +++ /dev/null @@ -1,91 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapConcreteToPointer.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "parameterRemapConcreteToPointer.h" -#include "interrogate.h" -#include "interrogateBuilder.h" -#include "typeManager.h" - -#include "cppType.h" -#include "cppDeclaration.h" -#include "cppConstType.h" -#include "cppPointerType.h" - -/** - * - */ -ParameterRemapConcreteToPointer:: -ParameterRemapConcreteToPointer(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - _new_type = TypeManager::wrap_pointer(orig_type); -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapConcreteToPointer:: -pass_parameter(std::ostream &out, const std::string &variable_name) { - if (variable_name.size() > 1 && variable_name[0] == '&') { - // Prevent generating something like *¶m Also, if this is really some - // local type, we can presumably just move it? - out << "std::move(" << variable_name.substr(1) << ")"; - } else { - out << "*" << variable_name; - } -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -std::string ParameterRemapConcreteToPointer:: -get_return_expr(const std::string &expression) { - return - "new " + _orig_type->get_local_name(&parser) + - "(" + expression + ")"; -} - -/** - * Returns true if the return value represents a value that was newly - * allocated, and hence must be explicitly deallocated later by the caller. - */ -bool ParameterRemapConcreteToPointer:: -return_value_needs_management() { - return true; -} - -/** - * If return_value_needs_management() returns true, this should return the - * index of the function that should be called when it is time to destruct the - * return value. It will generally be the same as the destructor for the - * class we just returned a pointer to. - */ -FunctionIndex ParameterRemapConcreteToPointer:: -get_return_value_destructor() { - return builder.get_destructor_for(_orig_type); -} - -/** - * This is a hack around a problem VC++ has with overly-complex expressions, - * particularly in conjunction with the 'new' operator. If this parameter - * type is one that will probably give VC++ a headache, this should be set - * true to indicate that the code generator should save the return value - * expression into a temporary variable first, and pass the temporary variable - * name in instead. - */ -bool ParameterRemapConcreteToPointer:: -return_value_should_be_simple() { - return true; -} diff --git a/dtool/src/interrogate/parameterRemapConcreteToPointer.h b/dtool/src/interrogate/parameterRemapConcreteToPointer.h deleted file mode 100644 index 2e69597712e..00000000000 --- a/dtool/src/interrogate/parameterRemapConcreteToPointer.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapConcreteToPointer.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef PARAMETERREMAPCONCRETETOPOINTER_H -#define PARAMETERREMAPCONCRETETOPOINTER_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A ParameterRemap class that handles remapping a concrete structure or class - * parameter to a pointer parameter. - */ -class ParameterRemapConcreteToPointer : public ParameterRemap { -public: - ParameterRemapConcreteToPointer(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); - virtual bool return_value_needs_management(); - virtual FunctionIndex get_return_value_destructor(); - virtual bool return_value_should_be_simple(); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapConstToNonConst.cxx b/dtool/src/interrogate/parameterRemapConstToNonConst.cxx deleted file mode 100644 index 2fb23e90bc2..00000000000 --- a/dtool/src/interrogate/parameterRemapConstToNonConst.cxx +++ /dev/null @@ -1,45 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapConstToNonConst.cxx - * @author drose - * @date 2000-08-04 - */ - -#include "parameterRemapConstToNonConst.h" -#include "typeManager.h" - -#include "cppConstType.h" - -/** - * - */ -ParameterRemapConstToNonConst:: -ParameterRemapConstToNonConst(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - _new_type = TypeManager::unwrap_const(orig_type); -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapConstToNonConst:: -pass_parameter(std::ostream &out, const std::string &variable_name) { - out << variable_name; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -std::string ParameterRemapConstToNonConst:: -get_return_expr(const std::string &expression) { - return expression; -} diff --git a/dtool/src/interrogate/parameterRemapConstToNonConst.h b/dtool/src/interrogate/parameterRemapConstToNonConst.h deleted file mode 100644 index ee376764e17..00000000000 --- a/dtool/src/interrogate/parameterRemapConstToNonConst.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapConstToNonConst.h - * @author drose - * @date 2000-08-04 - */ - -#ifndef PARAMETERREMAPCONSTTONONCONST_H -#define PARAMETERREMAPCONSTTONONCONST_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A ParameterRemap class that handles remapping a simple const parameter - * (like const int) to an ordinary parameter (like int). It doesn't apply to - * const references or const pointers, however. - */ -class ParameterRemapConstToNonConst : public ParameterRemap { -public: - ParameterRemapConstToNonConst(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapEnumToInt.cxx b/dtool/src/interrogate/parameterRemapEnumToInt.cxx deleted file mode 100644 index 59fb6019fc3..00000000000 --- a/dtool/src/interrogate/parameterRemapEnumToInt.cxx +++ /dev/null @@ -1,70 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapEnumToInt.cxx - * @author drose - * @date 2000-08-04 - */ - -#include "parameterRemapEnumToInt.h" -#include "interrogate.h" - -#include "cppSimpleType.h" -#include "cppConstType.h" -#include "cppPointerType.h" -#include "cppReferenceType.h" - -/** - * - */ -ParameterRemapEnumToInt:: -ParameterRemapEnumToInt(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - _new_type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int)); - _enum_type = unwrap_type(_orig_type); -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapEnumToInt:: -pass_parameter(std::ostream &out, const std::string &variable_name) { - out << "(" << _enum_type->get_local_name(&parser) << ")" << variable_name; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -std::string ParameterRemapEnumToInt:: -get_return_expr(const std::string &expression) { - return "(int)(" + expression + ")"; -} - -/** - * Recursively walks through the type definition, and finds the enum - * definition under all the wrappers. - */ -CPPType *ParameterRemapEnumToInt:: -unwrap_type(CPPType *source_type) const { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return unwrap_type(source_type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return unwrap_type(source_type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_pointer: - return unwrap_type(source_type->as_pointer_type()->_pointing_at); - - default: - return source_type; - } -} diff --git a/dtool/src/interrogate/parameterRemapEnumToInt.h b/dtool/src/interrogate/parameterRemapEnumToInt.h deleted file mode 100644 index a74951bcaa0..00000000000 --- a/dtool/src/interrogate/parameterRemapEnumToInt.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapEnumToInt.h - * @author drose - * @date 2000-08-04 - */ - -#ifndef PARAMETERREMAPENUMTOINT_H -#define PARAMETERREMAPENUMTOINT_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A ParameterRemap class that handles remapping an enumerated type to an - * integer parameter. - */ -class ParameterRemapEnumToInt : public ParameterRemap { -public: - ParameterRemapEnumToInt(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); - -private: - CPPType *_enum_type; - - CPPType *unwrap_type(CPPType *source_type) const; -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapHandleToInt.cxx b/dtool/src/interrogate/parameterRemapHandleToInt.cxx deleted file mode 100644 index 4594ca45c8a..00000000000 --- a/dtool/src/interrogate/parameterRemapHandleToInt.cxx +++ /dev/null @@ -1,56 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapHandleToInt.cxx - * @author rdb - * @date 2015-09-08 - */ - -#include "parameterRemapHandleToInt.h" -#include "interrogate.h" -#include "interrogateBuilder.h" -#include "typeManager.h" - -#include "cppType.h" -#include "cppDeclaration.h" -#include "cppConstType.h" -#include "cppPointerType.h" - -/** - * - */ -ParameterRemapHandleToInt:: -ParameterRemapHandleToInt(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - _new_type = TypeManager::get_int_type(); -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapHandleToInt:: -pass_parameter(std::ostream &out, const std::string &variable_name) { - CPPType *unwrapped = TypeManager::unwrap_const(_orig_type); - - if (unwrapped->get_local_name(&parser) == "TypeHandle") { - out << "TypeHandle::from_index(" << variable_name << ")"; - } else { - out << unwrapped->get_local_name(&parser) << "(" << variable_name << ")"; - } -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -std::string ParameterRemapHandleToInt:: -get_return_expr(const std::string &expression) { - return "(" + expression + ").get_index()"; -} diff --git a/dtool/src/interrogate/parameterRemapHandleToInt.h b/dtool/src/interrogate/parameterRemapHandleToInt.h deleted file mode 100644 index 32c2016300d..00000000000 --- a/dtool/src/interrogate/parameterRemapHandleToInt.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapHandleToInt.h - * @author rdb - * @date 2015-09-08 - */ - -#ifndef PARAMETERREMAPHANDLETOINT_H -#define PARAMETERREMAPHANDLETOINT_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A ParameterRemap class that handles remapping a Handle parameter to an - * integer. This makes it easier to set up a dynamic typing system on the - * scripting language side. - * - * It also applies to ButtonHandle or any other class with the same semantics, - * because why not. - */ -class ParameterRemapHandleToInt : public ParameterRemap { -public: - ParameterRemapHandleToInt(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapPTToPointer.cxx b/dtool/src/interrogate/parameterRemapPTToPointer.cxx deleted file mode 100644 index 243b9072601..00000000000 --- a/dtool/src/interrogate/parameterRemapPTToPointer.cxx +++ /dev/null @@ -1,92 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapPTToPointer.cxx - * @author drose - * @date 2000-08-10 - */ - -#include "parameterRemapPTToPointer.h" -#include "interrogate.h" -#include "interrogateBuilder.h" -#include "typeManager.h" - -#include "cppType.h" -#include "cppStructType.h" -#include "cppDeclaration.h" -#include "pnotify.h" - -using std::string; - -/** - * - */ -ParameterRemapPTToPointer:: -ParameterRemapPTToPointer(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - CPPStructType *pt_type = TypeManager::unwrap(_orig_type)->as_struct_type(); - assert(pt_type != nullptr); - - // A horrible hack around a CPPParser bug. We don't trust the CPPStructType - // pointer we were given; instead, we ask CPPParser to parse a new type of - // the same name. This has a better chance of fully resolving templates. - string name = pt_type->get_local_name(&parser); - CPPType *new_type = parser.parse_type(name); - if (new_type == nullptr) { - nout << "Type " << name << " is unknown to parser.\n"; - } else { - new_type = new_type->resolve_type(&parser, &parser); - pt_type = new_type->as_struct_type(); - assert(pt_type != nullptr); - } - - _pointer_type = TypeManager::get_pointer_type(pt_type); - if (_pointer_type == nullptr) { - // If we couldn't figure out the pointer type, forget it. - nout << "Couldn't figure out pointer type for " << *pt_type << "\n"; - _is_valid = false; - return; - } - - _new_type = _pointer_type; - - // We must use an actual PointerTo to hold any temporary values, until we - // can safely ref it. - _temporary_type = pt_type; -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapPTToPointer:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << variable_name; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapPTToPointer:: -get_return_expr(const string &expression) { - return expression; -} - -/** - * Returns the string that converts the expression stored in the indicated - * temporary variable to the appropriate return value type. This is normally - * a pass-through, but in cases when the temporary variable type must be - * different than the return type (i.e. get_temporary_type() != - * get_new_type()), this might perform some operation. - */ -string ParameterRemapPTToPointer:: -temporary_to_return(const string &temporary) { - return temporary + ".p()"; -} diff --git a/dtool/src/interrogate/parameterRemapPTToPointer.h b/dtool/src/interrogate/parameterRemapPTToPointer.h deleted file mode 100644 index 5c59f075b9d..00000000000 --- a/dtool/src/interrogate/parameterRemapPTToPointer.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapPTToPointer.h - * @author drose - * @date 2000-08-10 - */ - -#ifndef PARAMETERREMAPPTTOPOINTER_H -#define PARAMETERREMAPPTTOPOINTER_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -class CPPType; -class CPPStructType; - -/** - * A ParameterRemap class that handles remapping a PT(Type) or PointerTo - * to a Type *. - */ -class ParameterRemapPTToPointer : public ParameterRemap { -public: - ParameterRemapPTToPointer(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); - virtual std::string temporary_to_return(const std::string &temporary); - -private: - CPPType *_pointer_type; -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapReferenceToConcrete.cxx b/dtool/src/interrogate/parameterRemapReferenceToConcrete.cxx deleted file mode 100644 index bdb613cef66..00000000000 --- a/dtool/src/interrogate/parameterRemapReferenceToConcrete.cxx +++ /dev/null @@ -1,49 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapReferenceToConcrete.cxx - * @author drose - * @date 2000-08-04 - */ - -#include "parameterRemapReferenceToConcrete.h" -#include "typeManager.h" - -#include "cppType.h" -#include "cppDeclaration.h" -#include "cppConstType.h" -#include "cppPointerType.h" -#include "cppReferenceType.h" - -/** - * - */ -ParameterRemapReferenceToConcrete:: -ParameterRemapReferenceToConcrete(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - _new_type = TypeManager::unwrap_const_reference(orig_type); -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapReferenceToConcrete:: -pass_parameter(std::ostream &out, const std::string &variable_name) { - out << variable_name; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -std::string ParameterRemapReferenceToConcrete:: -get_return_expr(const std::string &expression) { - return expression; -} diff --git a/dtool/src/interrogate/parameterRemapReferenceToConcrete.h b/dtool/src/interrogate/parameterRemapReferenceToConcrete.h deleted file mode 100644 index 12c7ef27bd7..00000000000 --- a/dtool/src/interrogate/parameterRemapReferenceToConcrete.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapReferenceToConcrete.h - * @author drose - * @date 2000-08-04 - */ - -#ifndef PARAMETERREMAPREFERENCETOCONCRETE_H -#define PARAMETERREMAPREFERENCETOCONCRETE_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A ParameterRemap class that handles remapping a const reference parameter - * to a concrete. This only makes sense when we're talking about a const - * reference to a simple type. - */ -class ParameterRemapReferenceToConcrete : public ParameterRemap { -public: - ParameterRemapReferenceToConcrete(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapReferenceToPointer.cxx b/dtool/src/interrogate/parameterRemapReferenceToPointer.cxx deleted file mode 100644 index 4e8d1fad90c..00000000000 --- a/dtool/src/interrogate/parameterRemapReferenceToPointer.cxx +++ /dev/null @@ -1,58 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapReferenceToPointer.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "parameterRemapReferenceToPointer.h" -#include "typeManager.h" - -#include "cppType.h" -#include "cppDeclaration.h" -#include "cppConstType.h" -#include "cppPointerType.h" -#include "cppReferenceType.h" - -/** - * - */ -ParameterRemapReferenceToPointer:: -ParameterRemapReferenceToPointer(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - _new_type = TypeManager::wrap_pointer(TypeManager::unwrap_reference(orig_type)); -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapReferenceToPointer:: -pass_parameter(std::ostream &out, const std::string &variable_name) { - if (variable_name.size() > 1 && variable_name[0] == '&') { - // Prevent generating something like *¶m Also, if this is really some - // local type, we can presumably just move it? This is only relevant if - // this parameter is an rvalue reference, but CPPParser can't know that, - // and it might have an overload that takes an rvalue reference. It - // shouldn't hurt either way. - out << "std::move(" << variable_name.substr(1) << ")"; - } else { - out << "*" << variable_name; - } -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -std::string ParameterRemapReferenceToPointer:: -get_return_expr(const std::string &expression) { - return "&(" + expression + ")"; -} diff --git a/dtool/src/interrogate/parameterRemapReferenceToPointer.h b/dtool/src/interrogate/parameterRemapReferenceToPointer.h deleted file mode 100644 index 6ee71d86c56..00000000000 --- a/dtool/src/interrogate/parameterRemapReferenceToPointer.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapReferenceToPointer.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef PARAMETERREMAPREFERENCETOPOINTER_H -#define PARAMETERREMAPREFERENCETOPOINTER_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A ParameterRemap class that handles remapping a reference (or a const - * reference) parameter to a pointer (or const pointer) parameter. - */ -class ParameterRemapReferenceToPointer : public ParameterRemap { -public: - ParameterRemapReferenceToPointer(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapThis.cxx b/dtool/src/interrogate/parameterRemapThis.cxx deleted file mode 100644 index 7fd8be4243a..00000000000 --- a/dtool/src/interrogate/parameterRemapThis.cxx +++ /dev/null @@ -1,61 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapThis.cxx - * @author drose - * @date 2000-08-02 - */ - -#include "parameterRemapThis.h" -#include "typeManager.h" - -#include "cppType.h" -#include "cppSimpleType.h" -#include "cppPointerType.h" -#include "cppConstType.h" - -/** - * - */ -ParameterRemapThis:: -ParameterRemapThis(CPPType *type, bool is_const) : - ParameterRemap(TypeManager::get_void_type()) -{ - if (is_const) { - _new_type = TypeManager::wrap_const_pointer(type); - } else { - _new_type = TypeManager::wrap_pointer(type); - } - _orig_type = _new_type; -} - -/** - * Outputs an expression that converts the indicated variable from the new - * type to the original type, for passing into the actual C++ function. - */ -void ParameterRemapThis:: -pass_parameter(std::ostream &out, const std::string &variable_name) { - out << "(*" << variable_name << ")"; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -std::string ParameterRemapThis:: -get_return_expr(const std::string &) { - return "**invalid**"; -} - -/** - * Returns true if this is the "this" parameter. - */ -bool ParameterRemapThis:: -is_this() { - return true; -} diff --git a/dtool/src/interrogate/parameterRemapThis.h b/dtool/src/interrogate/parameterRemapThis.h deleted file mode 100644 index 3d13b66717e..00000000000 --- a/dtool/src/interrogate/parameterRemapThis.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapThis.h - * @author drose - * @date 2000-08-02 - */ - -#ifndef PARAMETERREMAPTHIS_H -#define PARAMETERREMAPTHIS_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -class CPPType; - -/** - * A ParameterRemap class that represents a generated "this" parameter. - */ -class ParameterRemapThis : public ParameterRemap { -public: - ParameterRemapThis(CPPType *type, bool is_const); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); - virtual bool is_this(); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapToString.cxx b/dtool/src/interrogate/parameterRemapToString.cxx deleted file mode 100644 index 9771a2db1b0..00000000000 --- a/dtool/src/interrogate/parameterRemapToString.cxx +++ /dev/null @@ -1,115 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapToString.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "parameterRemapToString.h" -#include "interrogate.h" -#include "typeManager.h" - -using std::string; - -/** - * - */ -ParameterRemapToString:: -ParameterRemapToString(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - static CPPType *char_star_type = nullptr; - if (char_star_type == nullptr) { - char_star_type = parser.parse_type("char *"); - } - - static CPPType *const_char_star_type = nullptr; - if (const_char_star_type == nullptr) { - const_char_star_type = parser.parse_type("const char *"); - } - - if (TypeManager::is_const_char_pointer(orig_type) || TypeManager::is_string(orig_type)) { - _new_type = const_char_star_type; - } else { - _new_type = char_star_type; - } -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapToString:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << variable_name; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapToString:: -get_return_expr(const string &expression) { - return expression; -} - -/** - * Returns true if the type represented by the conversion is now the atomic - * string type. We have to have this crazy method for representing atomic - * string, because there's no such type in C (and hence no corresponding - * CPPType *). - */ -bool ParameterRemapToString:: -new_type_is_atomic_string() { - return true; -} - -/** - * - */ -ParameterRemapToWString:: -ParameterRemapToWString(CPPType *orig_type) : - ParameterRemap(orig_type) -{ - static CPPType *char_star_type = nullptr; - if (char_star_type == nullptr) { - char_star_type = parser.parse_type("const wchar_t *"); - } - - _new_type = char_star_type; -} - -/** - * Outputs an expression that converts the indicated variable from the - * original type to the new type, for passing into the actual C++ function. - */ -void ParameterRemapToWString:: -pass_parameter(std::ostream &out, const string &variable_name) { - out << variable_name; -} - -/** - * Returns an expression that evalutes to the appropriate value type for - * returning from the function, given an expression of the original type. - */ -string ParameterRemapToWString:: -get_return_expr(const string &expression) { - return expression; -} - -/** - * Returns true if the type represented by the conversion is now the atomic - * string type. We have to have this crazy method for representing atomic - * string, because there's no such type in C (and hence no corresponding - * CPPType *). - */ -bool ParameterRemapToWString:: -new_type_is_atomic_string() { - return true; -} diff --git a/dtool/src/interrogate/parameterRemapToString.h b/dtool/src/interrogate/parameterRemapToString.h deleted file mode 100644 index 5eed97d7319..00000000000 --- a/dtool/src/interrogate/parameterRemapToString.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapToString.h - * @author drose - * @date 2000-08-09 - */ - -#ifndef PARAMETERREMAPTOSTRING_H -#define PARAMETERREMAPTOSTRING_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A base class for several different remapping types that convert to an - * atomic string class. - * - * The atomic string class is represented in the C interface as a (const char - * *). Other interfaces may be able to represent it differently, subverting - * the code defined here. - */ -class ParameterRemapToString : public ParameterRemap { -public: - ParameterRemapToString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); - - virtual bool new_type_is_atomic_string(); -}; - -/** - * A base class for several different remapping types that convert to an - * atomic string class. - * - * The atomic string class is represented in the C interface as a (const - * wchar_t *). Other interfaces may be able to represent it differently, - * subverting the code defined here. - */ -class ParameterRemapToWString : public ParameterRemap { -public: - ParameterRemapToWString(CPPType *orig_type); - - virtual void pass_parameter(std::ostream &out, const std::string &variable_name); - virtual std::string get_return_expr(const std::string &expression); - - virtual bool new_type_is_atomic_string(); -}; - -#endif diff --git a/dtool/src/interrogate/parameterRemapUnchanged.cxx b/dtool/src/interrogate/parameterRemapUnchanged.cxx deleted file mode 100644 index a39314166f3..00000000000 --- a/dtool/src/interrogate/parameterRemapUnchanged.cxx +++ /dev/null @@ -1,23 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapUnchanged.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "parameterRemapUnchanged.h" - -/** - * - */ -ParameterRemapUnchanged:: -ParameterRemapUnchanged(CPPType *orig_type) : - ParameterRemap(orig_type) -{ -} diff --git a/dtool/src/interrogate/parameterRemapUnchanged.h b/dtool/src/interrogate/parameterRemapUnchanged.h deleted file mode 100644 index 127fd908d8f..00000000000 --- a/dtool/src/interrogate/parameterRemapUnchanged.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parameterRemapUnchanged.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef PARAMETERREMAPUNCHANGED_H -#define PARAMETERREMAPUNCHANGED_H - -#include "dtoolbase.h" - -#include "parameterRemap.h" - -/** - * A ParameterRemap class that represents no change to the parameter: the - * parameter type is legal as is. - */ -class ParameterRemapUnchanged : public ParameterRemap { -public: - ParameterRemapUnchanged(CPPType *orig_type); -}; - -#endif diff --git a/dtool/src/interrogate/parse_file.cxx b/dtool/src/interrogate/parse_file.cxx deleted file mode 100644 index 0c92918c53a..00000000000 --- a/dtool/src/interrogate/parse_file.cxx +++ /dev/null @@ -1,379 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file parse_file.cxx - * @author drose - * @date 1999-10-20 - */ - -#include "cppParser.h" -#include "cppManifest.h" -#include "cppStructType.h" -#include "cppFunctionGroup.h" -#include "cppTypedefType.h" -#include "cppExpressionParser.h" -#include "cppExpression.h" -#include "cppType.h" -#include "cppGlobals.h" -#include "panda_getopt_long.h" -#include "preprocess_argv.h" -#include - -using std::cerr; -using std::cin; -using std::cout; -using std::string; - -CPPParser parser; - -void -predefine_macro(CPPParser &parser, const string &option) { - string macro_name, macro_def; - - size_t eq = option.find('='); - if (eq != string::npos) { - macro_name = option.substr(0, eq); - macro_def = option.substr(eq + 1); - } else { - macro_name = option; - } - - cerr << "Predefining " << macro_name << " as " << macro_def << "\n"; - - CPPManifest *macro = new CPPManifest(parser, macro_name, macro_def); - parser._manifests[macro->_name] = macro; -} - -void -show_type_or_expression(const string &str) { - CPPExpression *expr = parser.parse_expr(str); - if (expr != nullptr) { - cout << "\nExpression: " << *expr << "\n"; - CPPType *type = expr->determine_type(); - if (type == nullptr) { - cout << "type is unknown\n"; - } else { - cout << "type is " << *type << "\n"; - } - cout << "value is " << expr->evaluate() << "\n\n"; - - } else { - CPPType *type = parser.parse_type(str); - if (type != nullptr) { - cout << "\nType: " << *type << "\n" - << "Defined in: " << type->_file << "\n" - << "Subtype code is: " << (int)type->get_subtype() << "\n\n"; - - CPPStructType *stype = type->as_struct_type(); - if (stype != nullptr) { - stype->check_virtual(); - } - - type->output(cout, 0, &parser, true); - cout << "\n\n" - << "is_template = " << type->is_template() << "\n" - << "is_fully_specified = " << type->is_fully_specified() << "\n" - << "is_tbd = " << type->is_tbd() << "\n" - << "is_fundamental = " << type->is_fundamental() << "\n" - << "is_standard_layout = " << type->is_standard_layout() << "\n" - << "is_trivial = " << type->is_trivial() << "\n" - << "is_trivially_copyable = " << type->is_trivially_copyable() << "\n" - << "is_default_constructible = " << type->is_default_constructible() << "\n" - << "is_copy_constructible = " << type->is_copy_constructible() << "\n" - << "is_copy_assignable = " << type->is_copy_assignable() << "\n" - << "is_destructible = " << type->is_destructible() << "\n"; - if (type->has_typedef_name()) { - cout << "get_typedef_name = " << type->get_typedef_name() << "\n"; - } - cout << "get_simple_name = " << type->get_simple_name() << "\n" - << "get_local_name = " << type->get_local_name() << "\n" - << "get_fully_scoped_name = " << type->get_fully_scoped_name() << "\n" - << "get_preferred_name = " << type->get_preferred_name() << "\n" - << "is_incomplete = " << type->is_incomplete() << "\n"; - - if (stype != nullptr) { - cout << "scope = " << stype->get_scope()->get_fully_scoped_name() << "\n"; - bool is_abstract = stype->is_abstract(); - cout << "is_abstract = " << is_abstract << "\n"; - if (is_abstract) { - cout << "pure virtual functions:\n"; - CPPStructType::VFunctions vf; - stype->get_pure_virtual_funcs(vf); - CPPStructType::VFunctions::const_iterator fi; - for (fi = vf.begin(); fi != vf.end(); ++fi) { - cout << " " << *(*fi) << "\n"; - } - } - } - - cout << "\n"; - } else { - cout << "Invalid expression or type.\n"; - } - } -} - -void -show_methods(const string &str) { - CPPType *type = parser.parse_type(str); - if (type == nullptr) { - cerr << "Invalid type: " << str << "\n"; - return; - } - - CPPStructType *stype = type->as_struct_type(); - if (stype == nullptr) { - cerr << "Type is not a structure or class.\n"; - return; - } - - CPPScope *scope = stype->get_scope(); - assert(scope != nullptr); - - cerr << "Methods in " << *stype << ":\n"; - - CPPScope::Functions::const_iterator fi; - for (fi = scope->_functions.begin(); fi != scope->_functions.end(); ++fi) { - CPPFunctionGroup *fgroup = (*fi).second; - - CPPFunctionGroup::Instances::const_iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *inst = (*ii); - cerr << " " << *inst << "\n"; - } - } -} - -void -show_data_members(const string &str) { - CPPType *type = parser.parse_type(str); - if (type == nullptr) { - cerr << "Invalid type: " << str << "\n"; - return; - } - - CPPStructType *stype = type->as_struct_type(); - if (stype == nullptr) { - cerr << "Type is not a structure or class.\n"; - return; - } - - CPPScope *scope = stype->get_scope(); - assert(scope != nullptr); - - cerr << "Data members in " << *stype << ":\n"; - - CPPScope::Variables::const_iterator vi; - for (vi = scope->_variables.begin(); vi != scope->_variables.end(); ++vi) { - CPPInstance *inst = (*vi).second; - cerr << " " << *inst << "\n"; - } -} - -void -show_nested_types(const string &str) { - CPPType *type = parser.parse_type(str); - if (type == nullptr) { - cerr << "Invalid type: " << str << "\n"; - return; - } - - CPPStructType *stype = type->as_struct_type(); - if (stype == nullptr) { - cerr << "Type is not a structure or class.\n"; - return; - } - - CPPScope *scope = stype->get_scope(); - assert(scope != nullptr); - - cerr << "Nested types in " << *stype << ":\n"; - - CPPScope::Types::const_iterator ti; - for (ti = scope->_types.begin(); ti != scope->_types.end(); ++ti) { - CPPType *tp = (*ti).second; - cerr << " " << *tp << "\n"; - } -} - - -int -main(int argc, char **argv) { - extern char *optarg; - extern int optind; - const char *optstr = "I:S:D:o:l:vpE"; - preprocess_argv(argc, argv); - - parser.set_verbose(2); - bool prompt = false; - bool preprocess = false; - - int flag = getopt(argc, argv, optstr); - - while (flag != EOF) { - switch (flag) { - case 'I': - parser._quote_include_path.append_directory(optarg); - parser._quote_include_kind.push_back(CPPFile::S_alternate); - break; - - case 'S': - parser._angle_include_path.append_directory(optarg); - parser._quote_include_path.append_directory(optarg); - parser._quote_include_kind.push_back(CPPFile::S_system); - break; - - case 'D': - predefine_macro(parser, optarg); - break; - - case 'o': - cerr << "Ignoring output file " << optarg << "\n"; - break; - - case 'l': - cpp_longlong_keyword = optarg; - break; - - case 'v': - parser.set_verbose(parser.get_verbose() + 1); - break; - - case 'p': - prompt = true; - break; - - case 'E': - preprocess = true; - break; - - default: - exit(1); - } - flag = getopt(argc, argv, optstr); - } - - argc -= (optind-1); - argv += (optind-1); - - - if (argc < 2) { - cerr << "parse-file [opts] file1.h [file2.h ... ]\n" - << "\nOptions:\n\n" - << " -I include_path\n" - << " -S system_include_path\n" - << " -D manifest_name\n" - << " -D manifest_name=manifest_definition\n" - << " -o output_file (ignored)\n" - << " -v (increase verbosity)\n" - << " -E (output preprocessed token stream)\n" - << " -p (prompt for expression instead of dumping output)\n"; - - exit(1); - } - - for (int i = 1; i < argc; i++) { - if (preprocess) { - if (!parser.preprocess_file(argv[i])) { - cerr << "Error in preprocessing.\n"; - exit(1); - } - } else { - if (!parser.parse_file(argv[i])) { - cerr << "Error in parsing.\n"; - exit(1); - } - } - } - - cerr << "Finished parsing.\n"; - - if (prompt) { - while (cin) { - string str; - cout << "Enter an expression or type name:\n"; - std::getline(std::cin, str); - if (!str.empty()) { - - size_t space = str.find(' '); - if (space != string::npos) { - string first_word = str.substr(0, space); - string remainder = str.substr(space + 1); - - if (first_word == "methods") { - show_methods(remainder); - } else if (first_word == "members") { - show_data_members(remainder); - } else if (first_word == "types") { - show_nested_types(remainder); - } else { - show_type_or_expression(str); - } - } else { - show_type_or_expression(str); - } - } - } - } else { - parser.write(cout, 0, &parser); - cout << "\n"; - } - - /* - cout << "Opened the following files:\n"; - CPPParser::ParsedFiles::const_iterator fi; - for (fi = parser._parsed_files.begin(); - fi != parser._parsed_files.end(); - ++fi) { - cout << " "; - - switch ((*fi)._source) { - case CPPFile::S_local: - cout << "L"; - break; - case CPPFile::S_alternate: - cout << "A"; - break; - case CPPFile::S_system: - cout << "S"; - break; - default: - cout << " "; - } - - cout << " " << (*fi) << "\n"; - } - */ - - /* - CPPParser::Comments::const_iterator ci; - for (ci = parser._comments.begin(); ci != parser._comments.end(); ++ci) { - const CPPParser::CommentBlock &c = (*ci); - cout << "Comment in file " << c._file << " at line " << c._line_number - << ":\n" << c._comment << "\n\n"; - } - */ - - /* - CPPParser::Manifests::const_iterator mi; - for (mi = parser._manifests.begin(); mi != parser._manifests.end(); ++mi) { - const CPPManifest *m = (*mi).second; - cout << "Manifest " << m->_name << " defined in " << m->_file; - CPPType *type = m->determine_type(); - if (type == (CPPType *)NULL) { - cout << " (no type)\n"; - } else { - cout << " has type " << *type << "\n"; - } - } - */ - - return (0); -} diff --git a/dtool/src/interrogate/typeManager.cxx b/dtool/src/interrogate/typeManager.cxx deleted file mode 100644 index dc5d6679de0..00000000000 --- a/dtool/src/interrogate/typeManager.cxx +++ /dev/null @@ -1,2614 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file typeManager.cxx - * @author drose - * @date 2000-08-14 - */ - -#include "typeManager.h" -#include "interrogate.h" - -#include "cppArrayType.h" -#include "cppConstType.h" -#include "cppEnumType.h" -#include "cppFunctionGroup.h" -#include "cppFunctionType.h" -#include "cppIdentifier.h" -#include "cppParameterList.h" -#include "cppPointerType.h" -#include "cppReferenceType.h" -#include "cppSimpleType.h" -#include "cppStructType.h" -#include "cppTemplateScope.h" -#include "cppTypeDeclaration.h" -#include "cppTypedefType.h" -#include "pnotify.h" - -using std::string; - -/** - * A horrible hack around a CPPParser bug. We don't trust the CPPType pointer - * we were given; instead, we ask CPPParser to parse a new type of the same - * name. This has a better chance of fully resolving templates. - */ -CPPType *TypeManager:: -resolve_type(CPPType *type, CPPScope *scope) { - if (scope == nullptr) { - scope = &parser; - } - - //CPPType *orig_type = type; - type = type->resolve_type(scope, &parser); - string name = type->get_local_name(&parser); - if (name.empty()) { - // Don't try to resolve unnamed types. - return type; - } - - // I think I fixed the bug; no need for the below hack any more. - return type; - -/* - CPPType *new_type = parser.parse_type(name); - if (new_type == (CPPType *)NULL) { - nout << "Type \"" << name << "\" (from " << *orig_type << ") is unknown to parser.\n"; - } else { - type = new_type->resolve_type(&parser, &parser); - } - - return type; -*/ -} - -/** - * Returns true if the indicated type is something we can legitimately assign - * a value to, or false otherwise. - */ -bool TypeManager:: -is_assignable(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - case CPPDeclaration::ST_reference: - case CPPDeclaration::ST_extension: - return false; - - case CPPDeclaration::ST_struct: - // In many cases, this is assignable, but there are some bizarre cases - // where it is not. Particularly in the event that the programmer has - // defined a private copy assignment operator for the class or struct. - - // We could try to figure out whether this has happened, but screw it. - // Concrete structure objects are not assignable, and so they don't get - // setters synthesized for them. If you want a setter, write it yourself. - - // We'll make an exception for the string types, however, since these are - // nearly an atomic type. - if (is_basic_string_char(type) || is_basic_string_wchar(type)) { - return true; - } - - return false; - - case CPPDeclaration::ST_typedef: - return is_assignable(type->as_typedef_type()->_type); - - default: - return true; - } -} - -/** - * Returns true if the indicated type is some kind of a reference or const - * reference type to something useful, false otherwise. - */ -bool TypeManager:: -is_reference(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_reference(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return is_pointable(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_reference(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is some kind of an rvalue reference. - */ -bool TypeManager:: -is_rvalue_reference(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_rvalue_reference(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return type->as_reference_type()->_value_category == CPPReferenceType::VC_rvalue; - - case CPPDeclaration::ST_typedef: - return is_rvalue_reference(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is some kind of a reference or const - * reference type at all, false otherwise. - */ -bool TypeManager:: -is_ref_to_anything(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_ref_to_anything(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return true; - - case CPPDeclaration::ST_typedef: - return is_ref_to_anything(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const reference to something, false - * otherwise. - */ -bool TypeManager:: -is_const_ref_to_anything(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_const_ref_to_anything(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return is_const(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ref_to_anything(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const pointer to something, false - * otherwise. - */ -bool TypeManager:: -is_const_pointer_to_anything(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_const_pointer_to_anything(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_const(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_pointer_to_anything(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a non-const pointer or reference to - * something, false otherwise. - */ -bool TypeManager:: -is_const_pointer_or_ref(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_const_pointer_or_ref(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_const(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_reference: - return is_const(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_pointer_or_ref(type->as_typedef_type()->_type); - - case CPPDeclaration::ST_struct: - if (type->get_simple_name() == "PointerTo") { - return false; - } else if (type->get_simple_name() == "ConstPointerTo") { - return true; - } - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a non-const pointer or reference to - * something, false otherwise. - */ -bool TypeManager:: -is_non_const_pointer_or_ref(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_non_const_pointer_or_ref(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return !is_const(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_reference: - return !is_const(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_non_const_pointer_or_ref(type->as_typedef_type()->_type); - - case CPPDeclaration::ST_struct: - if (type->get_simple_name() == "PointerTo") { - return true; - } else if (type->get_simple_name() == "ConstPointerTo") { - return false; - } - - default: - return false; - } -} - -/** - * Returns true if the indicated type is some kind of a pointer or const - * pointer type, false otherwise. - */ -bool TypeManager:: -is_pointer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_pointable(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_pointer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is some kind of a const type, false - * otherwise. - */ -bool TypeManager:: -is_const(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return true; - - case CPPDeclaration::ST_typedef: - return is_const(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a concrete struct, class, or union - * type, or false otherwise. - */ -bool TypeManager:: -is_struct(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_struct(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_struct: - case CPPDeclaration::ST_extension: - return true; - - case CPPDeclaration::ST_typedef: - return is_struct(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is an enum class, const or otherwise. - */ -bool TypeManager:: -is_scoped_enum(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_enum: - return ((CPPEnumType *)type)->is_scoped(); - - case CPPDeclaration::ST_const: - return is_scoped_enum(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_scoped_enum(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is some kind of enumerated type, const - * or otherwise. - */ -bool TypeManager:: -is_enum(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_enum: - return true; - - case CPPDeclaration::ST_const: - return is_enum(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_enum(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const enumerated type. - */ -bool TypeManager:: -is_const_enum(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_enum(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_enum(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const reference to an enumerated - * type. - */ -bool TypeManager:: -is_const_ref_to_enum(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_reference: - return is_const_enum(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ref_to_enum(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is nullptr_t, possibly const or a - * typedef to it. - */ -bool TypeManager:: -is_nullptr(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_simple: - return type->as_simple_type()->_type == CPPSimpleType::T_nullptr; - - case CPPDeclaration::ST_const: - return is_nullptr(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_nullptr(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is something that a scripting language - * can handle directly as a concrete, like an int or float, either const or - * non-const. - */ -bool TypeManager:: -is_simple(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_simple: - case CPPDeclaration::ST_enum: - return !is_void(type); - - case CPPDeclaration::ST_const: - return is_simple(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_simple(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const wrapper around some simple - * type like int. - */ -bool TypeManager:: -is_const_simple(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_simple(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_const_simple(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const reference to something that a - * scripting language can handle directly as a concrete. - */ -bool TypeManager:: -is_const_ref_to_simple(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_reference: - return is_const_simple(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ref_to_simple(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a non-const reference to something - * that a scripting language can handle directly as a concrete. - */ -bool TypeManager:: -is_ref_to_simple(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_reference: - return is_simple(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_ref_to_simple(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is an array of a simple type. - */ -bool TypeManager:: -is_simple_array(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_simple_array(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_array: - return is_simple(type->as_array_type()->_element_type); - - case CPPDeclaration::ST_typedef: - return is_simple_array(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const or a non-constant pointer to - * a simple type. This could also be a reference to an array of the simple - * type. - */ -bool TypeManager:: -is_pointer_to_simple(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_simple(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_simple(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_array: - return is_simple(type->as_array_type()->_element_type); - - case CPPDeclaration::ST_reference: - return is_pointer_to_simple(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_pointer_to_simple(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is something ordinary that a scripting - * language can handle a pointer to, e.g. a class or a structure, but not an - * int or a function. - */ -bool TypeManager:: -is_pointable(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointable(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_extension: - return (type->as_extension_type()->_type != CPPExtensionType::T_enum); - - case CPPDeclaration::ST_struct: - return true; - - // case CPPDeclaration::ST_simple: return is_char(type); - - case CPPDeclaration::ST_typedef: - return is_pointable(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is char or const char, but not signed or - * unsigned char. - */ -bool TypeManager:: -is_char(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_char(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return - simple_type->_type == CPPSimpleType::T_char && - simple_type->_flags == 0; - } - } - - case CPPDeclaration::ST_typedef: - return is_char(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is unsigned char, but not signed or - * 'plain' char. - */ -bool TypeManager:: -is_unsigned_char(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_unsigned_char(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - - if (simple_type != nullptr) { - return - (simple_type->_type == CPPSimpleType::T_char) && - (simple_type->_flags & CPPSimpleType::F_unsigned) != 0; - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_unsigned_char(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is signed char, but not unsigned or - * 'plain' char. - */ -bool TypeManager:: -is_signed_char(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_signed_char(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - - if (simple_type != nullptr) { - return - (simple_type->_type == CPPSimpleType::T_char) && - (simple_type->_flags & CPPSimpleType::F_signed) != 0; - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_signed_char(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is char * or const char * or some such. - */ -bool TypeManager:: -is_char_pointer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_char_pointer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_char(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_char_pointer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is const char*. - */ -bool TypeManager:: -is_const_char_pointer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_const_char_pointer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return (is_const(type->as_pointer_type()->_pointing_at) && - is_char(type->as_pointer_type()->_pointing_at)); - - case CPPDeclaration::ST_typedef: - return is_const_char_pointer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is unsigned char* or const unsigned - * char*. - */ -bool TypeManager:: -is_unsigned_char_pointer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_unsigned_char_pointer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_unsigned_char(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_unsigned_char_pointer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is const unsigned char*. - */ -bool TypeManager:: -is_const_unsigned_char_pointer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_unsigned_char_pointer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_const_unsigned_char_pointer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the type is basic_string. This is the standard C++ - * string class. - */ -bool TypeManager:: -is_basic_string_char(CPPType *type) { - CPPType *string_type = get_basic_string_char_type(); - if (string_type != nullptr && - string_type->get_local_name(&parser) == type->get_local_name(&parser)) { - return true; - } - - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_basic_string_char(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_basic_string_char(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is a const wrapper around - * basic_string. - */ -bool TypeManager:: -is_const_basic_string_char(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_basic_string_char(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_const_basic_string_char(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const reference to - * basic_string. - */ -bool TypeManager:: -is_const_ref_to_basic_string_char(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_reference: - return is_const_basic_string_char(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ref_to_basic_string_char(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const pointer to - * basic_string. - */ -bool TypeManager:: -is_const_ptr_to_basic_string_char(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_pointer: - return is_const_basic_string_char(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ptr_to_basic_string_char(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the type is basic_string, or a const reference to it. - */ -bool TypeManager:: -is_string(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_reference: - return is_const_basic_string_char(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_string(type->as_typedef_type()->_type); - - default: - break; - } - - return is_basic_string_char(type); -} - -/** - * Returns true if the indicated type is wchar_t or const wchar_t. We don't - * mind signed or unsigned wchar_t. - */ -bool TypeManager:: -is_wchar(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_wchar(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return simple_type->_type == CPPSimpleType::T_wchar_t; - } - } - - case CPPDeclaration::ST_typedef: - return is_wchar(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is wchar_t * or const wchar_t * or some - * such. - */ -bool TypeManager:: -is_wchar_pointer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_wchar_pointer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_wchar(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_wchar_pointer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the type is basic_string. This is the standard - * C++ wide string class. - */ -bool TypeManager:: -is_basic_string_wchar(CPPType *type) { - CPPType *string_type = get_basic_string_wchar_type(); - if (string_type != nullptr && - string_type->get_local_name(&parser) == type->get_local_name(&parser)) { - return true; - } - - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_basic_string_wchar(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_basic_string_wchar(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is a const wrapper around - * basic_string. - */ -bool TypeManager:: -is_const_basic_string_wchar(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_basic_string_wchar(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_const_basic_string_wchar(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const reference to - * basic_string. - */ -bool TypeManager:: -is_const_ref_to_basic_string_wchar(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_reference: - return is_const_basic_string_wchar(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ref_to_basic_string_wchar(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const pointer to - * basic_string. - */ -bool TypeManager:: -is_const_ptr_to_basic_string_wchar(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_pointer: - return is_const_basic_string_wchar(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ptr_to_basic_string_wchar(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the type is basic_string, or a const reference to - * it. - */ -bool TypeManager:: -is_wstring(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_reference: - return is_const_basic_string_wchar(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_wstring(type->as_typedef_type()->_type); - - default: - break; - } - - return is_basic_string_wchar(type); -} - -/** - * Returns true if the type is vector, or a const reference to - * it. - */ -bool TypeManager:: -is_vector_unsigned_char(CPPType *type) { - if (type->get_local_name(&parser) == "vector< unsigned char >" || - type->get_local_name(&parser) == "std::vector< unsigned char >" || - type->get_local_name(&parser) == "pvector< unsigned char >") { - return true; - } - - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_vector_unsigned_char(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return is_const_vector_unsigned_char(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_struct: - { - CPPStructType *stype = type->as_struct_type(); - CPPStructType::Derivation::const_iterator di; - for (di = stype->_derivation.begin(); - di != stype->_derivation.end(); - ++di) { - if (is_vector_unsigned_char((*di)._base)) { - return true; - } - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_vector_unsigned_char(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is a const wrapper around - * vector. - */ -bool TypeManager:: -is_const_vector_unsigned_char(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_vector_unsigned_char(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_const_vector_unsigned_char(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is bool, or some trivial variant. - */ -bool TypeManager:: -is_bool(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_bool(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return - simple_type->_type == CPPSimpleType::T_bool; - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_bool(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is one of the basic integer types: bool, - * char, short, int, or long, signed or unsigned, as well as enumerated types. - */ -bool TypeManager:: -is_integer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_integer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_enum: - return true; - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return - (simple_type->_type == CPPSimpleType::T_bool || - simple_type->_type == CPPSimpleType::T_char || - simple_type->_type == CPPSimpleType::T_wchar_t || - simple_type->_type == CPPSimpleType::T_char8_t || - simple_type->_type == CPPSimpleType::T_char16_t || - simple_type->_type == CPPSimpleType::T_char32_t || - simple_type->_type == CPPSimpleType::T_int); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_integer(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is one of the basic integer types, but - * only the unsigned varieties. - */ -bool TypeManager:: -is_unsigned_integer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_unsigned_integer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return - ((simple_type->_type == CPPSimpleType::T_bool || - simple_type->_type == CPPSimpleType::T_char || - simple_type->_type == CPPSimpleType::T_wchar_t || - simple_type->_type == CPPSimpleType::T_int) && - (simple_type->_flags & CPPSimpleType::F_unsigned) != 0) || - (simple_type->_type == CPPSimpleType::T_char8_t || - simple_type->_type == CPPSimpleType::T_char16_t || - simple_type->_type == CPPSimpleType::T_char32_t); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_unsigned_integer(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is the "size_t" type, or a const size_t, - * or a typedef to either. - */ -bool TypeManager:: -is_size(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_size(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - if (type->get_simple_name() == "size_t") { - return is_integer(type->as_typedef_type()->_type); - } else { - return is_size(type->as_typedef_type()->_type); - } - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is the "ssize_t" type, or a const - * ssize_t, or a typedef to either. ptrdiff_t and streamsize are also - * accepted, since they are usually also defined as the signed counterpart to - * size_t. - */ -bool TypeManager:: -is_ssize(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_ssize(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - if (type->get_simple_name() == "Py_ssize_t" || - type->get_simple_name() == "ssize_t" || - type->get_simple_name() == "ptrdiff_t" || - type->get_simple_name() == "streamsize") { - return is_integer(type->as_typedef_type()->_type); - } else { - return is_ssize(type->as_typedef_type()->_type); - } - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is the "long" type, whether signed or - * unsigned. - */ -bool TypeManager:: -is_long(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_long(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return (simple_type->_type == CPPSimpleType::T_int && - (simple_type->_flags & CPPSimpleType::F_long) != 0); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_long(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is the "short" type, whether signed or - * unsigned. - */ -bool TypeManager:: -is_short(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_short(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return (simple_type->_type == CPPSimpleType::T_int && - (simple_type->_flags & CPPSimpleType::F_short) != 0); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_short(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is an unsigned "short" type. - */ -bool TypeManager:: -is_unsigned_short(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_unsigned_short(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return (simple_type->_type == CPPSimpleType::T_int && - (simple_type->_flags & (CPPSimpleType::F_short | CPPSimpleType::F_unsigned)) == (CPPSimpleType::F_short | CPPSimpleType::F_unsigned)); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_unsigned_short(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is the "long long" type or larger, or at - * least a 64-bit integer, whether signed or unsigned. - */ -bool TypeManager:: -is_longlong(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_longlong(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return (simple_type->_type == CPPSimpleType::T_int && - (simple_type->_flags & CPPSimpleType::F_longlong) != 0); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_longlong(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is an unsigned "long long" type or - * larger, or at least a 64-bit unsigned integer. - */ -bool TypeManager:: -is_unsigned_longlong(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_unsigned_longlong(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return (simple_type->_type == CPPSimpleType::T_int && - (simple_type->_flags & (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned)) == (CPPSimpleType::F_longlong | CPPSimpleType::F_unsigned)); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_unsigned_longlong(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is the "double" type. - */ -bool TypeManager:: -is_double(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_double(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return (simple_type->_type == CPPSimpleType::T_double); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_double(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is one of the basic floating-point - * types: float, double, or some similar variant. - */ -bool TypeManager:: -is_float(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_float(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_simple: - { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return - (simple_type->_type == CPPSimpleType::T_float || - simple_type->_type == CPPSimpleType::T_double); - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_float(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is void. (Not void *, just void.) - */ -bool TypeManager:: -is_void(CPPType *type) { - CPPSimpleType *simple_type = type->as_simple_type(); - if (simple_type != nullptr) { - return - simple_type->_type == CPPSimpleType::T_void && - simple_type->_flags == 0; - } - - return false; -} - -/** - * Returns true if the indicated type is some class that derives from - * ReferenceCount, or defines ref and unref(), or false otherwise. - */ -bool TypeManager:: -is_reference_count(CPPType *type) { - CPPType *refcount_type = get_reference_count_type(); - if (refcount_type != nullptr && - refcount_type->get_local_name(&parser) == type->get_local_name(&parser)) { - return true; - } - - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_reference_count(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_struct: - { - CPPStructType *stype = type->as_struct_type(); - - // If we have methods named ref() and unref(), this is good enough. - if (stype->_scope->_functions.count("ref") && - stype->_scope->_functions.count("unref") && - stype->_scope->_functions.count("get_ref_count")) { - return true; - } - - CPPStructType::Derivation::const_iterator di; - for (di = stype->_derivation.begin(); - di != stype->_derivation.end(); - ++di) { - if (is_reference_count((*di)._base)) { - return true; - } - } - } - break; - - case CPPDeclaration::ST_typedef: - return is_reference_count(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is a pointer to a class that derives - * from ReferenceCount. - */ -bool TypeManager:: -is_reference_count_pointer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_reference_count_pointer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_reference_count(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_reference_count_pointer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is some class that derives from - * PointerToBase, or false otherwise. - */ -bool TypeManager:: -is_pointer_to_base(CPPType *type) { - // We only check the simple name of the type against PointerToBase, since we - // need to allow for the various template instantiations of this thing. - - // We also check explicitly for "PointerTo" and "ConstPointerTo", instead of - // actually checking for PointerToBase, because we don't want to consider - // PointerToArray in this category. - if (type->get_simple_name() == "PointerTo" || - type->get_simple_name() == "ConstPointerTo") { - return true; - } - - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_base(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_struct: - { - CPPStructType *stype = type->as_struct_type(); - CPPStructType::Derivation::const_iterator di; - for (di = stype->_derivation.begin(); - di != stype->_derivation.end(); - ++di) { - if (is_pointer_to_base((*di)._base)) { - return true; - } - } - } - return false; - - case CPPDeclaration::ST_typedef: - return is_pointer_to_base(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const PointerToBase or some - * derivative. - */ -bool TypeManager:: -is_const_pointer_to_base(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_base(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return is_const_pointer_to_base(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is a const reference to a class that - * derives from PointerToBase. - */ -bool TypeManager:: -is_const_ref_to_pointer_to_base(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_reference(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return is_const_pointer_to_base(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_const_ref_to_pointer_to_base(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the type is pair<>, or a reference to it. - */ -bool TypeManager:: -is_pair(CPPType *type) { - // We only check the simple name of the type against pair, since we need to - // allow for the various template instantiations of this thing. - if (type->get_simple_name() == "pair") { - return true; - } - - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pair(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return is_pair(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_pair(type->as_typedef_type()->_type); - - default: - break; - } - - return false; -} - -/** - * Returns true if the indicated type is PyObject *. - */ -bool TypeManager:: -is_pointer_to_PyObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_PyObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_PyObject(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_pointer_to_PyObject(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyObject. - */ -bool TypeManager:: -is_PyObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_PyObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_extension: - case CPPDeclaration::ST_struct: - return (type->get_local_name(&parser) == "_object" || - type->get_local_name(&parser) == "_typeobject"); - - case CPPDeclaration::ST_typedef: - return (is_struct(type->as_typedef_type()->_type) && - (type->get_local_name(&parser) == "PyObject" || - type->get_local_name(&parser) == "PyTypeObject" || - type->get_local_name(&parser) == "PyStringObject" || - type->get_local_name(&parser) == "PyUnicodeObject")) || - is_PyObject(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyTypeObject *. - */ -bool TypeManager:: -is_pointer_to_PyTypeObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_PyTypeObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_PyTypeObject(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_pointer_to_PyTypeObject(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyTypeObject. - */ -bool TypeManager:: -is_PyTypeObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_PyTypeObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_extension: - case CPPDeclaration::ST_struct: - return (type->get_local_name(&parser) == "_typeobject"); - - case CPPDeclaration::ST_typedef: - return (type->get_local_name(&parser) == "PyTypeObject" && - is_struct(type->as_typedef_type()->_type)) || - is_PyTypeObject(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyStringObject *. - */ -bool TypeManager:: -is_pointer_to_PyStringObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_PyStringObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_PyStringObject(type->as_pointer_type()->_pointing_at); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyStringObject. - */ -bool TypeManager:: -is_PyStringObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_PyStringObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return (type->get_local_name(&parser) == "PyStringObject" && - is_struct(type->as_typedef_type()->_type)) || - is_PyStringObject(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyStringObject *. - */ -bool TypeManager:: -is_pointer_to_PyUnicodeObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_PyUnicodeObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_PyUnicodeObject(type->as_pointer_type()->_pointing_at); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyUnicodeObject. - */ -bool TypeManager:: -is_PyUnicodeObject(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_PyUnicodeObject(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_typedef: - return (type->get_local_name(&parser) == "PyUnicodeObject" && - is_struct(type->as_typedef_type()->_type)) || - is_PyUnicodeObject(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is Py_buffer *. - */ -bool TypeManager:: -is_pointer_to_Py_buffer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_Py_buffer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return is_Py_buffer(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_pointer_to_Py_buffer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is Py_buffer. - */ -bool TypeManager:: -is_Py_buffer(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_Py_buffer(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_extension: - case CPPDeclaration::ST_struct: - return (type->get_local_name(&parser) == "Py_buffer" || - type->get_local_name(&parser) == "bufferinfo"); - - case CPPDeclaration::ST_typedef: - return is_Py_buffer(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is TypeHandle or a class with identical - * semantics like ButtonHandle. - */ -bool TypeManager:: -is_handle(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_handle(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_extension: - case CPPDeclaration::ST_struct: - return (type->get_local_name(&parser) == "TypeHandle" || - type->get_local_name(&parser) == "ButtonHandle"); - - case CPPDeclaration::ST_typedef: - return is_handle(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyObject. - */ -bool TypeManager::is_ostream(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_ostream(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_struct: - return (type->get_local_name(&parser) == "std::ostream" || - type->get_local_name(&parser) == "ostream" || - type->get_local_name(&parser) == "std::basic_ostream< char >"); - - case CPPDeclaration::ST_typedef: - return is_ostream(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the indicated type is PyObject *. - */ -bool TypeManager:: -is_pointer_to_ostream(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_pointer_to_ostream(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return is_ostream(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_pointer: - return is_ostream(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return is_pointer_to_ostream(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns true if the type is an unpublished type, e.g. a protected or - * private nested class, or simply a type not marked as 'published', or if the - * type is a pointer or reference to such an unpublished type, or even if the - * type is a function type that includes a parameter of such an unpublished - * type. - */ -bool TypeManager:: -involves_unpublished(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return involves_unpublished(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return involves_unpublished(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_pointer: - return involves_unpublished(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_struct: - // A struct type is unpublished only if all of its members are - // unpublished. - if (type->_declaration != nullptr) { - if (type->_declaration->_vis <= min_vis) { - return false; - } - } - { - CPPScope *scope = type->as_struct_type()->_scope; - - bool any_exported = false; - CPPScope::Declarations::const_iterator di; - for (di = scope->_declarations.begin(); - di != scope->_declarations.end() && !any_exported; - ++di) { - if ((*di)->_vis <= min_vis) { - any_exported = true; - } - } - - return !any_exported; - } - - case CPPDeclaration::ST_function: - if (type->_declaration != nullptr) { - if (type->_declaration->_vis <= min_vis) { - return false; - } - } - return true; - /* - { - CPPFunctionType *ftype = type->as_function_type(); - if (involves_unpublished(ftype->_return_type)) { - return true; - } - const CPPParameterList::Parameters ¶ms = - ftype->_parameters->_parameters; - CPPParameterList::Parameters::const_iterator pi; - for (pi = params.begin(); pi != params.end(); ++pi) { - if (involves_unpublished((*pi)->_type)) { - return true; - } - } - return false; - } - */ - - case CPPDeclaration::ST_typedef: - return involves_unpublished(type->as_typedef_type()->_type); - - default: - if (type->_declaration != nullptr) { - return (type->_declaration->_vis > min_vis); - } - return false; - } -} - -/** - * Returns true if the type is an protected type, e.g. a protected or private - * nested class, or if the type is a pointer or reference to such a protected - * type, or even if the type is a function type that includes a parameter of - * such a protected type. - */ -bool TypeManager:: -involves_protected(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return involves_protected(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return involves_protected(type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_pointer: - return involves_protected(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_function: - { - CPPFunctionType *ftype = type->as_function_type(); - if (involves_protected(ftype->_return_type)) { - return true; - } - const CPPParameterList::Parameters ¶ms = - ftype->_parameters->_parameters; - CPPParameterList::Parameters::const_iterator pi; - for (pi = params.begin(); pi != params.end(); ++pi) { - if (involves_protected((*pi)->_type)) { - return true; - } - } - return false; - } - - case CPPDeclaration::ST_typedef: - return involves_protected(type->as_typedef_type()->_type); - - default: - if (type->_declaration != nullptr) { - return (type->_declaration->_vis > V_public); - } - return false; - } -} - -/** - * Returns true if the type involves an rvalue reference. - */ -bool TypeManager:: -involves_rvalue_reference(CPPType *type) { - switch (type->get_subtype()) { - case CPPDeclaration::ST_const: - return involves_rvalue_reference(type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return type->as_reference_type()->_value_category == CPPReferenceType::VC_rvalue; - - case CPPDeclaration::ST_pointer: - return involves_rvalue_reference(type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_function: - { - CPPFunctionType *ftype = type->as_function_type(); - if (involves_rvalue_reference(ftype->_return_type)) { - return true; - } - const CPPParameterList::Parameters ¶ms = - ftype->_parameters->_parameters; - CPPParameterList::Parameters::const_iterator pi; - for (pi = params.begin(); pi != params.end(); ++pi) { - if (involves_rvalue_reference((*pi)->_type)) { - return true; - } - } - return false; - } - - case CPPDeclaration::ST_typedef: - return involves_rvalue_reference(type->as_typedef_type()->_type); - - default: - return false; - } -} - -/** - * Returns the type this pointer type points to. - */ -CPPType *TypeManager:: -unwrap_pointer(CPPType *source_type) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return unwrap_pointer(source_type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_pointer: - return source_type->as_pointer_type()->_pointing_at; - - default: - return source_type; - } -} - -/** - * Returns the type this reference type points to. - */ -CPPType *TypeManager:: -unwrap_reference(CPPType *source_type) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return unwrap_reference(source_type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return source_type->as_reference_type()->_pointing_at; - - default: - return source_type; - } -} - -/** - * Removes the const declaration from the outside of the type. - */ -CPPType *TypeManager:: -unwrap_const(CPPType *source_type) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return unwrap_const(source_type->as_const_type()->_wrapped_around); - - default: - return source_type; - } -} - -/** - * Removes a reference or a const reference from the type. - */ -CPPType *TypeManager:: -unwrap_const_reference(CPPType *source_type) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return unwrap_const_reference(source_type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return unwrap_const(source_type->as_reference_type()->_pointing_at); - - default: - return source_type; - } -} - -/** - * Removes all const, pointer, reference wrappers, and typedefs, to get to the - * thing we're talking about. - */ -CPPType *TypeManager:: -unwrap(CPPType *source_type) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return unwrap(source_type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return unwrap(source_type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_pointer: - return unwrap(source_type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_typedef: - return unwrap(source_type->as_typedef_type()->_type); - - default: - return source_type; - } -} - -/** - * Returns the type of pointer the given PointerTo class emulates. - * Essentially this just checks the return type of the method called 'p()'. - * Returns NULL if the PointerTo class has no method p(). - */ -CPPType *TypeManager:: -get_pointer_type(CPPStructType *pt_type) { - CPPScope *scope = pt_type->_scope; - - CPPScope::Functions::const_iterator fi; - fi = scope->_functions.find("p"); - if (fi != scope->_functions.end()) { - CPPFunctionGroup *fgroup = (*fi).second; - - // These are all the functions named "p". Now look for one that takes no - // parameters. - CPPFunctionGroup::Instances::iterator ii; - for (ii = fgroup->_instances.begin(); - ii != fgroup->_instances.end(); - ++ii) { - CPPInstance *function = (*ii); - CPPFunctionType *ftype = function->_type->as_function_type(); - assert(ftype != nullptr); - if (ftype->_parameters->_parameters.empty()) { - // Here's the function p(). What's its return type? - return resolve_type(ftype->_return_type); - } - } - } - - return nullptr; -} - -/** - * Returns the ith template parameter type. For instance, if the type is - * pair, then this function will return type A when passing 0 and type B - * when passing 1, and NULL otherwise. - */ -CPPType *TypeManager:: -get_template_parameter_type(CPPType *source_type, int i) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return get_template_parameter_type(source_type->as_const_type()->_wrapped_around, i); - - case CPPDeclaration::ST_reference: - return get_template_parameter_type(source_type->as_reference_type()->_pointing_at, i); - - case CPPDeclaration::ST_typedef: - return get_template_parameter_type(source_type->as_typedef_type()->_type); - - default: - break; - } - - CPPStructType *type = source_type->as_struct_type(); - if (type == nullptr) { - return nullptr; - } - - // I'm not sure how reliable this is, but I don't know if there is a more - // proper way to access this. - CPPTemplateParameterList *templ = type->_ident->_names.back().get_templ(); - if (templ == nullptr || i >= (int)templ->_parameters.size()) { - return nullptr; - } - - CPPDeclaration *decl = templ->_parameters[i]; - return decl->as_type(); -} - -/** - * Returns the type corresponding to a pointer to the given type. - */ -CPPType *TypeManager:: -wrap_pointer(CPPType *source_type) { - return CPPType::new_type(new CPPPointerType(source_type)); -} - -/** - * Returns the type corresponding to a const pointer to the given type. - */ -CPPType *TypeManager:: -wrap_const_pointer(CPPType *source_type) { - if (source_type->as_const_type() != nullptr) { - // It's already const. - return - CPPType::new_type(new CPPPointerType(source_type)); - } else { - return - CPPType::new_type(new CPPPointerType(new CPPConstType(source_type))); - } -} - -/** - * Returns the type corresponding to a const reference to the given type. - */ -CPPType *TypeManager:: -wrap_const_reference(CPPType *source_type) { - if (source_type->as_const_type() != nullptr) { - // It's already const. - return - CPPType::new_type(new CPPReferenceType(source_type)); - } else { - return - CPPType::new_type(new CPPReferenceType(new CPPConstType(source_type))); - } -} - -/** - * Returns a CPPType that represents basic_string, or NULL if the type - * is unknown. - */ -CPPType *TypeManager:: -get_basic_string_char_type() { - static bool got_type = false; - static CPPType *type = nullptr; - if (!got_type) { - type = parser.parse_type("std::basic_string"); - got_type = true; - } - return type; -} - -/** - * Returns a CPPType that represents basic_string, or NULL if the - * type is unknown. - */ -CPPType *TypeManager:: -get_basic_string_wchar_type() { - static bool got_type = false; - static CPPType *type = nullptr; - if (!got_type) { - type = parser.parse_type("std::basic_string"); - got_type = true; - } - return type; -} - -/** - * Returns a CPPType that represents ReferenceCount, or NULL if the type is - * unknown. - */ -CPPType *TypeManager:: -get_reference_count_type() { - static bool got_type = false; - static CPPType *type = nullptr; - if (!got_type) { - type = parser.parse_type("ReferenceCount"); - got_type = true; - } - return type; -} - -/** - * Returns a CPPType that represents void. - */ -CPPType *TypeManager:: -get_void_type() { - static bool got_type = false; - static CPPType *type = nullptr; - if (!got_type) { - type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_void)); - got_type = true; - } - return type; -} - -/** - * Returns a CPPType that represents int. - */ -CPPType *TypeManager:: -get_int_type() { - static bool got_type = false; - static CPPType *type = nullptr; - if (!got_type) { - type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_int)); - got_type = true; - } - return type; -} - -/** - * Returns a string corresponding to the given function signature. This is a - * unique string per each uniquely-callable C++ function or method. Basically - * it's the function prototype, sans the return type. - * - * If num_default_parameters is nonzero, it is the number of parameters to - * omit from the end of the parameter list. This in effect gets the function - * signature for an equivalent function with n parameters assuming default - * values. - */ -string TypeManager:: -get_function_signature(CPPInstance *function, - int num_default_parameters) { - CPPFunctionType *ftype = function->_type->as_function_type(); - assert(ftype != nullptr); - - std::ostringstream out; - - // It's tempting to mark static methods with a different function signature - // than non-static, because a static method doesn't have an implicit 'this' - // parameter. However, this breaks the lookup when we come across a method - // definition outside of the class body; since there's no clue at this point - // whether the method is static or not, we can't successfully look it up. - // Bummer. - /* - if ((function->_storage_class & CPPInstance::SC_static) != 0) { - out << "static "; - } - */ - - out << function->get_local_name(&parser) << "("; - - const CPPParameterList::Parameters ¶ms = - ftype->_parameters->_parameters; - CPPParameterList::Parameters::const_iterator pi; - - int num_params = params.size() - num_default_parameters; - pi = params.begin(); - for (int n = 0; n < num_params; n++) { - assert(pi != params.end()); - CPPType *ptype = (*pi)->_type; - - // One exception: if the type is a const reference to something, we build - // the signature with its corresponding concrete. C++ can't differentiate - // these two anyway. - if (is_const_ref_to_anything(ptype)) { - ptype = unwrap_const_reference(ptype); - } - - out << ptype->get_local_name(&parser); - - if (n + 1 < num_params) { - out << ", "; - } - - ++pi; - } - out << ")"; - - if (ftype->_flags & CPPFunctionType::F_const_method) { - out << " const"; - } - - return out.str(); -} - -/** - * Returns a string corresponding to the given function name. This is not - * necessarily unique to the particular overloaded function instance, but is - * common among all overloaded functions of the same name. - */ -string TypeManager:: -get_function_name(CPPInstance *function) { - return function->get_local_name(&parser); -} - -/** - * Returns true if the destructor for the given class or struct is protected - * or private, or false if the destructor is public or absent. - */ -bool TypeManager:: -has_protected_destructor(CPPType *type) { - CPPStructType *struct_type = type->as_struct_type(); - if (struct_type == nullptr) { - // It's not even a struct type! - return false; - } - - CPPScope *scope = struct_type->get_scope(); - - // Look for the destructor. - CPPScope::Declarations::const_iterator di; - for (di = scope->_declarations.begin(); - di != scope->_declarations.end(); - ++di) { - if ((*di)->get_subtype() == CPPDeclaration::ST_instance) { - CPPInstance *inst = (*di)->as_instance(); - if (inst->_type->get_subtype() == CPPDeclaration::ST_function) { - // Here's a function declaration. - CPPFunctionType *ftype = inst->_type->as_function_type(); - assert(ftype != nullptr); - if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) { - // Here's the destructor! Is it protected? - return (inst->_vis > V_public); - } - } - } - } - - // No explicit destructor. - return false; -} -/** - * - */ -bool TypeManager:: -is_exported(CPPType *in_type) { - string name = in_type->get_local_name(&parser); - if (name.empty()) { - return false; - } - - // this question is about the base type - CPPType *base_type = resolve_type(unwrap(in_type)); - // CPPType *base_type = in_type; Ok export Rules.. Classes and Structs and - // Unions are exported only if they have a function that is exported.. - // function is the easiest case. - - if (base_type->_vis <= min_vis) { - return true; - } - - if (in_type->_vis <= min_vis) { - return true; - } - - if (base_type->get_subtype() == CPPDeclaration::ST_struct) { - CPPStructType *struct_type = base_type->resolve_type(&parser, &parser)->as_struct_type(); - CPPScope *scope = struct_type->_scope; - - CPPScope::Declarations::const_iterator di; - for (di = scope->_declarations.begin(); - di != scope->_declarations.end(); ++di) { - if ((*di)->_vis <= min_vis) { - return true; - } - } - - } else if (base_type->get_subtype() == CPPDeclaration::ST_instance) { - CPPInstance *inst = base_type->as_instance(); - if (inst->_type->get_subtype() == CPPDeclaration::ST_function) { - CPPInstance *function = inst; - CPPFunctionType *ftype = function->_type->resolve_type(&parser, &parser)->as_function_type(); - if (ftype->_vis <= min_vis) { - return true; - } - } else { - if (inst->_vis <= min_vis) { - return true; - } - } - - } else if (base_type->get_subtype() == CPPDeclaration::ST_typedef) { - CPPTypedefType *tdef = base_type->as_typedef_type(); - if (tdef->_type->get_subtype() == CPPDeclaration::ST_struct) { - CPPStructType *struct_type =tdef->_type->resolve_type(&parser, &parser)->as_struct_type(); - return is_exported(struct_type); - } - - } else if (base_type->get_subtype() == CPPDeclaration::ST_type_declaration) { - CPPType *type = base_type->as_type_declaration()->_type; - if (type->get_subtype() == CPPDeclaration::ST_struct) { - CPPStructType *struct_type =type->as_type()->resolve_type(&parser, &parser)->as_struct_type(); - // CPPScope *scope = struct_type->_scope; - return is_exported(struct_type); - - } else if (type->get_subtype() == CPPDeclaration::ST_enum) { - // CPPEnumType *enum_type = type->as_type()->resolve_type(&parser, - // &parser)->as_enum_type(); - if (type->_vis <= min_vis) { - return true; - } - } - } - -/* - printf("---------------------> Visibility Failed %s %d Vis=%d, Minvis=%d\n", - base_type->get_fully_scoped_name().c_str(), - base_type->get_subtype(), - base_type->_vis, - min_vis); -*/ - return false; -} - -/** - * Returns true if the type is defined in a local file rather than one that is - * included. - */ -bool TypeManager:: -is_local(CPPType *source_type) { - switch (source_type->get_subtype()) { - case CPPDeclaration::ST_const: - return is_local(source_type->as_const_type()->_wrapped_around); - - case CPPDeclaration::ST_reference: - return is_local(source_type->as_reference_type()->_pointing_at); - - case CPPDeclaration::ST_pointer: - return is_local(source_type->as_pointer_type()->_pointing_at); - - case CPPDeclaration::ST_simple: - return false; - - default: - { - CPPType *resolved_type = resolve_type(source_type); - if (resolved_type->_file._source == CPPFile::S_local && !resolved_type->is_incomplete()) { - return true; - } - } - } - - return false; - - /* - - if (base_type->get_subtype() == CPPDeclaration::ST_struct) - { - CPPStructType *struct_type = base_type->as_struct_type(); - if (struct_type->_file._source == CPPFile::S_local) - return true; - - } - else if (base_type->get_subtype() == CPPDeclaration::ST_instance) - { - CPPInstance *inst = base_type->as_instance(); - if (inst->_type->get_subtype() == CPPDeclaration::ST_function) - { - CPPInstance *function = inst; - CPPFunctionType *ftype = function->_type->resolve_type(&parser, &parser)->as_function_type(); - if (ftype->_file._source == CPPFile::S_local) - return true; - } - else - { - if (inst->_file._source == CPPFile::S_local) - return true; - } - } - else if (base_type->get_subtype() == CPPDeclaration::ST_typedef) - { - CPPTypedef *tdef = base_type->as_typedef(); - if (tdef->_type->get_subtype() == CPPDeclaration::ST_struct) - { - CPPStructType *struct_type =tdef->_type->resolve_type(&parser, &parser)->as_struct_type(); - return IsLocal(struct_type); - - - } - } - else if (base_type->get_subtype() == CPPDeclaration::ST_type_declaration) - { - CPPType *type = base_type->as_type_declaration()->_type; - if (type->get_subtype() == CPPDeclaration::ST_struct) - { - CPPStructType *struct_type =type->as_type()->resolve_type(&parser, &parser)->as_struct_type(); - if (struct_type->_file._source == CPPFile::S_local) - return true; - - } - else if (type->get_subtype() == CPPDeclaration::ST_enum) - { - CPPEnumType *enum_type = type->as_type()->resolve_type(&parser, &parser)->as_enum_type(); - if (enum_type->_file._source != CPPFile::S_local) - return true; - } - } - - if (base_type->_file._source == CPPFile::S_local) - return true; - - return false; - */ -} diff --git a/dtool/src/interrogate/typeManager.h b/dtool/src/interrogate/typeManager.h deleted file mode 100644 index e9161dbd31d..00000000000 --- a/dtool/src/interrogate/typeManager.h +++ /dev/null @@ -1,157 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file typeManager.h - * @author drose - * @date 2000-08-14 - */ - -#ifndef TYPEMANAGER_H -#define TYPEMANAGER_H - -#include "dtoolbase.h" - -class CPPFunctionGroup; -class CPPInstance; -class CPPType; -class CPPSimpleType; -class CPPPointerType; -class CPPConstType; -class CPPExtensionType; -class CPPStructType; -class CPPEnumType; -class CPPFunctionType; -class CPPScope; -class CPPIdentifier; -class CPPNameComponent; -class CPPManifest; - -/** - * This is just a collection of static methods that perform useful operations - * on CPPTypes for interrogate. The class is really just a namespace that - * groups these functions together. - */ -class TypeManager { -public: - - static CPPType *resolve_type(CPPType *type, CPPScope *scope = nullptr); - - static bool is_assignable(CPPType *type); - - static bool is_reference(CPPType *type); - static bool is_rvalue_reference(CPPType *type); - static bool is_ref_to_anything(CPPType *type); - static bool is_const_ref_to_anything(CPPType *type); - static bool is_const_pointer_to_anything(CPPType *type); - static bool is_const_pointer_or_ref(CPPType *type); - static bool is_non_const_pointer_or_ref(CPPType *type); - static bool is_pointer(CPPType *type); - static bool is_const(CPPType *type); - static bool is_struct(CPPType *type); - static bool is_scoped_enum(CPPType *type); - static bool is_enum(CPPType *type); - static bool is_const_enum(CPPType *type); - static bool is_const_ref_to_enum(CPPType *type); - static bool is_nullptr(CPPType *type); - static bool is_simple(CPPType *type); - static bool is_const_simple(CPPType *type); - static bool is_const_ref_to_simple(CPPType *type); - static bool is_ref_to_simple(CPPType *type); - static bool is_simple_array(CPPType *type); - static bool is_pointer_to_simple(CPPType *type); - static bool is_pointable(CPPType *type); - static bool is_char(CPPType *type); - static bool is_unsigned_char(CPPType *type); - static bool is_signed_char(CPPType *type); - static bool is_char_pointer(CPPType *type); - static bool is_const_char_pointer(CPPType *type); - static bool is_unsigned_char_pointer(CPPType *type); - static bool is_const_unsigned_char_pointer(CPPType *type); - static bool is_basic_string_char(CPPType *type); - static bool is_const_basic_string_char(CPPType *type); - static bool is_const_ref_to_basic_string_char(CPPType *type); - static bool is_const_ptr_to_basic_string_char(CPPType *type); - static bool is_string(CPPType *type); - static bool is_wchar(CPPType *type); - static bool is_wchar_pointer(CPPType *type); - static bool is_basic_string_wchar(CPPType *type); - static bool is_const_basic_string_wchar(CPPType *type); - static bool is_const_ref_to_basic_string_wchar(CPPType *type); - static bool is_const_ptr_to_basic_string_wchar(CPPType *type); - static bool is_wstring(CPPType *type); - static bool is_vector_unsigned_char(CPPType *type); - static bool is_const_vector_unsigned_char(CPPType *type); - static bool is_pair(CPPType *type); - static bool is_bool(CPPType *type); - static bool is_integer(CPPType *type); - static bool is_unsigned_integer(CPPType *type); - static bool is_size(CPPType *type); - static bool is_ssize(CPPType *type); - static bool is_long(CPPType *type); - static bool is_short(CPPType *type); - static bool is_unsigned_short(CPPType *type); - static bool is_longlong(CPPType *type); - static bool is_unsigned_longlong(CPPType *type); - static bool is_double(CPPType *type); - static bool is_float(CPPType *type); - static bool is_void(CPPType *type); - static bool is_reference_count(CPPType *type); - static bool is_reference_count_pointer(CPPType *type); - static bool is_pointer_to_base(CPPType *type); - static bool is_const_pointer_to_base(CPPType *type); - static bool is_const_ref_to_pointer_to_base(CPPType *type); - static bool is_pointer_to_PyObject(CPPType *type); - static bool is_PyObject(CPPType *type); - static bool is_pointer_to_PyTypeObject(CPPType *type); - static bool is_PyTypeObject(CPPType *type); - static bool is_pointer_to_PyStringObject(CPPType *type); - static bool is_PyStringObject(CPPType *type); - static bool is_pointer_to_PyUnicodeObject(CPPType *type); - static bool is_PyUnicodeObject(CPPType *type); - static bool is_pointer_to_Py_buffer(CPPType *type); - static bool is_Py_buffer(CPPType *type); - static bool is_handle(CPPType *type); - static bool involves_unpublished(CPPType *type); - static bool involves_protected(CPPType *type); - static bool involves_rvalue_reference(CPPType *type); - - static bool is_ostream(CPPType *type); - static bool is_pointer_to_ostream(CPPType *type); - - static CPPType *unwrap_pointer(CPPType *type); - static CPPType *unwrap_reference(CPPType *type); - static CPPType *unwrap_const(CPPType *type); - static CPPType *unwrap_const_reference(CPPType *type); - static CPPType *unwrap(CPPType *type); - - static CPPType *get_pointer_type(CPPStructType *pt_type); - static CPPType *get_template_parameter_type(CPPType *type, int i = 0); - - static CPPType *wrap_pointer(CPPType *type); - static CPPType *wrap_const_pointer(CPPType *type); - static CPPType *wrap_const_reference(CPPType *type); - - static CPPType *get_basic_string_char_type(); - static CPPType *get_basic_string_wchar_type(); - static CPPType *get_reference_count_type(); - static CPPType *get_void_type(); - static CPPType *get_int_type(); - - static std::string get_function_signature(CPPInstance *function, - int num_default_parameters = 0); - - static std::string get_function_name(CPPInstance *function); - - static bool has_protected_destructor(CPPType *type); - - - static bool is_exported(CPPType *type); - static bool is_local(CPPType *type); -}; - -#endif diff --git a/dtool/src/interrogatedb/CMakeLists.txt b/dtool/src/interrogatedb/CMakeLists.txt index adadd5a24b6..f137a7b8023 100644 --- a/dtool/src/interrogatedb/CMakeLists.txt +++ b/dtool/src/interrogatedb/CMakeLists.txt @@ -1,76 +1,8 @@ -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 + interrogate_request.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) diff --git a/dtool/src/interrogatedb/config_interrogatedb.cxx b/dtool/src/interrogatedb/config_interrogatedb.cxx deleted file mode 100644 index 16986de56b6..00000000000 --- a/dtool/src/interrogatedb/config_interrogatedb.cxx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_interrogatedb.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "config_interrogatedb.h" -#include "interrogate_request.h" -#include "configVariableBool.h" -#include "configVariableSearchPath.h" -#include "dconfig.h" - -#if defined(_MSC_VER) && defined(_DEBUG) -// _DEBUG assumes you are linking to msvcrt70d.dll, not msvcrt70.dll -#define USE_WIN32_DBGHEAP -#include -#endif - -Configure(config_interrogatedb); -NotifyCategoryDef(interrogatedb, ""); - -ConfigureFn(config_interrogatedb) { - // interrogate_request_library("types"); - -#ifdef USE_WIN32_DBGHEAP - ConfigVariableBool use_win32_dbgheap("use-win32-dbgheap", false); - ConfigVariableBool win32_report_leaks("win32-report-leaks", false); - - int dbg_flags = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ); - - if (use_win32_dbgheap.get_string_value() == "full") { - // "full" means check the heap after *every* allocdealloc. Expensive. - dbg_flags |= (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | - _CRTDBG_CHECK_CRT_DF); - - } else { - // Otherwise, it's a bool flag. true means check the heap normally, false - // means don't do any debug checking. - if (!use_win32_dbgheap) { - // deflt disable complete heap verify every 1024 allocations (VC7 - // deflt). With vc7 stl small-string-optimization causing more allocs, - // this can cause order-of-magnitude slowdowns in dbg builds - dbg_flags = 0; - } - } - - if (win32_report_leaks) { - // Report memory still allocated at program termination. Not sure how - // useful this is, as many things get allocated once and never freed, but - // they aren't really leaks. - dbg_flags |= _CRTDBG_LEAK_CHECK_DF; - } - - _CrtSetDbgFlag(dbg_flags); -#endif -} - -ConfigVariableSearchPath interrogatedb_path -("interrogatedb-path", "The search path for interrogate's *.in files."); diff --git a/dtool/src/interrogatedb/config_interrogatedb.h b/dtool/src/interrogatedb/config_interrogatedb.h deleted file mode 100644 index 1a99702d0e2..00000000000 --- a/dtool/src/interrogatedb/config_interrogatedb.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_interrogatedb.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef CONFIG_INTERROGATEDB_H -#define CONFIG_INTERROGATEDB_H - -#include "dtoolbase.h" -#include "notifyCategoryProxy.h" -#include "configVariableSearchPath.h" - -NotifyCategoryDecl(interrogatedb, EXPCL_INTERROGATEDB, EXPTP_INTERROGATEDB); - -extern ConfigVariableSearchPath interrogatedb_path; - -#endif diff --git a/dtool/src/interrogatedb/dtool_super_base.cxx b/dtool/src/interrogatedb/dtool_super_base.cxx deleted file mode 100644 index 0b7613617e3..00000000000 --- a/dtool/src/interrogatedb/dtool_super_base.cxx +++ /dev/null @@ -1,161 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file dtool_super_base.cxx - * @author drose - * @date 2005-07-04 - */ - -#include "py_panda.h" - -#ifdef HAVE_PYTHON - -static PyMemberDef standard_type_members[] = { - {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"}, - {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"}, - {(char *)"this_const", T_BOOL, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"}, -// {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature), -// READONLY, (char *)"A type check signature"}, - {(char *)"this_metatype", T_OBJECT_EX, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"}, - {nullptr} /* Sentinel */ -}; - -static PyObject *GetSuperBase(PyObject *self) { - Dtool_PyTypedObject *super_base = Dtool_GetSuperBase(); - return Py_XNewRef((PyObject *)&super_base->_PyType); -}; - -static void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module) { - if (module != nullptr) { - Dtool_PyTypedObject *super_base = Dtool_GetSuperBase(); - PyModule_AddObjectRef(module, "DTOOL_SUPER_BASE", (PyObject *)&super_base->_PyType); - } -} - -static void *Dtool_UpcastInterface_DTOOL_SUPER_BASE(PyObject *self, Dtool_PyTypedObject *requested_type) { - return nullptr; -} - -static PyObject *Dtool_Wrap_DTOOL_SUPER_BASE(void *from_this, PyTypeObject *from_type) { - return nullptr; -} - -static int Dtool_Init_DTOOL_SUPER_BASE(PyObject *self, PyObject *args, PyObject *kwds) { - assert(self != nullptr); - PyErr_Format(PyExc_TypeError, "cannot init constant class %s", Py_TYPE(self)->tp_name); - return -1; -} - -static void Dtool_FreeInstance_DTOOL_SUPER_BASE(PyObject *self) { - Py_TYPE(self)->tp_free(self); -} - -/** - * Returns a pointer to the DTOOL_SUPER_BASE class that is the base class of - * all Panda types. This pointer is shared by all modules. - */ -Dtool_PyTypedObject *Dtool_GetSuperBase() { - Dtool_TypeMap *type_map = Dtool_GetGlobalTypeMap(); - auto it = type_map->find("DTOOL_SUPER_BASE"); - if (it != type_map->end()) { - return it->second; - } - - static PyMethodDef methods[] = { - { "DtoolGetSuperBase", (PyCFunction)&GetSuperBase, METH_NOARGS, "Will Return SUPERbase Class"}, - { nullptr, nullptr, 0, nullptr } - }; - - static Dtool_PyTypedObject super_base_type = { - { - PyVarObject_HEAD_INIT(nullptr, 0) - "dtoolconfig.DTOOL_SUPER_BASE", - sizeof(Dtool_PyInstDef), - 0, // tp_itemsize - &Dtool_FreeInstance_DTOOL_SUPER_BASE, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr -#if PY_MAJOR_VERSION >= 3 - nullptr, // tp_compare -#else - &DtoolInstance_ComparePointers, -#endif - nullptr, // tp_repr - nullptr, // tp_as_number - nullptr, // tp_as_sequence - nullptr, // tp_as_mapping - &DtoolInstance_HashPointer, - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES), - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear -#if PY_MAJOR_VERSION >= 3 - &DtoolInstance_RichComparePointers, -#else - nullptr, // tp_richcompare -#endif - 0, // tp_weaklistoffset - nullptr, // tp_iter - nullptr, // tp_iternext - methods, - standard_type_members, - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - Dtool_Init_DTOOL_SUPER_BASE, - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }, - TypeHandle::none(), - Dtool_PyModuleClassInit_DTOOL_SUPER_BASE, - Dtool_UpcastInterface_DTOOL_SUPER_BASE, - Dtool_Wrap_DTOOL_SUPER_BASE, - nullptr, - nullptr, - }; - - super_base_type._PyType.tp_dict = PyDict_New(); - PyDict_SetItemString(super_base_type._PyType.tp_dict, "DtoolClassDict", super_base_type._PyType.tp_dict); - - if (PyType_Ready((PyTypeObject *)&super_base_type) < 0) { - PyErr_SetString(PyExc_TypeError, "PyType_Ready(Dtool_DTOOL_SUPER_BASE)"); - return nullptr; - } - Py_INCREF(&super_base_type._PyType); - - PyDict_SetItemString(super_base_type._PyType.tp_dict, "DtoolGetSuperBase", PyCFunction_New(&methods[0], (PyObject *)&super_base_type)); - - (*type_map)["DTOOL_SUPER_BASE"] = &super_base_type; - return &super_base_type; -} - -#endif // HAVE_PYTHON diff --git a/dtool/src/interrogatedb/indexRemapper.cxx b/dtool/src/interrogatedb/indexRemapper.cxx deleted file mode 100644 index 7c606bec065..00000000000 --- a/dtool/src/interrogatedb/indexRemapper.cxx +++ /dev/null @@ -1,68 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file indexRemapper.cxx - * @author drose - * @date 2000-08-05 - */ - -#include "indexRemapper.h" - - -/** - * - */ -IndexRemapper:: -IndexRemapper() { -} - -/** - * - */ -IndexRemapper:: -~IndexRemapper() { -} - -/** - * Removes all mappings from the object. - */ -void IndexRemapper:: -clear() { - _map_int.clear(); -} - -/** - * Adds a mapping from the integer 'from' to 'to'. - */ -void IndexRemapper:: -add_mapping(int from, int to) { - _map_int[from] = to; -} - -/** - * Returns true if the given 'from' integer has been assigned a mapping, false - * if it has not. - */ -bool IndexRemapper:: -in_map(int from) const { - return _map_int.count(from) != 0; -} - -/** - * Returns the integer that the given 'from' integer had been set to map to, - * or the same integer if nothing had been set for it. - */ -int IndexRemapper:: -map_from(int from) const { - std::map::const_iterator mi; - mi = _map_int.find(from); - if (mi == _map_int.end()) { - return from; - } - return (*mi).second; -} diff --git a/dtool/src/interrogatedb/indexRemapper.h b/dtool/src/interrogatedb/indexRemapper.h deleted file mode 100644 index c89a7a29882..00000000000 --- a/dtool/src/interrogatedb/indexRemapper.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file indexRemapper.h - * @author drose - * @date 2000-08-05 - */ - -#ifndef INDEXREMAPPER_H -#define INDEXREMAPPER_H - -#include "dtoolbase.h" - -#include - -/** - * This class manages a mapping of integers to integers. It's used in this - * package to resequence some or all of the index numbers in the database to a - * different sequence. - * - * This class is just a wrapper around STL map. The only reason it exists is - * because Microsoft can't export STL map outside of the DLL. - */ -class EXPCL_INTERROGATEDB IndexRemapper { -public: - IndexRemapper(); - ~IndexRemapper(); - - void clear(); - void add_mapping(int from, int to); - - bool in_map(int from) const; - int map_from(int from) const; - -private: - std::map _map_int; -}; - -#endif diff --git a/dtool/src/interrogatedb/interrogateComponent.I b/dtool/src/interrogatedb/interrogateComponent.I deleted file mode 100644 index dddbb421fb4..00000000000 --- a/dtool/src/interrogatedb/interrogateComponent.I +++ /dev/null @@ -1,123 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateComponent.I - * @author drose - * @date 2000-08-08 - */ - -/** - * - */ -INLINE InterrogateComponent:: -InterrogateComponent(InterrogateModuleDef *def) : - _def(def) -{ -} - -/** - * - */ -INLINE InterrogateComponent:: -InterrogateComponent(const InterrogateComponent ©) : - _def(copy._def), - _name(copy._name) -{ -} - -/** - * - */ -INLINE void InterrogateComponent:: -operator = (const InterrogateComponent ©) { - _def = copy._def; - _name = copy._name; -} - -/** - * Returns true if we have a known library name, false if we do not. See - * get_library_name(). - */ -INLINE bool InterrogateComponent:: -has_library_name() const { - const char *name = get_library_name(); - return (name != nullptr && name[0] != '\0'); -} - -/** - * Returns the library name, if it is known, or NULL if it is not. This is - * the name of the library that this particular component was built into. - * Typically this will be a one-to-one correspondance with an invocation of - * the interrogate command. Typical examples are "libutil" and "liblinmath". - */ -INLINE const char *InterrogateComponent:: -get_library_name() const { - if (_def != nullptr) { - return _def->library_name; - } - return nullptr; -} - -/** - * Returns true if we have a known module name, false if we do not. See - * get_module_name(). - */ -INLINE bool InterrogateComponent:: -has_module_name() const { - const char *name = get_module_name(); - return (name != nullptr && name[0] != '\0'); -} - -/** - * Returns the module name, if it is known, or NULL if it is not. This is the - * name of the module that this particular component is associated with. This - * is a higher grouping than library. Typical examples are "panda" and - * "pandaegg". - */ -INLINE const char *InterrogateComponent:: -get_module_name() const { - if (_def != nullptr) { - return _def->module_name; - } - return nullptr; -} - -/** - * - */ -INLINE bool InterrogateComponent:: -has_name() const { - return !_name.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateComponent:: -get_name() const { - return _name; -} - -/** - * - */ -INLINE int InterrogateComponent:: -get_num_alt_names() const { - return _alt_names.size(); -} - -/** - * - */ -INLINE const std::string &InterrogateComponent:: -get_alt_name(int n) const { - if (n >= 0 && n < (int)_alt_names.size()) { - return _alt_names[n]; - } - return _empty_string; -} diff --git a/dtool/src/interrogatedb/interrogateComponent.cxx b/dtool/src/interrogatedb/interrogateComponent.cxx deleted file mode 100644 index 61398f686f7..00000000000 --- a/dtool/src/interrogatedb/interrogateComponent.cxx +++ /dev/null @@ -1,50 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateComponent.cxx - * @author drose - * @date 2000-08-08 - */ - -#include "interrogateComponent.h" -#include "interrogate_datafile.h" - -// This static string is just kept around as a handy bogus return value for -// functions that must return a const string reference. -std::string InterrogateComponent::_empty_string; - -/** - * Formats the component for output to a data file. - */ -void InterrogateComponent:: -output(std::ostream &out) const { - idf_output_string(out, _name); - out << _alt_names.size() << " "; - - Strings::const_iterator vi; - for (vi = _alt_names.begin(); vi != _alt_names.end(); ++vi) { - idf_output_string(out, *vi); - } -} - -/** - * Reads the data file as previously formatted by output(). - */ -void InterrogateComponent:: -input(std::istream &in) { - idf_input_string(in, _name); - - int num_alt_names; - in >> num_alt_names; - _alt_names.reserve(num_alt_names); - for (int i = 0; i < num_alt_names; ++i) { - std::string alt_name; - idf_input_string(in, alt_name); - _alt_names.push_back(alt_name); - } -} diff --git a/dtool/src/interrogatedb/interrogateComponent.h b/dtool/src/interrogatedb/interrogateComponent.h deleted file mode 100644 index 25557697567..00000000000 --- a/dtool/src/interrogatedb/interrogateComponent.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateComponent.h - * @author drose - * @date 2000-08-08 - */ - -#ifndef INTERROGATECOMPONENT_H -#define INTERROGATECOMPONENT_H - -#include "dtoolbase.h" - -#include "interrogate_interface.h" -#include "interrogate_request.h" - -#include - -class IndexRemapper; - -/** - * The base class for things that are part of the interrogate database. This - * includes types, functions, and function wrappers. - */ -class EXPCL_INTERROGATEDB InterrogateComponent { -public: - INLINE InterrogateComponent(InterrogateModuleDef *def = nullptr); - INLINE InterrogateComponent(const InterrogateComponent ©); - INLINE void operator = (const InterrogateComponent ©); - - INLINE bool has_library_name() const; - INLINE const char *get_library_name() const; - - INLINE bool has_module_name() const; - INLINE const char *get_module_name() const; - - INLINE bool has_name() const; - INLINE const std::string &get_name() const; - - INLINE int get_num_alt_names() const; - INLINE const std::string &get_alt_name(int n) const; - - void output(std::ostream &out) const; - void input(std::istream &in); - -protected: - static std::string _empty_string; - -private: - InterrogateModuleDef *_def; - std::string _name; - - typedef std::vector Strings; - Strings _alt_names; - - friend class InterrogateBuilder; - friend class FunctionRemap; -}; - -#include "interrogateComponent.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogateDatabase.I b/dtool/src/interrogatedb/interrogateDatabase.I deleted file mode 100644 index cf15d962bf8..00000000000 --- a/dtool/src/interrogatedb/interrogateDatabase.I +++ /dev/null @@ -1,89 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateDatabase.I - * @author drose - * @date 2000-08-01 - */ - -/** - * Checks that all the latest data for all the libraries have been loaded. - * Loads them if not. - */ -INLINE void InterrogateDatabase:: -check_latest() { - if (!_requests.empty()) { - load_latest(); - } -} - -/** - * Returns the TypeIndex associated with the first type found with the given - * name, or 0 if no type has this name. - */ -INLINE TypeIndex InterrogateDatabase:: -lookup_type_by_name(const std::string &name) { - check_latest(); - return lookup(name, _types_by_name, LT_type_name, - &InterrogateDatabase::freshen_types_by_name); -} - -/** - * Returns the TypeIndex associated with the first type found with the given - * scoped name, or 0 if no type has this name. - */ -INLINE TypeIndex InterrogateDatabase:: -lookup_type_by_scoped_name(const std::string &name) { - check_latest(); - return lookup(name, _types_by_scoped_name, LT_type_scoped_name, - &InterrogateDatabase::freshen_types_by_scoped_name); -} - -/** - * Returns the TypeIndex associated with the first type found with the given - * true name, or 0 if no type has this name. - */ -INLINE TypeIndex InterrogateDatabase:: -lookup_type_by_true_name(const std::string &name) { - check_latest(); - return lookup(name, _types_by_true_name, LT_type_true_name, - &InterrogateDatabase::freshen_types_by_true_name); -} - -/** - * Returns the ManifestIndex associated with the first manifest found with the - * given name, or 0 if no manifest has this name. - */ -INLINE ManifestIndex InterrogateDatabase:: -lookup_manifest_by_name(const std::string &name) { - check_latest(); - return lookup(name, _manifests_by_name, LT_manifest_name, - &InterrogateDatabase::freshen_manifests_by_name); -} - -/** - * Returns the ElementIndex associated with the first element found with the - * given name, or 0 if no element has this name. - */ -INLINE ElementIndex InterrogateDatabase:: -lookup_element_by_name(const std::string &name) { - check_latest(); - return lookup(name, _elements_by_name, LT_element_name, - &InterrogateDatabase::freshen_elements_by_name); -} - -/** - * Returns the ElementIndex associated with the first element found with the - * given scoped name, or 0 if no element has this name. - */ -INLINE ElementIndex InterrogateDatabase:: -lookup_element_by_scoped_name(const std::string &name) { - check_latest(); - return lookup(name, _elements_by_scoped_name, LT_element_scoped_name, - &InterrogateDatabase::freshen_elements_by_scoped_name); -} diff --git a/dtool/src/interrogatedb/interrogateDatabase.cxx b/dtool/src/interrogatedb/interrogateDatabase.cxx deleted file mode 100644 index afdb7a11f7f..00000000000 --- a/dtool/src/interrogatedb/interrogateDatabase.cxx +++ /dev/null @@ -1,1330 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateDatabase.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "interrogateDatabase.h" -#include "config_interrogatedb.h" -#include "indexRemapper.h" -#include "interrogate_datafile.h" - -using std::map; -using std::string; - -InterrogateDatabase *InterrogateDatabase::_global_ptr = nullptr; -int InterrogateDatabase::_file_major_version = 0; -int InterrogateDatabase::_file_minor_version = 0; -int InterrogateDatabase::_current_major_version = 3; -int InterrogateDatabase::_current_minor_version = 3; - -/** - * - */ -InterrogateDatabase:: -InterrogateDatabase() { - _error_flag = false; - _next_index = 1; - _lookups_fresh = 0; -} - -/** - * Returns the global pointer to the one InterrogateDatabase. - */ -InterrogateDatabase *InterrogateDatabase:: -get_ptr() { - if (_global_ptr == nullptr) { - if (interrogatedb_cat->is_debug()) { - interrogatedb_cat->debug() - << "Creating interrogate database\n"; - } - _global_ptr = new InterrogateDatabase; - } - return _global_ptr; -} - -/** - * Requests that the interrogate data for the given module be made available. - * The function pointers will be made available immediately, while the - * database file will be read later, the next time someone asks for - * interrogate data that requires it. - */ -void InterrogateDatabase:: -request_module(InterrogateModuleDef *def) { - if (interrogatedb_cat->is_debug()) { - if (def->library_name == nullptr) { - interrogatedb_cat->debug() - << "Got interrogate data for anonymous module\n"; - } else { - interrogatedb_cat->debug() - << "Got interrogate data for module " << def->library_name << "\n"; - } - } - - int num_indices = def->next_index - def->first_index; - if (num_indices > 0) { - // If the module def has any definitions--any index numbers used--assign - // it to its own unique range of index numbers. - def->first_index = _next_index; - _next_index += num_indices; - def->next_index = _next_index; - - // Assign a reference to the module def by index number. When we need to - // look up a function by its index number, we'll be able to use this. - _modules.push_back(def); - } - - if (def->num_unique_names > 0 && def->library_name != nullptr) { - // Define a lookup by hash for this module, mainly so we can look up - // functions by their unique names. - _modules_by_hash[def->library_hash_name] = def; - } - - if (def->database_filename != nullptr) { - _requests.push_back(def); - } -} - -/** - * Returns the global error flag. This will be set true if there was some - * problem importing the database (e.g. cannot find an .in file), or false if - * everything is ok. - */ -bool InterrogateDatabase:: -get_error_flag() { - return _error_flag; -} - -/** - * Returns the total number of "global" types known to the interrogate - * database. These are types defined at the global level that should be - * considered for exporting, but not the incidental types (like pointers, - * etc.) that must be defined to support these. - */ -int InterrogateDatabase:: -get_num_global_types() { - check_latest(); - return _global_types.size(); -} - -/** - * Returns the index of the nth global type known to the interrogate database. - */ -TypeIndex InterrogateDatabase:: -get_global_type(int n) { - check_latest(); - if (n >= 0 && n < (int)_global_types.size()) { - return _global_types[n]; - } - return 0; -} - -/** - * Returns the total number of types known to the interrogate database. This - * includes all known types, global as well as incidental. See also - * get_num_global_types(). - */ -int InterrogateDatabase:: -get_num_all_types() { - check_latest(); - return _all_types.size(); -} - -/** - * Returns the index of the nth type known to the interrogate database. - */ -TypeIndex InterrogateDatabase:: -get_all_type(int n) { - check_latest(); - if (n >= 0 && n < (int)_all_types.size()) { - return _all_types[n]; - } - return 0; -} - -/** - * Returns the total number of global functions known to the interrogate - * database. These are functions defined at the global level, e.g. non- - * member functions. - */ -int InterrogateDatabase:: -get_num_global_functions() { - check_latest(); - return _global_functions.size(); -} - -/** - * Returns the index of the nth global function known to the interrogate - * database. - */ -FunctionIndex InterrogateDatabase:: -get_global_function(int n) { - check_latest(); - if (n >= 0 && n < (int)_global_functions.size()) { - return _global_functions[n]; - } - return 0; -} - -/** - * Returns the total number of functions known to the interrogate database. - * This includes all known functions, global, method, or synthesized. See - * also get_num_global_functions(). - */ -int InterrogateDatabase:: -get_num_all_functions() { - check_latest(); - return _all_functions.size(); -} - -/** - * Returns the index of the nth function known to the interrogate database. - */ -FunctionIndex InterrogateDatabase:: -get_all_function(int n) { - check_latest(); - if (n >= 0 && n < (int)_all_functions.size()) { - return _all_functions[n]; - } - return 0; -} - -/** - * Returns the total number of global manifest constants known to the - * interrogate database. - */ -int InterrogateDatabase:: -get_num_global_manifests() { - check_latest(); - return _global_manifests.size(); -} - -/** - * Returns the index of the nth global manifest constant known to the - * interrogate database. - */ -ManifestIndex InterrogateDatabase:: -get_global_manifest(int n) { - check_latest(); - if (n >= 0 && n < (int)_global_manifests.size()) { - return _global_manifests[n]; - } - return 0; -} - -/** - * Returns the total number of global data elements known to the interrogate - * database. - */ -int InterrogateDatabase:: -get_num_global_elements() { - check_latest(); - return _global_elements.size(); -} - -/** - * Returns the index of the nth global data element known to the interrogate - * database. - */ -ElementIndex InterrogateDatabase:: -get_global_element(int n) { - check_latest(); - if (n >= 0 && n < (int)_global_elements.size()) { - return _global_elements[n]; - } - return 0; -} - -/** - * Returns the type associated with the given TypeIndex, if there is one. - */ -const InterrogateType &InterrogateDatabase:: -get_type(TypeIndex type) { - static InterrogateType bogus_type; - - check_latest(); - TypeMap::const_iterator ti; - ti = _type_map.find(type); - if (ti == _type_map.end()) { - return bogus_type; - } - return (*ti).second; -} - -/** - * Returns the function associated with the given FunctionIndex, if there is - * one. - */ -const InterrogateFunction &InterrogateDatabase:: -get_function(FunctionIndex function) { - static InterrogateFunction bogus_function; - - check_latest(); - FunctionMap::const_iterator fi; - fi = _function_map.find(function); - if (fi == _function_map.end()) { - return bogus_function; - } - return *(*fi).second; -} - -/** - * Returns the function wrapper associated with the given - * FunctionWrapperIndex, if there is one. - */ -const InterrogateFunctionWrapper &InterrogateDatabase:: -get_wrapper(FunctionWrapperIndex wrapper) { - static InterrogateFunctionWrapper bogus_wrapper; - - check_latest(); - FunctionWrapperMap::const_iterator wi; - wi = _wrapper_map.find(wrapper); - if (wi == _wrapper_map.end()) { - return bogus_wrapper; - } - return (*wi).second; -} - -/** - * Returns the manifest constant associated with the given ManifestIndex, if - * there is one. - */ -const InterrogateManifest &InterrogateDatabase:: -get_manifest(ManifestIndex manifest) { - static InterrogateManifest bogus_manifest; - - check_latest(); - ManifestMap::const_iterator mi; - mi = _manifest_map.find(manifest); - if (mi == _manifest_map.end()) { - return bogus_manifest; - } - return (*mi).second; -} - -/** - * Returns the data element associated with the given ElementIndex, if there - * is one. - */ -const InterrogateElement &InterrogateDatabase:: -get_element(ElementIndex element) { - static InterrogateElement bogus_element; - - check_latest(); - ElementMap::const_iterator ei; - ei = _element_map.find(element); - if (ei == _element_map.end()) { - return bogus_element; - } - return (*ei).second; -} - -/** - * Returns the make_seq associated with the given MakeSeqIndex, if there is - * one. - */ -const InterrogateMakeSeq &InterrogateDatabase:: -get_make_seq(MakeSeqIndex make_seq) { - static InterrogateMakeSeq bogus_make_seq; - - check_latest(); - MakeSeqMap::const_iterator si; - si = _make_seq_map.find(make_seq); - if (si == _make_seq_map.end()) { - return bogus_make_seq; - } - return (*si).second; -} - -/** - * Erases the type from the database. - */ -void InterrogateDatabase:: -remove_type(TypeIndex type) { - _type_map.erase(type); -} - -/** - * Returns the function pointer associated with the given function wrapper, if - * it has a pointer available. Returns NULL if the pointer is not available. - */ -void *InterrogateDatabase:: -get_fptr(FunctionWrapperIndex wrapper) { - InterrogateModuleDef *def; - int module_index; - if (find_module(wrapper, def, module_index)) { - if (module_index >= 0 && module_index < def->num_fptrs) { - return def->fptrs[module_index]; - } - } - return nullptr; -} - -/** - * Looks up the function wrapper corresponding to the given unique name, if - * available. Returns the corresponding wrapper index, or 0 if no such - * wrapper is found. - */ -FunctionWrapperIndex InterrogateDatabase:: -get_wrapper_by_unique_name(const string &unique_name) { - // First, split the unique_name into a library_hash_name and a - // wrapper_hash_name. - - // The first four characters are always the library_name. - string library_hash_name = unique_name.substr(0, 4); - string wrapper_hash_name = unique_name.substr(4); - - // Is the library_name defined? - ModulesByHash::const_iterator mi; - mi = _modules_by_hash.find(library_hash_name); - if (mi == _modules_by_hash.end()) { - return 0; - } - - InterrogateModuleDef *def = (*mi).second; - int index_offset = - binary_search_wrapper_hash(def->unique_names, - def->unique_names + def->num_unique_names, - wrapper_hash_name); - if (index_offset >= 0) { - return def->first_index + index_offset; - } - - return 0; -} - -/** - * Returns the major version number of the interrogate database file currently - * being read. - */ -int InterrogateDatabase:: -get_file_major_version() { - return _file_major_version; -} - -/** - * Returns the minor version number of the interrogate database file currently - * being read. - */ -int InterrogateDatabase:: -get_file_minor_version() { - return _file_minor_version; -} - -/** - * Returns the major version number currently expected in interrogate database - * files generated by this code base. - */ -int InterrogateDatabase:: -get_current_major_version() { - return _current_major_version; -} - -/** - * Returns the minor version number currently expected in interrogate database - * files generated by this code base. - */ -int InterrogateDatabase:: -get_current_minor_version() { - return _current_minor_version; -} - -/** - * Sets the global error flag. This should be set true if there was some - * problem importing the database (e.g. cannot find an .in file). - */ -void InterrogateDatabase:: -set_error_flag(bool error_flag) { - _error_flag = error_flag; -} - -/** - * Returns a new index number suitable for the next thing, that will not be - * shared with any other index numbers. - */ -int InterrogateDatabase:: -get_next_index() { - return _next_index++; -} - -/** - * Adds the indicated type to the database at the given index number. - */ -void InterrogateDatabase:: -add_type(TypeIndex index, const InterrogateType &type) { - assert(index != 0); - bool inserted = - _type_map.insert(TypeMap::value_type(index, type)).second; - - if (!inserted) { - // If there was already a type at that index, maybe it was a forward - // reference. If its _fully_defined bit isn't set, then it's ok. - InterrogateType &old_type = _type_map[index]; - assert(!old_type.is_fully_defined()); - - // It was a forward reference. Merge it with the new one. - old_type.merge_with(type); - } - - if (type.is_global()) { - _global_types.push_back(index); - } - _all_types.push_back(index); -} - -/** - * Adds the indicated function to the database at the given index number. - */ -void InterrogateDatabase:: -add_function(FunctionIndex index, InterrogateFunction *function) { - bool inserted = - _function_map.insert(FunctionMap::value_type(index, function)).second; - assert(inserted); - - if (function->is_global()) { - _global_functions.push_back(index); - } - _all_functions.push_back(index); -} - -/** - * Adds the indicated function wrapper to the database at the given index - * number. - */ -void InterrogateDatabase:: -add_wrapper(FunctionWrapperIndex index, - const InterrogateFunctionWrapper &wrapper) { - bool inserted = - _wrapper_map.insert(FunctionWrapperMap::value_type(index, wrapper)).second; - assert(inserted); -} - -/** - * Adds the indicated manifest constant to the database at the given index - * number. - */ -void InterrogateDatabase:: -add_manifest(ManifestIndex index, const InterrogateManifest &manifest) { - bool inserted = - _manifest_map.insert(ManifestMap::value_type(index, manifest)).second; - assert(inserted); - - _global_manifests.push_back(index); -} - -/** - * Adds the indicated data element to the database at the given index number. - */ -void InterrogateDatabase:: -add_element(ElementIndex index, const InterrogateElement &element) { - bool inserted = - _element_map.insert(ElementMap::value_type(index, element)).second; - assert(inserted); - - if (element.is_global()) { - _global_elements.push_back(index); - } -} - -/** - * Adds the indicated make_seq to the database at the given index number. - */ -void InterrogateDatabase:: -add_make_seq(MakeSeqIndex index, const InterrogateMakeSeq &make_seq) { - bool inserted = - _make_seq_map.insert(MakeSeqMap::value_type(index, make_seq)).second; - assert(inserted); -} - -/** - * Returns a non-const reference to the indicated type, allowing the user to - * update it. - */ -InterrogateType &InterrogateDatabase:: -update_type(TypeIndex type) { - assert(type != 0); - check_latest(); - return _type_map[type]; -} - -/** - * Returns a non-const reference to the indicated function, allowing the user - * to update it. - */ -InterrogateFunction &InterrogateDatabase:: -update_function(FunctionIndex function) { - check_latest(); - return *_function_map[function]; -} - -/** - * Returns a non-const reference to the indicated function wrapper, allowing - * the user to update it. - */ -InterrogateFunctionWrapper &InterrogateDatabase:: -update_wrapper(FunctionWrapperIndex wrapper) { - check_latest(); - return _wrapper_map[wrapper]; -} - -/** - * Returns a non-const reference to the indicated manifest constant, allowing - * the user to update it. - */ -InterrogateManifest &InterrogateDatabase:: -update_manifest(ManifestIndex manifest) { - check_latest(); - return _manifest_map[manifest]; -} - -/** - * Returns a non-const reference to the indicated data element, allowing the - * user to update it. - */ -InterrogateElement &InterrogateDatabase:: -update_element(ElementIndex element) { - check_latest(); - return _element_map[element]; -} - -/** - * Returns a non-const reference to the indicated make_seq, allowing the user - * to update it. - */ -InterrogateMakeSeq &InterrogateDatabase:: -update_make_seq(MakeSeqIndex make_seq) { - check_latest(); - return _make_seq_map[make_seq]; -} - -/** - * Resequences all of the various index numbers so that all of the functions - * start at first_index and increment consecutively from there, and then all - * of the types follow. Returns the next available index number. - */ -int InterrogateDatabase:: -remap_indices(int first_index) { - IndexRemapper remap; - return remap_indices(first_index, remap); -} - -/** - * This flavor of remap_indices() accepts a map that should be empty on - * initial call, and will be filled with the mapping of old index number to - * new index number. This allows the caller to update its own data structures - * to match the new index numbers. - */ -int InterrogateDatabase:: -remap_indices(int first_index, IndexRemapper &remap) { - remap.clear(); - - // First, build up the complete map. - - // Get the wrapper indices first. This is important, because the - // InterrogateBuilder wants these to be first, and consecutive. - FunctionWrapperMap new_wrapper_map; - FunctionWrapperMap::iterator wi; - for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) { - remap.add_mapping((*wi).first, first_index); - new_wrapper_map[first_index] = (*wi).second; - first_index++; - } - - // Everything else can follow; it doesn't matter so much. - FunctionMap new_function_map; - FunctionMap::iterator fi; - for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) { - remap.add_mapping((*fi).first, first_index); - new_function_map[first_index] = (*fi).second; - first_index++; - } - - TypeMap new_type_map; - TypeMap::iterator ti; - for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) { - assert((*ti).first != 0); - remap.add_mapping((*ti).first, first_index); - new_type_map[first_index] = (*ti).second; - first_index++; - } - - ManifestMap new_manifest_map; - ManifestMap::iterator mi; - for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) { - remap.add_mapping((*mi).first, first_index); - new_manifest_map[first_index] = (*mi).second; - first_index++; - } - - ElementMap new_element_map; - ElementMap::iterator ei; - for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) { - remap.add_mapping((*ei).first, first_index); - new_element_map[first_index] = (*ei).second; - first_index++; - } - - MakeSeqMap new_make_seq_map; - MakeSeqMap::iterator si; - for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) { - remap.add_mapping((*si).first, first_index); - new_make_seq_map[first_index] = (*si).second; - first_index++; - } - - _next_index = first_index; - - _wrapper_map.swap(new_wrapper_map); - _function_map.swap(new_function_map); - _type_map.swap(new_type_map); - _manifest_map.swap(new_manifest_map); - _element_map.swap(new_element_map); - _make_seq_map.swap(new_make_seq_map); - - // Then, go back through and update all of the internal references. - for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) { - (*wi).second.remap_indices(remap); - } - for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) { - (*fi).second->remap_indices(remap); - } - for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) { - (*ti).second.remap_indices(remap); - } - for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) { - (*mi).second.remap_indices(remap); - } - for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) { - (*ei).second.remap_indices(remap); - } - for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) { - (*si).second.remap_indices(remap); - } - GlobalFunctions::iterator gfi; - for (gfi = _global_functions.begin(); gfi != _global_functions.end(); ++gfi) { - (*gfi) = remap.map_from(*gfi); - } - for (gfi = _all_functions.begin(); gfi != _all_functions.end(); ++gfi) { - (*gfi) = remap.map_from(*gfi); - } - GlobalTypes::iterator gti; - for (gti = _global_types.begin(); gti != _global_types.end(); ++gti) { - (*gti) = remap.map_from(*gti); - } - for (gti = _all_types.begin(); gti != _all_types.end(); ++gti) { - (*gti) = remap.map_from(*gti); - } - GlobalManifests::iterator gmi; - for (gmi = _global_manifests.begin(); gmi != _global_manifests.end(); ++gmi) { - (*gmi) = remap.map_from(*gmi); - } - GlobalElements::iterator gei; - for (gei = _global_elements.begin(); gei != _global_elements.end(); ++gei) { - (*gei) = remap.map_from(*gei); - } - - return _next_index; -} - -/** - * Writes the database to the indicated stream for later reading. - */ -void InterrogateDatabase:: -write(std::ostream &out, InterrogateModuleDef *def) const { - // Write out the file header. - out << def->file_identifier << "\n" - << _current_major_version << " " << _current_minor_version << "\n"; - - // Write out the module definition. - idf_output_string(out, def->library_name); - idf_output_string(out, def->library_hash_name); - idf_output_string(out, def->module_name); - out << "\n"; - - // Now write out the components. - - out << _function_map.size() << "\n"; - FunctionMap::const_iterator fi; - for (fi = _function_map.begin(); fi != _function_map.end(); ++fi) { - out << (*fi).first << " " << *(*fi).second << "\n"; - } - - out << _wrapper_map.size() << "\n"; - FunctionWrapperMap::const_iterator wi; - for (wi = _wrapper_map.begin(); wi != _wrapper_map.end(); ++wi) { - out << (*wi).first << " " << (*wi).second << "\n"; - } - - out << _type_map.size() << "\n"; - TypeMap::const_iterator ti; - for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) { - out << (*ti).first << " " << (*ti).second << "\n"; - } - - out << _manifest_map.size() << "\n"; - ManifestMap::const_iterator mi; - for (mi = _manifest_map.begin(); mi != _manifest_map.end(); ++mi) { - out << (*mi).first << " " << (*mi).second << "\n"; - } - - out << _element_map.size() << "\n"; - ElementMap::const_iterator ei; - for (ei = _element_map.begin(); ei != _element_map.end(); ++ei) { - out << (*ei).first << " " << (*ei).second << "\n"; - } - - out << _make_seq_map.size() << "\n"; - MakeSeqMap::const_iterator si; - for (si = _make_seq_map.begin(); si != _make_seq_map.end(); ++si) { - out << (*si).first << " " << (*si).second << "\n"; - } -} - -/** - * Reads a database from the indicated stream, associated with the indicated - * module definition and merges it with any existing data in the database, - * according to the expected index numbers specified in the module def. The - * header information has already been read. - * - * Returns true if the file is read successfully, false if there is an error. - */ -bool InterrogateDatabase:: -read(std::istream &in, InterrogateModuleDef *def) { - InterrogateDatabase temp; - if (!temp.read_new(in, def)) { - return false; - } - - if (def->first_index == 0 && def->next_index == 0) { - _next_index = temp.remap_indices(_next_index); - - } else { - int next = temp.remap_indices(def->first_index); - if (next != def->next_index) { - interrogatedb_cat->error() - << "Module database file " << def->database_filename - << " is out of date.\n"; - return false; - } - } - - merge_from(temp); - return true; -} - -/** - * Reads in the latest interrogate data. - */ -void InterrogateDatabase:: -load_latest() { - const DSearchPath &searchpath = interrogatedb_path; - - Requests copy_requests; - copy_requests.swap(_requests); - - Requests::const_iterator ri; - for (ri = copy_requests.begin(); ri != copy_requests.end(); ++ri) { - InterrogateModuleDef *def = (*ri); - - if (def->database_filename != nullptr) { - Filename filename = def->database_filename; - Filename pathname = filename; - if (!pathname.empty() && pathname[0] != '/') { - pathname = searchpath.find_file(pathname); - } - - if (pathname.empty()) { - interrogatedb_cat->error() - << "Unable to find " << filename << " on " << searchpath << "\n"; - set_error_flag(true); - - } else { - - pifstream input; - pathname.set_text(); - if (!pathname.open_read(input)) { - interrogatedb_cat->error() << "Unable to read " << pathname << ".\n"; - set_error_flag(true); - - } else { - int file_identifier; - input >> file_identifier - >> _file_major_version >> _file_minor_version; - - if (def->file_identifier != 0 && - file_identifier != def->file_identifier) { - interrogatedb_cat->warning() - << "Interrogate data in " << pathname - << " is out of sync with the compiled-in data" - << " (" << file_identifier << " != " << def->file_identifier << ").\n"; - set_error_flag(true); - } - - if (_file_major_version != _current_major_version || - _file_minor_version > _current_minor_version) { - interrogatedb_cat->error() - << "Cannot read interrogate data in " << pathname - << "; database is version " << _file_major_version << "." - << _file_minor_version << " while we are expecting " - << _current_major_version << "." << _current_minor_version - << ".\n"; - set_error_flag(true); - - } else { - if (interrogatedb_cat->is_debug()) { - interrogatedb_cat->debug() - << "Reading " << filename << "\n"; - } - if (!read(input, def)) { - interrogatedb_cat->error() - << "Error reading " << pathname << ".\n"; - set_error_flag(true); - } - } - } - } - } - } - - _requests.clear(); -} - -/** - * Reads from the indicated stream (the header information has already been - * read) into the newly-created database. It is an error if the database - * already has some data in it. - */ -bool InterrogateDatabase:: -read_new(std::istream &in, InterrogateModuleDef *def) { - // We've already read the header. Read the module definition. - idf_input_string(in, def->library_name); - idf_input_string(in, def->library_hash_name); - idf_input_string(in, def->module_name); - - // Now read all of the components. - - { // Functions. - int num_functions; - in >> num_functions; - if (in.fail()) { - return false; - } - - while (num_functions > 0) { - FunctionIndex index; - InterrogateFunction *function = new InterrogateFunction(def); - in >> index >> *function; - if (in.fail()) { - delete function; - return false; - } - - add_function(index, function); - num_functions--; - } - } - - { // Wrappers. - int num_wrappers; - in >> num_wrappers; - if (in.fail()) { - return false; - } - - while (num_wrappers > 0) { - FunctionWrapperIndex index; - InterrogateFunctionWrapper wrapper(def); - in >> index >> wrapper; - if (in.fail()) { - return false; - } - - add_wrapper(index, wrapper); - num_wrappers--; - } - } - - { // Types. - int num_types; - in >> num_types; - if (in.fail()) { - return false; - } - - while (num_types > 0) { - TypeIndex index; - InterrogateType type(def); - in >> index >> type; - if (in.fail()) { - return false; - } - - add_type(index, type); - num_types--; - - // Older versions of interrogate were not setting these flags. - const InterrogateType &itype = get_type(index); - FunctionIndex dtor = itype.get_destructor(); - if (dtor != 0) { - update_function(dtor)._flags |= InterrogateFunction::F_destructor; - } - for (int i = 0; i < itype.number_of_constructors(); ++i) { - FunctionIndex ctor = itype.get_constructor(i); - update_function(ctor)._flags |= InterrogateFunction::F_constructor; - } - } - } - - { // Manifests. - int num_manifests; - in >> num_manifests; - if (in.fail()) { - return false; - } - - while (num_manifests > 0) { - ManifestIndex index; - InterrogateManifest manifest(def); - in >> index >> manifest; - if (in.fail()) { - return false; - } - - add_manifest(index, manifest); - num_manifests--; - } - } - - { // Elements. - int num_elements; - in >> num_elements; - if (in.fail()) { - return false; - } - - while (num_elements > 0) { - ElementIndex index; - InterrogateElement element(def); - in >> index >> element; - if (in.fail()) { - return false; - } - - add_element(index, element); - num_elements--; - } - } - - { // MakeSeqs. - int num_make_seqs; - in >> num_make_seqs; - if (in.fail()) { - return false; - } - - while (num_make_seqs > 0) { - MakeSeqIndex index; - InterrogateMakeSeq make_seq(def); - in >> index >> make_seq; - if (in.fail()) { - return false; - } - - add_make_seq(index, make_seq); - num_make_seqs--; - } - } - - return true; -} - -/** - * Copies all the data from the indicated database into this one. It is an - * error if any index numbers are shared between the two databases. - */ -void InterrogateDatabase:: -merge_from(const InterrogateDatabase &other) { - // We want to collapse shared types together. - IndexRemapper remap; - - // First, we need to build a set of types by name, so we know what types we - // already have. - map types_by_name; - - TypeMap::const_iterator ti; - for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) { - const InterrogateType &type = (*ti).second; - if (type.has_true_name()) { - types_by_name[type.get_true_name()] = (*ti).first; - } - } - - // Now go through the other set of types and determine the mapping into this - // set. - for (ti = other._type_map.begin(); ti != other._type_map.end(); ++ti) { - TypeIndex other_type_index = (*ti).first; - const InterrogateType &other_type = (*ti).second; - - if (other_type.has_name()) { - map::iterator ni; - ni = types_by_name.find(other_type.get_true_name()); - if (ni != types_by_name.end()) { - // Here's a type that we seem to have in common! We'll have to merge - // them. - TypeIndex this_type_index = (*ni).second; - remap.add_mapping(other_type_index, this_type_index); - } - } - } - - // Now that we know the full type-to-type mapping, we can copy the new - // types, one at a time. - for (ti = other._type_map.begin(); ti != other._type_map.end(); ++ti) { - TypeIndex other_type_index = (*ti).first; - const InterrogateType &other_type = (*ti).second; - - if (!remap.in_map(other_type_index)) { - // Here's a new type. - add_type(other_type_index, other_type); - update_type(other_type_index).remap_indices(remap); - - } else { - // Here's a type to merge. - TypeIndex this_type_index = remap.map_from(other_type_index); - - InterrogateType &this_type = update_type(this_type_index); - if (!this_type.is_global() && other_type.is_global()) { - // If the type is about to become global, we need to add it to our - // global_types list. - _global_types.push_back(this_type_index); - } - - InterrogateType merge_type = other_type; - merge_type.remap_indices(remap); - this_type.merge_with(merge_type); - } - } - - // And copy all of the functions, wrappers, manifests, and elements. - FunctionMap::const_iterator fi; - for (fi = other._function_map.begin(); - fi != other._function_map.end(); - ++fi) { - FunctionIndex other_function_index = (*fi).first; - InterrogateFunction *other_function = (*fi).second; - add_function(other_function_index, other_function); - update_function(other_function_index).remap_indices(remap); - } - - FunctionWrapperMap::const_iterator wi; - for (wi = other._wrapper_map.begin(); - wi != other._wrapper_map.end(); - ++wi) { - FunctionWrapperIndex other_wrapper_index = (*wi).first; - const InterrogateFunctionWrapper &other_wrapper = (*wi).second; - add_wrapper(other_wrapper_index, other_wrapper); - update_wrapper(other_wrapper_index).remap_indices(remap); - } - - ManifestMap::const_iterator mi; - for (mi = other._manifest_map.begin(); - mi != other._manifest_map.end(); - ++mi) { - ManifestIndex other_manifest_index = (*mi).first; - const InterrogateManifest &other_manifest = (*mi).second; - add_manifest(other_manifest_index, other_manifest); - update_manifest(other_manifest_index).remap_indices(remap); - } - - ElementMap::const_iterator ei; - for (ei = other._element_map.begin(); - ei != other._element_map.end(); - ++ei) { - ElementIndex other_element_index = (*ei).first; - const InterrogateElement &other_element = (*ei).second; - add_element(other_element_index, other_element); - update_element(other_element_index).remap_indices(remap); - } - - MakeSeqMap::const_iterator si; - for (si = other._make_seq_map.begin(); - si != other._make_seq_map.end(); - ++si) { - MakeSeqIndex other_make_seq_index = (*si).first; - const InterrogateMakeSeq &other_make_seq = (*si).second; - add_make_seq(other_make_seq_index, other_make_seq); - update_make_seq(other_make_seq_index).remap_indices(remap); - } - - _lookups_fresh = 0; -} - -/** - * Looks up the wrapper definition in the set of module defs that are loaded - * in at runtime and represent the part of the interrogate database that's - * compiled in. - * - * If the wrapper definition is not found, returns false. If it is found, - * returns true and sets def and module_index to the particular module and the - * index within the module where the wrapper is defined. - */ -bool InterrogateDatabase:: -find_module(FunctionWrapperIndex wrapper, InterrogateModuleDef *&def, - int &module_index) { - if (_modules.empty()) { - return false; - } - - int mi = binary_search_module(0, _modules.size(), wrapper); - assert(mi >= 0 && mi < (int)_modules.size()); - def = _modules[mi]; - module_index = wrapper - def->first_index; - - return (wrapper < def->next_index); -} - -/** - * Searches for the function module that includes the given function index by - * binary search. - */ -int InterrogateDatabase:: -binary_search_module(int begin, int end, FunctionIndex function) { - int mid = begin + (end - begin) / 2; - if (mid == begin) { - return mid; - } - - int index = _modules[mid]->first_index; - if (index <= function) { - return binary_search_module(mid, end, function); - - } else { - return binary_search_module(begin, mid, function); - } -} - -/** - * Searches for the particular function wrapper's hash name within a given - * module. Returns the index number local to the module, or -1 if it is not - * found. - */ -int InterrogateDatabase:: -binary_search_wrapper_hash(InterrogateUniqueNameDef *begin, - InterrogateUniqueNameDef *end, - const string &wrapper_hash_name) { - if (end <= begin) { - return -1; - } - - InterrogateUniqueNameDef *mid = begin + (end - begin) / 2; - string name = mid->name; - if (name < wrapper_hash_name) { - return binary_search_wrapper_hash(mid, end, wrapper_hash_name); - - } else if (wrapper_hash_name < name) { - return binary_search_wrapper_hash(begin, mid, wrapper_hash_name); - - } else { - return mid->index_offset; - } -} - -/** - * Builds up the lookup of types by name. - */ -void InterrogateDatabase:: -freshen_types_by_name() { - _types_by_name.clear(); - TypeMap::const_iterator ti; - for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) { - _types_by_name[(*ti).second.get_name()] = (*ti).first; - } -} - -/** - * Builds up the lookup of types by scoped name. - */ -void InterrogateDatabase:: -freshen_types_by_scoped_name() { - _types_by_scoped_name.clear(); - TypeMap::const_iterator ti; - for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) { - _types_by_scoped_name[(*ti).second.get_scoped_name()] = (*ti).first; - } -} - -/** - * Builds up the lookup of types by true name. - */ -void InterrogateDatabase:: -freshen_types_by_true_name() { - _types_by_true_name.clear(); - TypeMap::const_iterator ti; - for (ti = _type_map.begin(); ti != _type_map.end(); ++ti) { - _types_by_true_name[(*ti).second.get_true_name()] = (*ti).first; - } -} - -/** - * Builds up the lookup of manifests by name. - */ -void InterrogateDatabase:: -freshen_manifests_by_name() { - _manifests_by_name.clear(); - ManifestMap::const_iterator ti; - for (ti = _manifest_map.begin(); ti != _manifest_map.end(); ++ti) { - _manifests_by_name[(*ti).second.get_name()] = (*ti).first; - } -} - -/** - * Builds up the lookup of elements by name. - */ -void InterrogateDatabase:: -freshen_elements_by_name() { - _elements_by_name.clear(); - ElementMap::const_iterator ti; - for (ti = _element_map.begin(); ti != _element_map.end(); ++ti) { - _elements_by_name[(*ti).second.get_name()] = (*ti).first; - } -} - -/** - * Builds up the lookup of elements by scoped name. - */ -void InterrogateDatabase:: -freshen_elements_by_scoped_name() { - _elements_by_scoped_name.clear(); - ElementMap::const_iterator ti; - for (ti = _element_map.begin(); ti != _element_map.end(); ++ti) { - _elements_by_scoped_name[(*ti).second.get_scoped_name()] = (*ti).first; - } -} - -/** - * Looks up a type, manifest, or element in the indicated lookup table by - * name. This is an internal support function. - */ -int InterrogateDatabase:: -lookup(const string &name, Lookup &lookup, LookupType type, - void (InterrogateDatabase::*freshen)()) { - if ((_lookups_fresh & (int)type) == 0) { - // The lookup table isn't fresh; we need to freshen it. - (this->*freshen)(); - _lookups_fresh |= (int)type; - } - - Lookup::const_iterator li; - li = lookup.find(name); - if (li != lookup.end()) { - return (*li).second; - } - return 0; -} diff --git a/dtool/src/interrogatedb/interrogateDatabase.h b/dtool/src/interrogatedb/interrogateDatabase.h deleted file mode 100644 index 9c60b0318e1..00000000000 --- a/dtool/src/interrogatedb/interrogateDatabase.h +++ /dev/null @@ -1,205 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateDatabase.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef INTERROGATEDATABASE_H -#define INTERROGATEDATABASE_H - -#include "dtoolbase.h" - -#include "interrogate_interface.h" -#include "interrogateType.h" -#include "interrogateFunction.h" -#include "interrogateFunctionWrapper.h" -#include "interrogateManifest.h" -#include "interrogateElement.h" -#include "interrogateMakeSeq.h" -#include "interrogate_request.h" - -#include - -class IndexRemapper; - -/** - * This stores all of the interrogate data and handles reading the data from a - * disk file when necessary. - */ -class EXPCL_INTERROGATEDB InterrogateDatabase { -private: - InterrogateDatabase(); - -public: - static InterrogateDatabase *get_ptr(); - void request_module(InterrogateModuleDef *def); - -public: - // Functions to read the database. - bool get_error_flag(); - - int get_num_global_types(); - TypeIndex get_global_type(int n); - int get_num_all_types(); - TypeIndex get_all_type(int n); - int get_num_global_functions(); - FunctionIndex get_global_function(int n); - int get_num_all_functions(); - FunctionIndex get_all_function(int n); - int get_num_global_manifests(); - ManifestIndex get_global_manifest(int n); - int get_num_global_elements(); - ElementIndex get_global_element(int n); - - const InterrogateType &get_type(TypeIndex type); - const InterrogateFunction &get_function(FunctionIndex function); - const InterrogateFunctionWrapper &get_wrapper(FunctionWrapperIndex wrapper); - const InterrogateManifest &get_manifest(ManifestIndex manifest); - const InterrogateElement &get_element(ElementIndex element); - const InterrogateMakeSeq &get_make_seq(MakeSeqIndex element); - - INLINE TypeIndex lookup_type_by_name(const std::string &name); - INLINE TypeIndex lookup_type_by_scoped_name(const std::string &name); - INLINE TypeIndex lookup_type_by_true_name(const std::string &name); - INLINE ManifestIndex lookup_manifest_by_name(const std::string &name); - INLINE ElementIndex lookup_element_by_name(const std::string &name); - INLINE ElementIndex lookup_element_by_scoped_name(const std::string &name); - - void remove_type(TypeIndex type); - - void *get_fptr(FunctionWrapperIndex wrapper); - - FunctionWrapperIndex get_wrapper_by_unique_name(const std::string &unique_name); - - static int get_file_major_version(); - static int get_file_minor_version(); - static int get_current_major_version(); - static int get_current_minor_version(); - -public: - // Functions to build the database. - void set_error_flag(bool error_flag); - - int get_next_index(); - void add_type(TypeIndex index, const InterrogateType &type); - void add_function(FunctionIndex index, InterrogateFunction *function); - void add_wrapper(FunctionWrapperIndex index, - const InterrogateFunctionWrapper &wrapper); - void add_manifest(ManifestIndex index, const InterrogateManifest &manifest); - void add_element(ElementIndex index, const InterrogateElement &element); - void add_make_seq(MakeSeqIndex index, const InterrogateMakeSeq &make_seq); - - InterrogateType &update_type(TypeIndex type); - InterrogateFunction &update_function(FunctionIndex function); - InterrogateFunctionWrapper &update_wrapper(FunctionWrapperIndex wrapper); - InterrogateManifest &update_manifest(ManifestIndex manifest); - InterrogateElement &update_element(ElementIndex element); - InterrogateMakeSeq &update_make_seq(MakeSeqIndex make_seq); - - int remap_indices(int first_index); - int remap_indices(int first_index, IndexRemapper &remap); - - void write(std::ostream &out, InterrogateModuleDef *def) const; - bool read(std::istream &in, InterrogateModuleDef *def); - -private: - INLINE void check_latest(); - void load_latest(); - - bool read_new(std::istream &in, InterrogateModuleDef *def); - void merge_from(const InterrogateDatabase &other); - - bool find_module(FunctionWrapperIndex wrapper, - InterrogateModuleDef *&def, int &module_index); - int binary_search_module(int begin, int end, FunctionIndex function); - int binary_search_wrapper_hash(InterrogateUniqueNameDef *begin, - InterrogateUniqueNameDef *end, - const std::string &wrapper_hash_name); - - // This data is loaded from the various database files. - typedef std::map TypeMap; - TypeMap _type_map; - typedef std::map FunctionMap; - FunctionMap _function_map; - typedef std::map FunctionWrapperMap; - FunctionWrapperMap _wrapper_map; - - typedef std::map ManifestMap; - ManifestMap _manifest_map; - typedef std::map ElementMap; - ElementMap _element_map; - - typedef std::map MakeSeqMap; - MakeSeqMap _make_seq_map; - - typedef std::vector GlobalTypes; - GlobalTypes _global_types; - GlobalTypes _all_types; - typedef std::vector GlobalFunctions; - GlobalFunctions _global_functions; - GlobalFunctions _all_functions; - typedef std::vector GlobalManifests; - GlobalManifests _global_manifests; - typedef std::vector GlobalElements; - GlobalElements _global_elements; - - // This data is compiled in directly to the shared libraries that we link - // with. - typedef std::vector Modules; - Modules _modules; - typedef std::map ModulesByHash; - ModulesByHash _modules_by_hash; - - // This records the set of database files that are still to be loaded. - typedef std::vector Requests; - Requests _requests; - - bool _error_flag; - int _next_index; - - enum LookupType { - LT_type_name = 0x001, - LT_type_scoped_name = 0x002, - LT_type_true_name = 0x004, - LT_manifest_name = 0x008, - LT_element_name = 0x010, - LT_element_scoped_name = 0x020, - }; - - int _lookups_fresh; - typedef std::map Lookup; - Lookup _types_by_name; - Lookup _types_by_scoped_name; - Lookup _types_by_true_name; - Lookup _manifests_by_name; - Lookup _elements_by_name; - Lookup _elements_by_scoped_name; - - void freshen_types_by_name(); - void freshen_types_by_scoped_name(); - void freshen_types_by_true_name(); - void freshen_manifests_by_name(); - void freshen_elements_by_name(); - void freshen_elements_by_scoped_name(); - - int lookup(const std::string &name, - Lookup &lookup, LookupType type, - void (InterrogateDatabase::*freshen)()); - - static InterrogateDatabase *_global_ptr; - static int _file_major_version; - static int _file_minor_version; - static int _current_major_version; - static int _current_minor_version; -}; - -#include "interrogateDatabase.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogateElement.I b/dtool/src/interrogatedb/interrogateElement.I deleted file mode 100644 index 93e6889b165..00000000000 --- a/dtool/src/interrogatedb/interrogateElement.I +++ /dev/null @@ -1,259 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateElement.I - * @author drose - * @date 2000-08-11 - */ - -/** - * - */ -INLINE InterrogateElement:: -InterrogateElement(InterrogateModuleDef *def) : - InterrogateComponent(def) -{ - _flags = 0; - _type = 0; - _getter = 0; - _setter = 0; - _has_function = 0; - _clear_function = 0; - _del_function = 0; - _insert_function = 0; - _getkey_function = 0; - _length_function = 0; - _make_property = nullptr; -} - -/** - * - */ -INLINE InterrogateElement:: -InterrogateElement(const InterrogateElement ©) { - (*this) = copy; -} - -/** - * - */ -INLINE void InterrogateElement:: -operator = (const InterrogateElement ©) { - InterrogateComponent::operator = (copy); - _flags = copy._flags; - _scoped_name = copy._scoped_name; - _comment = copy._comment; - _type = copy._type; - _getter = copy._getter; - _setter = copy._setter; - _has_function = copy._has_function; - _clear_function = copy._clear_function; - _del_function = copy._del_function; - _insert_function = copy._insert_function; - _getkey_function = copy._getkey_function; - _length_function = copy._length_function; - _make_property = copy._make_property; -} - -/** - * Returns true if the element is marked as 'global'. This means only that it - * should appear in the global element list. - */ -INLINE bool InterrogateElement:: -is_global() const { - return (_flags & F_global) != 0; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_scoped_name() const { - return !_scoped_name.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateElement:: -get_scoped_name() const { - return _scoped_name; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_comment() const { - return !_comment.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateElement:: -get_comment() const { - return _comment; -} - -/** - * - */ -INLINE TypeIndex InterrogateElement:: -get_type() const { - return _type; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_getter() const { - return (_flags & F_has_getter) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_getter() const { - return _getter; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_setter() const { - return (_flags & F_has_setter) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_setter() const { - return _setter; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_has_function() const { - return (_flags & F_has_has_function) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_has_function() const { - return _has_function; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_clear_function() const { - return (_flags & F_has_clear_function) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_clear_function() const { - return _clear_function; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_del_function() const { - return (_flags & F_has_del_function) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_del_function() const { - return _del_function; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_insert_function() const { - return (_flags & F_has_insert_function) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_insert_function() const { - return _insert_function; -} - -/** - * - */ -INLINE bool InterrogateElement:: -has_getkey_function() const { - return (_flags & F_has_getkey_function) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_getkey_function() const { - return _getkey_function; -} - -/** - * - */ -INLINE bool InterrogateElement:: -is_sequence() const { - return (_flags & F_sequence) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateElement:: -get_length_function() const { - return _length_function; -} - -/** - * - */ -INLINE bool InterrogateElement:: -is_mapping() const { - return (_flags & F_mapping) != 0; -} - - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateElement &element) { - element.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateElement &element) { - element.input(in); - return in; -} diff --git a/dtool/src/interrogatedb/interrogateElement.cxx b/dtool/src/interrogatedb/interrogateElement.cxx deleted file mode 100644 index 4b6b3d948f8..00000000000 --- a/dtool/src/interrogatedb/interrogateElement.cxx +++ /dev/null @@ -1,74 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateElement.cxx - * @author drose - * @date 2000-08-11 - */ - -#include "interrogateElement.h" -#include "interrogateDatabase.h" -#include "indexRemapper.h" -#include "interrogate_datafile.h" - -/** - * Formats the InterrogateElement data for output to a data file. - */ -void InterrogateElement:: -output(std::ostream &out) const { - InterrogateComponent::output(out); - out << _flags << " " - << _type << " " - << _getter << " " - << _setter << " " - << _has_function << " " - << _clear_function << " " - << _del_function << " " - << _length_function << " " - << _insert_function << " " - << _getkey_function << " "; - idf_output_string(out, _scoped_name); - idf_output_string(out, _comment, '\n'); -} - -/** - * Reads the data file as previously formatted by output(). - */ -void InterrogateElement:: -input(std::istream &in) { - InterrogateComponent::input(in); - in >> _flags >> _type >> _getter >> _setter; - if (InterrogateDatabase::get_file_minor_version() >= 1) { - in >> _has_function >> _clear_function; - if (InterrogateDatabase::get_file_minor_version() >= 2) { - in >> _del_function >> _length_function; - if (InterrogateDatabase::get_file_minor_version() >= 3) { - in >> _insert_function >> _getkey_function; - } - } - } - idf_input_string(in, _scoped_name); - idf_input_string(in, _comment); -} - -/** - * Remaps all internal index numbers according to the indicated map. This - * called from InterrogateDatabase::remap_indices(). - */ -void InterrogateElement:: -remap_indices(const IndexRemapper &remap) { - _type = remap.map_from(_type); - _getter = remap.map_from(_getter); - _setter = remap.map_from(_setter); - _has_function = remap.map_from(_has_function); - _clear_function = remap.map_from(_clear_function); - _del_function = remap.map_from(_del_function); - _insert_function = remap.map_from(_insert_function); - _getkey_function = remap.map_from(_getkey_function); - _length_function = remap.map_from(_length_function); -} diff --git a/dtool/src/interrogatedb/interrogateElement.h b/dtool/src/interrogatedb/interrogateElement.h deleted file mode 100644 index e3d55569f00..00000000000 --- a/dtool/src/interrogatedb/interrogateElement.h +++ /dev/null @@ -1,103 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateElement.h - * @author drose - * @date 2000-08-11 - */ - -#ifndef INTERROGATEELEMENT_H -#define INTERROGATEELEMENT_H - -#include "dtoolbase.h" - -#include "interrogateComponent.h" - -class IndexRemapper; -class CPPMakeProperty; - -/** - * An internal representation of a data element, like a data member or a - * global variable. - */ -class EXPCL_INTERROGATEDB InterrogateElement : public InterrogateComponent { -public: - INLINE InterrogateElement(InterrogateModuleDef *def = nullptr); - INLINE InterrogateElement(const InterrogateElement ©); - INLINE void operator = (const InterrogateElement ©); - - INLINE bool is_global() const; - - INLINE bool has_scoped_name() const; - INLINE const std::string &get_scoped_name() const; - - INLINE bool has_comment() const; - INLINE const std::string &get_comment() const; - - INLINE TypeIndex get_type() const; - INLINE bool has_getter() const; - INLINE FunctionIndex get_getter() const; - INLINE bool has_setter() const; - INLINE FunctionIndex get_setter() const; - INLINE bool has_has_function() const; - INLINE FunctionIndex get_has_function() const; - INLINE bool has_clear_function() const; - INLINE FunctionIndex get_clear_function() const; - INLINE bool has_del_function() const; - INLINE FunctionIndex get_del_function() const; - INLINE bool has_insert_function() const; - INLINE FunctionIndex get_insert_function() const; - INLINE bool has_getkey_function() const; - INLINE FunctionIndex get_getkey_function() const; - INLINE bool is_sequence() const; - INLINE FunctionIndex get_length_function() const; - INLINE bool is_mapping() const; - - void output(std::ostream &out) const; - void input(std::istream &in); - - void remap_indices(const IndexRemapper &remap); - -private: - enum Flags { - F_global = 0x0001, - F_has_getter = 0x0002, - F_has_setter = 0x0004, - F_has_has_function= 0x0008, - F_has_clear_function= 0x0010, - F_has_del_function= 0x0020, - F_sequence = 0x0040, - F_mapping = 0x0080, - F_has_insert_function= 0x0100, - F_has_getkey_function= 0x0200, - }; - - int _flags; - std::string _scoped_name; - std::string _comment; - TypeIndex _type; - FunctionIndex _length_function; - FunctionIndex _getter; - FunctionIndex _setter; - FunctionIndex _has_function; - FunctionIndex _clear_function; - FunctionIndex _del_function; - FunctionIndex _insert_function; - FunctionIndex _getkey_function; - - CPPMakeProperty *_make_property; - - friend class InterrogateBuilder; -}; - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateElement &element); -INLINE std::istream &operator >> (std::istream &in, InterrogateElement &element); - -#include "interrogateElement.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogateFunction.I b/dtool/src/interrogatedb/interrogateFunction.I deleted file mode 100644 index 6c36fec5d3d..00000000000 --- a/dtool/src/interrogatedb/interrogateFunction.I +++ /dev/null @@ -1,178 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateFunction.I - * @author drose - * @date 2000-08-01 - */ - -/** - * Returns true if the function is marked as 'global'. This means only that it - * should appear in the global function list. - */ -INLINE bool InterrogateFunction:: -is_global() const { - return (_flags & F_global) != 0; -} - -/** - * Returns true if the function is virtual, for whatever that's worth. - */ -INLINE bool InterrogateFunction:: -is_virtual() const { - return (_flags & F_virtual) != 0; -} - -/** - * Returns true if the function is a class method. - */ -INLINE bool InterrogateFunction:: -is_method() const { - return (_flags & F_method) != 0; -} - -/** - * Returns true if the function is flagged as a special unary operator, like - * operator -() with no parameters. - */ -INLINE bool InterrogateFunction:: -is_unary_op() const { - return (_flags & F_unary_op) != 0; -} - -/** - * Returns true if the function is a special typecast operator, like operator - * bool(). - */ -INLINE bool InterrogateFunction:: -is_operator_typecast() const { - return (_flags & F_operator_typecast) != 0; -} - -/** - * Returns true if the function is a constructor. - */ -INLINE bool InterrogateFunction:: -is_constructor() const { - return (_flags & F_constructor) != 0; -} - -/** - * Returns true if the function is a destructor. - */ -INLINE bool InterrogateFunction:: -is_destructor() const { - return (_flags & F_destructor) != 0; -} - -/** - * Return the class that owns the method, if is_method() returns true. - */ -INLINE TypeIndex InterrogateFunction:: -get_class() const { - return _class; -} - -/** - * - */ -INLINE bool InterrogateFunction:: -has_scoped_name() const { - return !_scoped_name.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateFunction:: -get_scoped_name() const { - return _scoped_name; -} - -/** - * - */ -INLINE bool InterrogateFunction:: -has_comment() const { - return !_comment.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateFunction:: -get_comment() const { - return _comment; -} - -/** - * - */ -INLINE bool InterrogateFunction:: -has_prototype() const { - return !_prototype.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateFunction:: -get_prototype() const { - return _prototype; -} - -/** - * - */ -INLINE int InterrogateFunction:: -number_of_c_wrappers() const { - return _c_wrappers.size(); -} - -/** - * - */ -INLINE FunctionWrapperIndex InterrogateFunction:: -get_c_wrapper(int n) const { - if (n >= 0 && n < (int)_c_wrappers.size()) { - return _c_wrappers[n]; - } - return 0; -} - -/** - * - */ -INLINE int InterrogateFunction:: -number_of_python_wrappers() const { - return _python_wrappers.size(); -} - -/** - * - */ -INLINE FunctionWrapperIndex InterrogateFunction:: -get_python_wrapper(int n) const { - if (n >= 0 && n < (int)_python_wrappers.size()) { - return _python_wrappers[n]; - } - return 0; -} - - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateFunction &function) { - function.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateFunction &function) { - function.input(in); - return in; -} diff --git a/dtool/src/interrogatedb/interrogateFunction.cxx b/dtool/src/interrogatedb/interrogateFunction.cxx deleted file mode 100644 index db70cc0b9cc..00000000000 --- a/dtool/src/interrogatedb/interrogateFunction.cxx +++ /dev/null @@ -1,100 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateFunction.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "interrogateFunction.h" -#include "indexRemapper.h" -#include "interrogate_datafile.h" -#include "interrogateDatabase.h" - -/** - * - */ -InterrogateFunction:: -InterrogateFunction(InterrogateModuleDef *def) : - InterrogateComponent(def) -{ - _flags = 0; - _class = 0; - _instances = nullptr; -} - -/** - * - */ -InterrogateFunction:: -InterrogateFunction(const InterrogateFunction ©) { - (*this) = copy; -} - -/** - * - */ -void InterrogateFunction:: -operator = (const InterrogateFunction ©) { - InterrogateComponent::operator = (copy); - _flags = copy._flags; - _scoped_name = copy._scoped_name; - _comment = copy._comment; - _prototype = copy._prototype; - _class = copy._class; - _c_wrappers = copy._c_wrappers; - _python_wrappers = copy._python_wrappers; - - _instances = copy._instances; - _expression = copy._expression; -} - -/** - * Formats the InterrogateFunction data for output to a data file. - */ -void InterrogateFunction:: -output(std::ostream &out) const { - InterrogateComponent::output(out); - out << _flags << " " - << _class << " "; - idf_output_string(out, _scoped_name); - idf_output_vector(out, _c_wrappers); - idf_output_vector(out, _python_wrappers); - idf_output_string(out, _comment, '\n'); - idf_output_string(out, _prototype, '\n'); -} - -/** - * Reads the data file as previously formatted by output(). - */ -void InterrogateFunction:: -input(std::istream &in) { - InterrogateComponent::input(in); - in >> _flags >> _class; - idf_input_string(in, _scoped_name); - idf_input_vector(in, _c_wrappers); - idf_input_vector(in, _python_wrappers); - idf_input_string(in, _comment); - idf_input_string(in, _prototype); -} - -/** - * Remaps all internal index numbers according to the indicated map. This - * called from InterrogateDatabase::remap_indices(). - */ -void InterrogateFunction:: -remap_indices(const IndexRemapper &remap) { - _class = remap.map_from(_class); - Wrappers::iterator wi; - for (wi = _c_wrappers.begin(); wi != _c_wrappers.end(); ++wi) { - (*wi) = remap.map_from(*wi); - } - for (wi = _python_wrappers.begin(); wi != _python_wrappers.end(); ++wi) { - (*wi) = remap.map_from(*wi); - } -} diff --git a/dtool/src/interrogatedb/interrogateFunction.h b/dtool/src/interrogatedb/interrogateFunction.h deleted file mode 100644 index 76f4f20ccd5..00000000000 --- a/dtool/src/interrogatedb/interrogateFunction.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateFunction.h - * @author drose - * @date 2000-08-01 - */ - -#ifndef INTERROGATEFUNCTION_H -#define INTERROGATEFUNCTION_H - -#include "dtoolbase.h" - -#include "interrogateComponent.h" - -#include -#include - -class IndexRemapper; -class CPPInstance; - -/** - * An internal representation of a function. - */ -class EXPCL_INTERROGATEDB InterrogateFunction : public InterrogateComponent { -public: - InterrogateFunction(InterrogateModuleDef *def = nullptr); - InterrogateFunction(const InterrogateFunction ©); - void operator = (const InterrogateFunction ©); - - INLINE bool is_global() const; - INLINE bool is_virtual() const; - INLINE bool is_method() const; - INLINE bool is_unary_op() const; - INLINE bool is_operator_typecast() const; - INLINE bool is_constructor() const; - INLINE bool is_destructor() const; - INLINE TypeIndex get_class() const; - - INLINE bool has_scoped_name() const; - INLINE const std::string &get_scoped_name() const; - - INLINE bool has_comment() const; - INLINE const std::string &get_comment() const; - - INLINE bool has_prototype() const; - INLINE const std::string &get_prototype() const; - - INLINE int number_of_c_wrappers() const; - INLINE FunctionWrapperIndex get_c_wrapper(int n) const; - - INLINE int number_of_python_wrappers() const; - INLINE FunctionWrapperIndex get_python_wrapper(int n) const; - - void output(std::ostream &out) const; - void input(std::istream &in); - - void remap_indices(const IndexRemapper &remap); - -private: - enum Flags { - F_global = 0x0001, - F_virtual = 0x0002, - F_method = 0x0004, - F_typecast = 0x0008, - F_getter = 0x0010, - F_setter = 0x0020, - F_unary_op = 0x0040, - F_operator_typecast = 0x0080, - F_constructor = 0x0100, - F_destructor = 0x0200, - F_item_assignment = 0x0400, - }; - - int _flags; - std::string _scoped_name; - std::string _comment; - std::string _prototype; - TypeIndex _class; - - typedef std::vector Wrappers; - Wrappers _c_wrappers; - Wrappers _python_wrappers; - -public: - // The rest of the members in this class aren't part of the public interface - // to interrogate, but are used internally as the interrogate database is - // built. They are valid only during the session of interrogate that - // generates the database, and will not be filled in when the database is - // reloaded from disk. - - // This must be a pointer, rather than a concrete map, so we don't risk - // trying to create a map in one DLL and access it in another. Silly - // Windows. - typedef std::map Instances; - Instances *_instances; - std::string _expression; - - friend class InterrogateBuilder; - friend class InterrogateDatabase; - friend class InterfaceMakerC; - friend class InterfaceMakerPythonSimple; - friend class InterfaceMakerPythonNative; - friend class FunctionRemap; -}; - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateFunction &function); -INLINE std::istream &operator >> (std::istream &in, InterrogateFunction &function); - -#include "interrogateFunction.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogateFunctionWrapper.I b/dtool/src/interrogatedb/interrogateFunctionWrapper.I deleted file mode 100644 index 93fff488b07..00000000000 --- a/dtool/src/interrogatedb/interrogateFunctionWrapper.I +++ /dev/null @@ -1,240 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateFunctionWrapper.I - * @author drose - * @date 2000-08-06 - */ - -/** - * - */ -INLINE InterrogateFunctionWrapper:: -InterrogateFunctionWrapper(InterrogateModuleDef *def) : - InterrogateComponent(def) -{ - _flags = 0; - _function = 0; - _return_type = 0; - _return_value_destructor = 0; -} - -/** - * - */ -INLINE InterrogateFunctionWrapper:: -InterrogateFunctionWrapper(const InterrogateFunctionWrapper ©) { - (*this) = copy; -} - -/** - * - */ -INLINE void InterrogateFunctionWrapper:: -operator = (const InterrogateFunctionWrapper ©) { - InterrogateComponent::operator = (copy); - _flags = copy._flags; - _function = copy._function; - _return_type = copy._return_type; - _return_value_destructor = copy._return_value_destructor; - _unique_name = copy._unique_name; - _comment = copy._comment; - _parameters = copy._parameters; -} - -/** - * Returns the FunctionIndex of the function that this wrapper corresponds to. - */ -INLINE FunctionIndex InterrogateFunctionWrapper:: -get_function() const { - return _function; -} - -/** - * - */ -INLINE bool InterrogateFunctionWrapper:: -is_callable_by_name() const { - return (_flags & F_callable_by_name) != 0; -} - -/** - * @since 1.10.13 - */ -INLINE bool InterrogateFunctionWrapper:: -is_copy_constructor() const { - return (_flags & F_copy_constructor) != 0; -} - -/** - * @since 1.10.13 - */ -INLINE bool InterrogateFunctionWrapper:: -is_coerce_constructor() const { - return (_flags & F_coerce_constructor) != 0; -} - -/** - * @since 1.10.13 - */ -INLINE bool InterrogateFunctionWrapper:: -is_extension() const { - return (_flags & F_extension) != 0; -} - -/** - * @since 1.11.0 - */ -INLINE bool InterrogateFunctionWrapper:: -is_deprecated() const { - return (_flags & F_deprecated) != 0; -} - -/** - * - */ -INLINE bool InterrogateFunctionWrapper:: -has_return_value() const { - return (_flags & F_has_return) != 0; -} - -/** - * - */ -INLINE TypeIndex InterrogateFunctionWrapper:: -get_return_type() const { - return _return_type; -} - -/** - * - */ -INLINE bool InterrogateFunctionWrapper:: -caller_manages_return_value() const { - return (_flags & F_caller_manages) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateFunctionWrapper:: -get_return_value_destructor() const { - return _return_value_destructor; -} - -/** - * - */ -INLINE int InterrogateFunctionWrapper:: -number_of_parameters() const { - return _parameters.size(); -} - -/** - * - */ -INLINE TypeIndex InterrogateFunctionWrapper:: -parameter_get_type(int n) const { - if (n >= 0 && n < (int)_parameters.size()) { - return _parameters[n]._type; - } - return 0; -} - -/** - * - */ -INLINE bool InterrogateFunctionWrapper:: -parameter_has_name(int n) const { - if (n >= 0 && n < (int)_parameters.size()) { - return (_parameters[n]._parameter_flags & PF_has_name) != 0; - } - return false; -} - -/** - * - */ -INLINE const std::string &InterrogateFunctionWrapper:: -parameter_get_name(int n) const { - static std::string bogus_string; - if (n >= 0 && n < (int)_parameters.size()) { - return _parameters[n]._name; - } - return bogus_string; -} - -/** - * - */ -INLINE bool InterrogateFunctionWrapper:: -parameter_is_this(int n) const { - if (n >= 0 && n < (int)_parameters.size()) { - return (_parameters[n]._parameter_flags & PF_is_this) != 0; - } - return false; -} - -/** - * - */ -INLINE bool InterrogateFunctionWrapper:: -parameter_is_optional(int n) const { - if (n >= 0 && n < (int)_parameters.size()) { - return (_parameters[n]._parameter_flags & PF_is_optional) != 0; - } - return false; -} - -/** - * - */ -INLINE const std::string &InterrogateFunctionWrapper:: -get_unique_name() const { - return _unique_name; -} - -/** - * - */ -INLINE bool InterrogateFunctionWrapper:: -has_comment() const { - return !_comment.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateFunctionWrapper:: -get_comment() const { - return _comment; -} - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateFunctionWrapper &wrapper) { - wrapper.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateFunctionWrapper &wrapper) { - wrapper.input(in); - return in; -} - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateFunctionWrapper::Parameter &p) { - p.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateFunctionWrapper::Parameter &p) { - p.input(in); - return in; -} diff --git a/dtool/src/interrogatedb/interrogateFunctionWrapper.cxx b/dtool/src/interrogatedb/interrogateFunctionWrapper.cxx deleted file mode 100644 index 9cad10ef4e4..00000000000 --- a/dtool/src/interrogatedb/interrogateFunctionWrapper.cxx +++ /dev/null @@ -1,84 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateFunctionWrapper.cxx - * @author drose - * @date 2000-08-06 - */ - -#include "interrogateFunctionWrapper.h" -#include "indexRemapper.h" -#include "interrogate_datafile.h" - -#include - -using std::istream; -using std::ostream; - -/** - * - */ -void InterrogateFunctionWrapper::Parameter:: -output(ostream &out) const { - idf_output_string(out, _name); - out << _parameter_flags << " " << _type << " "; -} - -/** - * - */ -void InterrogateFunctionWrapper::Parameter:: -input(istream &in) { - idf_input_string(in, _name); - in >> _parameter_flags >> _type; -} - -/** - * Formats the InterrogateFunctionWrapper data for output to a data file. - */ -void InterrogateFunctionWrapper:: -output(ostream &out) const { - InterrogateComponent::output(out); - out << _flags << " " - << _function << " " - << _return_type << " " - << _return_value_destructor << " "; - idf_output_string(out, _unique_name); - idf_output_string(out, _comment); - idf_output_vector(out, _parameters); -} - -/** - * Reads the data file as previously formatted by output(). - */ -void InterrogateFunctionWrapper:: -input(istream &in) { - InterrogateComponent::input(in); - in >> _flags - >> _function - >> _return_type - >> _return_value_destructor; - idf_input_string(in, _unique_name); - idf_input_string(in, _comment); - idf_input_vector(in, _parameters); -} - -/** - * Remaps all internal index numbers according to the indicated map. This - * called from InterrogateDatabase::remap_indices(). - */ -void InterrogateFunctionWrapper:: -remap_indices(const IndexRemapper &remap) { - _return_value_destructor = remap.map_from(_return_value_destructor); - _return_type = remap.map_from(_return_type); - - Parameters::iterator pi; - for (pi = _parameters.begin(); pi != _parameters.end(); ++pi) { - (*pi)._type = remap.map_from((*pi)._type); - } -} diff --git a/dtool/src/interrogatedb/interrogateFunctionWrapper.h b/dtool/src/interrogatedb/interrogateFunctionWrapper.h deleted file mode 100644 index 3fca6f3400f..00000000000 --- a/dtool/src/interrogatedb/interrogateFunctionWrapper.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateFunctionWrapper.h - * @author drose - * @date 2000-08-06 - */ - -#ifndef INTERROGATEFUNCTIONWRAPPER_H -#define INTERROGATEFUNCTIONWRAPPER_H - -#include "dtoolbase.h" - -#include "interrogateComponent.h" - -#include - -class IndexRemapper; - -/** - * An internal representation of a callable function. - */ -class EXPCL_INTERROGATEDB InterrogateFunctionWrapper : public InterrogateComponent { -public: - INLINE InterrogateFunctionWrapper(InterrogateModuleDef *def = nullptr); - INLINE InterrogateFunctionWrapper(const InterrogateFunctionWrapper ©); - INLINE void operator = (const InterrogateFunctionWrapper ©); - - INLINE FunctionIndex get_function() const; - - INLINE bool is_callable_by_name() const; - INLINE bool is_copy_constructor() const; - INLINE bool is_coerce_constructor() const; - INLINE bool is_extension() const; - INLINE bool is_deprecated() const; - - INLINE bool has_return_value() const; - INLINE TypeIndex get_return_type() const; - INLINE bool caller_manages_return_value() const; - INLINE FunctionIndex get_return_value_destructor() const; - - INLINE int number_of_parameters() const; - INLINE TypeIndex parameter_get_type(int n) const; - INLINE bool parameter_has_name(int n) const; - INLINE const std::string ¶meter_get_name(int n) const; - INLINE bool parameter_is_this(int n) const; - INLINE bool parameter_is_optional(int n) const; - - INLINE const std::string &get_unique_name() const; - - INLINE bool has_comment() const; - INLINE const std::string &get_comment() const; - - void output(std::ostream &out) const; - void input(std::istream &in); - - void remap_indices(const IndexRemapper &remap); - -private: - enum Flags { - F_caller_manages = 0x0001, - F_has_return = 0x0002, - F_callable_by_name = 0x0004, - F_copy_constructor = 0x0008, - F_coerce_constructor = 0x0010, - F_extension = 0x0020, - F_deprecated = 0x0040, - }; - - enum ParameterFlags { - PF_has_name = 0x0001, - PF_is_this = 0x0002, - PF_is_optional = 0x0004, - }; - - int _flags; - FunctionIndex _function; - TypeIndex _return_type; - FunctionIndex _return_value_destructor; - std::string _unique_name; - std::string _comment; - -public: - // This nested class must be declared public just so we can declare the - // external ostream and istream IO operator functions, on the SGI compiler. - // Arguably a compiler bug, but what can you do. - class Parameter { - public: - void output(std::ostream &out) const; - void input(std::istream &in); - - int _parameter_flags; - TypeIndex _type; - std::string _name; - }; - -private: - typedef std::vector Parameters; - Parameters _parameters; - - friend class InterrogateBuilder; - friend class FunctionRemap; -}; - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateFunctionWrapper &wrapper); -INLINE std::istream &operator >> (std::istream &in, InterrogateFunctionWrapper &wrapper); - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateFunctionWrapper::Parameter &p); -INLINE std::istream &operator >> (std::istream &in, InterrogateFunctionWrapper::Parameter &p); - -#include "interrogateFunctionWrapper.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogateMakeSeq.I b/dtool/src/interrogatedb/interrogateMakeSeq.I deleted file mode 100644 index 82e01761eac..00000000000 --- a/dtool/src/interrogatedb/interrogateMakeSeq.I +++ /dev/null @@ -1,103 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateMakeSeq.I - * @author drose - * @date 2009-09-15 - */ - -/** - * - */ -INLINE InterrogateMakeSeq:: -InterrogateMakeSeq(InterrogateModuleDef *def) : - InterrogateComponent(def) -{ - _length_getter = 0; - _element_getter = 0; -} - -/** - * - */ -INLINE InterrogateMakeSeq:: -InterrogateMakeSeq(const InterrogateMakeSeq ©) { - (*this) = copy; -} - -/** - * - */ -INLINE void InterrogateMakeSeq:: -operator = (const InterrogateMakeSeq ©) { - InterrogateComponent::operator = (copy); - _scoped_name = copy._scoped_name; - _comment = copy._comment; - _length_getter = copy._length_getter; - _element_getter = copy._element_getter; -} - -/** - * - */ -INLINE bool InterrogateMakeSeq:: -has_scoped_name() const { - return !_scoped_name.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateMakeSeq:: -get_scoped_name() const { - return _scoped_name; -} - -/** - * - */ -INLINE bool InterrogateMakeSeq:: -has_comment() const { - return !_comment.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateMakeSeq:: -get_comment() const { - return _comment; -} - -/** - * - */ -INLINE FunctionIndex InterrogateMakeSeq:: -get_length_getter() const { - return _length_getter; -} - -/** - * - */ -INLINE FunctionIndex InterrogateMakeSeq:: -get_element_getter() const { - return _element_getter; -} - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateMakeSeq &make_seq) { - make_seq.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateMakeSeq &make_seq) { - make_seq.input(in); - return in; -} diff --git a/dtool/src/interrogatedb/interrogateMakeSeq.cxx b/dtool/src/interrogatedb/interrogateMakeSeq.cxx deleted file mode 100644 index d875a91809d..00000000000 --- a/dtool/src/interrogatedb/interrogateMakeSeq.cxx +++ /dev/null @@ -1,50 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateMakeSeq.cxx - * @author drose - * @date 2009-09-15 - */ - -#include "interrogateMakeSeq.h" -#include "indexRemapper.h" -#include "interrogate_datafile.h" - -/** - * Formats the InterrogateMakeSeq data for output to a data file. - */ -void InterrogateMakeSeq:: -output(std::ostream &out) const { - InterrogateComponent::output(out); - out << _length_getter << " " - << _element_getter << " "; - idf_output_string(out, _scoped_name); - idf_output_string(out, _comment, '\n'); -} - -/** - * Reads the data file as previously formatted by output(). - */ -void InterrogateMakeSeq:: -input(std::istream &in) { - InterrogateComponent::input(in); - - in >> _length_getter >> _element_getter; - idf_input_string(in, _scoped_name); - idf_input_string(in, _comment); -} - -/** - * Remaps all internal index numbers according to the indicated map. This - * called from InterrogateDatabase::remap_indices(). - */ -void InterrogateMakeSeq:: -remap_indices(const IndexRemapper &remap) { - _length_getter = remap.map_from(_length_getter); - _element_getter = remap.map_from(_element_getter); -} diff --git a/dtool/src/interrogatedb/interrogateMakeSeq.h b/dtool/src/interrogatedb/interrogateMakeSeq.h deleted file mode 100644 index 5d6e1858b2c..00000000000 --- a/dtool/src/interrogatedb/interrogateMakeSeq.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateMakeSeq.h - * @author drose - * @date 2009-09-15 - */ - -#ifndef INTERROGATEMAKESEQ_H -#define INTERROGATEMAKESEQ_H - -#include "dtoolbase.h" - -#include "interrogateComponent.h" - -class IndexRemapper; - -/** - * Represents a synthetic method created via the MAKE_SEQ() macro. - */ -class EXPCL_INTERROGATEDB InterrogateMakeSeq : public InterrogateComponent { -public: - INLINE InterrogateMakeSeq(InterrogateModuleDef *def = nullptr); - INLINE InterrogateMakeSeq(const InterrogateMakeSeq ©); - INLINE void operator = (const InterrogateMakeSeq ©); - - INLINE bool has_scoped_name() const; - INLINE const std::string &get_scoped_name() const; - - INLINE bool has_comment() const; - INLINE const std::string &get_comment() const; - - INLINE FunctionIndex get_length_getter() const; - INLINE FunctionIndex get_element_getter() const; - - void output(std::ostream &out) const; - void input(std::istream &in); - - void remap_indices(const IndexRemapper &remap); - -private: - std::string _scoped_name; - std::string _comment; - FunctionIndex _length_getter; - FunctionIndex _element_getter; - - friend class InterrogateBuilder; -}; - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateMakeSeq &make_seq); -INLINE std::istream &operator >> (std::istream &in, InterrogateMakeSeq &make_seq); - -#include "interrogateMakeSeq.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogateManifest.I b/dtool/src/interrogatedb/interrogateManifest.I deleted file mode 100644 index 2aedf8a6828..00000000000 --- a/dtool/src/interrogatedb/interrogateManifest.I +++ /dev/null @@ -1,116 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateManifest.I - * @author drose - * @date 2000-08-11 - */ - -/** - * - */ -INLINE InterrogateManifest:: -InterrogateManifest(InterrogateModuleDef *def) : - InterrogateComponent(def) -{ - _flags = 0; - _int_value = 0; - _type = 0; - _getter = 0; -} - -/** - * - */ -INLINE InterrogateManifest:: -InterrogateManifest(const InterrogateManifest ©) { - (*this) = copy; -} - -/** - * - */ -INLINE void InterrogateManifest:: -operator = (const InterrogateManifest ©) { - InterrogateComponent::operator = (copy); - _flags = copy._flags; - _definition = copy._definition; - _int_value = copy._int_value; - _type = copy._type; - _getter = copy._getter; -} - - -/** - * - */ -INLINE const std::string &InterrogateManifest:: -get_definition() const { - return _definition; -} - -/** - * - */ -INLINE bool InterrogateManifest:: -has_type() const { - return (_flags & F_has_type) != 0; -} - -/** - * - */ -INLINE TypeIndex InterrogateManifest:: -get_type() const { - return _type; -} - -/** - * - */ -INLINE bool InterrogateManifest:: -has_getter() const { - return (_flags & F_has_getter) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateManifest:: -get_getter() const { - return _getter; -} - -/** - * - */ -INLINE bool InterrogateManifest:: -has_int_value() const { - return (_flags & F_has_int_value) != 0; -} - -/** - * - */ -INLINE int InterrogateManifest:: -get_int_value() const { - return _int_value; -} - - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateManifest &manifest) { - manifest.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateManifest &manifest) { - manifest.input(in); - return in; -} diff --git a/dtool/src/interrogatedb/interrogateManifest.cxx b/dtool/src/interrogatedb/interrogateManifest.cxx deleted file mode 100644 index a078e868f41..00000000000 --- a/dtool/src/interrogatedb/interrogateManifest.cxx +++ /dev/null @@ -1,49 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateManifest.cxx - * @author drose - * @date 2000-08-11 - */ - -#include "interrogateManifest.h" -#include "indexRemapper.h" -#include "interrogate_datafile.h" - -/** - * Formats the InterrogateManifest data for output to a data file. - */ -void InterrogateManifest:: -output(std::ostream &out) const { - InterrogateComponent::output(out); - out << _flags << " " - << _int_value << " " - << _type << " " - << _getter << " "; - idf_output_string(out, _definition); -} - -/** - * Reads the data file as previously formatted by output(). - */ -void InterrogateManifest:: -input(std::istream &in) { - InterrogateComponent::input(in); - in >> _flags >> _int_value >> _type >> _getter; - idf_input_string(in, _definition); -} - -/** - * Remaps all internal index numbers according to the indicated map. This - * called from InterrogateDatabase::remap_indices(). - */ -void InterrogateManifest:: -remap_indices(const IndexRemapper &remap) { - _type = remap.map_from(_type); - _getter = remap.map_from(_getter); -} diff --git a/dtool/src/interrogatedb/interrogateManifest.h b/dtool/src/interrogatedb/interrogateManifest.h deleted file mode 100644 index a038cc0ce16..00000000000 --- a/dtool/src/interrogatedb/interrogateManifest.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateManifest.h - * @author drose - * @date 2000-08-11 - */ - -#ifndef INTERROGATEMANIFEST_H -#define INTERROGATEMANIFEST_H - -#include "dtoolbase.h" - -#include "interrogateComponent.h" - -class IndexRemapper; - -/** - * An internal representation of a manifest constant. - */ -class EXPCL_INTERROGATEDB InterrogateManifest : public InterrogateComponent { -public: - INLINE InterrogateManifest(InterrogateModuleDef *def = nullptr); - INLINE InterrogateManifest(const InterrogateManifest ©); - INLINE void operator = (const InterrogateManifest ©); - - INLINE const std::string &get_definition() const; - INLINE bool has_type() const; - INLINE TypeIndex get_type() const; - INLINE bool has_getter() const; - INLINE FunctionIndex get_getter() const; - INLINE bool has_int_value() const; - INLINE int get_int_value() const; - - void output(std::ostream &out) const; - void input(std::istream &in); - - void remap_indices(const IndexRemapper &remap); - -private: - enum Flags { - F_has_type = 0x0001, - F_has_getter = 0x0002, - F_has_int_value = 0x0004 - }; - - int _flags; - std::string _definition; - int _int_value; - TypeIndex _type; - FunctionIndex _getter; - - friend class InterrogateBuilder; -}; - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateManifest &manifest); -INLINE std::istream &operator >> (std::istream &in, InterrogateManifest &manifest); - -#include "interrogateManifest.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogateType.I b/dtool/src/interrogatedb/interrogateType.I deleted file mode 100644 index 64c164e83e1..00000000000 --- a/dtool/src/interrogatedb/interrogateType.I +++ /dev/null @@ -1,594 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateType.I - * @author drose - * @date 2000-07-31 - */ - -/** - * Returns true if the type is marked as 'global'. This means only that it - * should appear in the global type list. - */ -INLINE bool InterrogateType:: -is_global() const { - return (_flags & F_global) != 0; -} - -/** - * Returns true if the type is marked as 'deprecated'. - * - * @since 1.11.0 - */ -INLINE bool InterrogateType:: -is_deprecated() const { - return (_flags & F_deprecated) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -has_scoped_name() const { - return !_scoped_name.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateType:: -get_scoped_name() const { - return _scoped_name; -} - -/** - * - */ -INLINE bool InterrogateType:: -has_true_name() const { - return !_true_name.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateType:: -get_true_name() const { - return _true_name; -} - -/** - * - */ -INLINE bool InterrogateType:: -has_comment() const { - return !_comment.empty(); -} - -/** - * - */ -INLINE const std::string &InterrogateType:: -get_comment() const { - return _comment; -} - -/** - * Returns true if this type is nested within some class definition. - */ -INLINE bool InterrogateType:: -is_nested() const { - return (_flags & F_nested) != 0; -} - -/** - * If is_nested() returns true, this is the class within which this type is - * defined. - */ -INLINE TypeIndex InterrogateType:: -get_outer_class() const { - return _outer_class; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_atomic() const { - return (_flags & F_atomic) != 0; -} - -/** - * - */ -INLINE AtomicToken InterrogateType:: -get_atomic_token() const { - return _atomic_token; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_unsigned() const { - return (_flags & F_unsigned) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_signed() const { - return (_flags & F_signed) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_long() const { - return (_flags & F_long) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_longlong() const { - return (_flags & F_longlong) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_short() const { - return (_flags & F_short) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_wrapped() const { - return (_flags & F_wrapped) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_pointer() const { - return (_flags & F_pointer) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_const() const { - return (_flags & F_const) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_typedef() const { - return (_flags & F_typedef) != 0; -} - -/** - * - */ -INLINE TypeIndex InterrogateType:: -get_wrapped_type() const { - return _wrapped_type; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_array() const { - return (_flags & F_array) != 0; -} - -/** - * - */ -INLINE int InterrogateType:: -get_array_size() const { - return _array_size; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_enum() const { - return (_flags & F_enum) != 0; -} - -/** - * Returns true if enum values are only available under a scope. - */ -INLINE bool InterrogateType:: -is_scoped_enum() const { - return (_flags & F_scoped_enum) != 0; -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_enum_values() const { - return _enum_values.size(); -} - -/** - * - */ -INLINE const std::string &InterrogateType:: -get_enum_value_name(int n) const { - if (n >= 0 && n < (int)_enum_values.size()) { - return _enum_values[n]._name; - } - return _empty_string; -} - -/** - * - */ -INLINE const std::string &InterrogateType:: -get_enum_value_scoped_name(int n) const { - if (n >= 0 && n < (int)_enum_values.size()) { - return _enum_values[n]._scoped_name; - } - return _empty_string; -} - -/** - * - */ -INLINE const std::string &InterrogateType:: -get_enum_value_comment(int n) const { - if (n >= 0 && n < (int)_enum_values.size()) { - return _enum_values[n]._comment; - } - return _empty_string; -} - -/** - * - */ -INLINE int InterrogateType:: -get_enum_value(int n) const { - if (n >= 0 && n < (int)_enum_values.size()) { - return _enum_values[n]._value; - } - return 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_struct() const { - return (_flags & F_struct) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_class() const { - return (_flags & F_class) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_union() const { - return (_flags & F_union) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_final() const { - return (_flags & F_final) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -is_fully_defined() const { - return (_flags & F_fully_defined) != 0; -} - -/** - * Returns true if the type is an unpublished type. This either means the - * type is a nested type, and it is protected or private within its scope, or - * that its definition is simply not marked as 'published'. - */ -INLINE bool InterrogateType:: -is_unpublished() const { - return (_flags & F_unpublished) != 0; -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_constructors() const { - return _constructors.size(); -} - -/** - * - */ -INLINE FunctionIndex InterrogateType:: -get_constructor(int n) const { - if (n >= 0 && n < (int)_constructors.size()) { - return _constructors[n]; - } else { - return 0; - } -} - -/** - * - */ -INLINE bool InterrogateType:: -has_destructor() const { - return (_destructor != 0); -} - -/** - * - */ -INLINE bool InterrogateType:: -destructor_is_inherited() const { - return (_flags & F_inherited_destructor) != 0; -} - -/** - * - */ -INLINE bool InterrogateType:: -destructor_is_implicit() const { - return (_flags & F_implicit_destructor) != 0; -} - -/** - * - */ -INLINE FunctionIndex InterrogateType:: -get_destructor() const { - return _destructor; -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_elements() const { - return _elements.size(); -} - -/** - * - */ -INLINE ElementIndex InterrogateType:: -get_element(int n) const { - if (n >= 0 && n < (int)_elements.size()) { - return _elements[n]; - } else { - return 0; - } -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_methods() const { - return _methods.size(); -} - -/** - * - */ -INLINE FunctionIndex InterrogateType:: -get_method(int n) const { - if (n >= 0 && n < (int)_methods.size()) { - return _methods[n]; - } else { - return 0; - } -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_make_seqs() const { - return _make_seqs.size(); -} - -/** - * - */ -INLINE MakeSeqIndex InterrogateType:: -get_make_seq(int n) const { - if (n >= 0 && n < (int)_make_seqs.size()) { - return _make_seqs[n]; - } else { - return 0; - } -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_casts() const { - return _casts.size(); -} - -/** - * - */ -INLINE FunctionIndex InterrogateType:: -get_cast(int n) const { - if (n >= 0 && n < (int)_casts.size()) { - return _casts[n]; - } else { - return 0; - } -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_derivations() const { - return _derivations.size(); -} - -/** - * - */ -INLINE TypeIndex InterrogateType:: -get_derivation(int n) const { - if (n >= 0 && n < (int)_derivations.size()) { - return _derivations[n]._base; - } else { - return 0; - } -} - -/** - * - */ -INLINE bool InterrogateType:: -derivation_has_upcast(int n) const { - if (n >= 0 && n < (int)_derivations.size()) { - return (_derivations[n]._flags & DF_upcast) != 0; - } else { - return false; - } -} - -/** - * - */ -INLINE TypeIndex InterrogateType:: -derivation_get_upcast(int n) const { - if (n >= 0 && n < (int)_derivations.size()) { - return _derivations[n]._upcast; - } else { - return 0; - } -} - -/** - * - */ -INLINE bool InterrogateType:: -derivation_downcast_is_impossible(int n) const { - if (n >= 0 && n < (int)_derivations.size()) { - return (_derivations[n]._flags & DF_downcast_impossible) != 0; - } else { - return false; - } -} - -/** - * - */ -INLINE bool InterrogateType:: -derivation_has_downcast(int n) const { - if (n >= 0 && n < (int)_derivations.size()) { - return (_derivations[n]._flags & DF_downcast) != 0; - } else { - return false; - } -} - -/** - * - */ -INLINE TypeIndex InterrogateType:: -derivation_get_downcast(int n) const { - if (n >= 0 && n < (int)_derivations.size()) { - return _derivations[n]._downcast; - } else { - return 0; - } -} - -/** - * - */ -INLINE int InterrogateType:: -number_of_nested_types() const { - return _nested_types.size(); -} - -/** - * - */ -INLINE TypeIndex InterrogateType:: -get_nested_type(int n) const { - if (n >= 0 && n < (int)_nested_types.size()) { - return _nested_types[n]; - } else { - return 0; - } -} - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateType &type) { - type.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateType &type) { - type.input(in); - return in; -} - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateType::Derivation &d) { - d.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateType::Derivation &d) { - d.input(in); - return in; -} - -INLINE std::ostream & -operator << (std::ostream &out, const InterrogateType::EnumValue &ev) { - ev.output(out); - return out; -} - -INLINE std::istream & -operator >> (std::istream &in, InterrogateType::EnumValue &ev) { - ev.input(in); - return in; -} diff --git a/dtool/src/interrogatedb/interrogateType.cxx b/dtool/src/interrogatedb/interrogateType.cxx deleted file mode 100644 index a9b9404cd44..00000000000 --- a/dtool/src/interrogatedb/interrogateType.cxx +++ /dev/null @@ -1,247 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateType.cxx - * @author drose - * @date 2000-07-31 - */ - -#include "interrogateType.h" -#include "indexRemapper.h" -#include "interrogate_datafile.h" -#include "interrogateDatabase.h" - -#include - -using std::istream; -using std::ostream; - -/** - * - */ -InterrogateType:: -InterrogateType(InterrogateModuleDef *def) : - InterrogateComponent(def) -{ - _flags = 0; - _outer_class = 0; - _atomic_token = AT_not_atomic; - _wrapped_type = 0; - _array_size = 1; - _destructor = 0; - - _cpptype = nullptr; - _cppscope = nullptr; -} - -/** - * - */ -InterrogateType:: -InterrogateType(const InterrogateType ©) { - (*this) = copy; -} - -/** - * - */ -void InterrogateType::Derivation:: -output(ostream &out) const { - out << _flags << " " << _base << " " << _upcast << " " << _downcast; -} - -/** - * - */ -void InterrogateType::Derivation:: -input(istream &in) { - in >> _flags >> _base >> _upcast >> _downcast; -} - -/** - * - */ -void InterrogateType::EnumValue:: -output(ostream &out) const { - idf_output_string(out, _name); - idf_output_string(out, _scoped_name); - idf_output_string(out, _comment, '\n'); - out << _value; -} - -/** - * - */ -void InterrogateType::EnumValue:: -input(istream &in) { - idf_input_string(in, _name); - idf_input_string(in, _scoped_name); - idf_input_string(in, _comment); - in >> _value; -} - -/** - * - */ -void InterrogateType:: -operator = (const InterrogateType ©) { - InterrogateComponent::operator = (copy); - _flags = copy._flags; - _scoped_name = copy._scoped_name; - _true_name = copy._true_name; - _comment = copy._comment; - _outer_class = copy._outer_class; - _atomic_token = copy._atomic_token; - _wrapped_type = copy._wrapped_type; - _array_size = copy._array_size; - _constructors = copy._constructors; - _destructor = copy._destructor; - _elements = copy._elements; - _methods = copy._methods; - _make_seqs = copy._make_seqs; - _casts = copy._casts; - _derivations = copy._derivations; - _enum_values = copy._enum_values; - _nested_types = copy._nested_types; - - _cpptype = copy._cpptype; - _cppscope = copy._cppscope; -} - -/** - * Combines type with the other similar definition. If one type is "fully - * defined" and the other one isn't, the fully-defined type wins. If both - * types are fully defined, whichever type is marked "global" wins. - */ -void InterrogateType:: -merge_with(const InterrogateType &other) { - // The only thing we care about copying from the non-fully-defined type - // right now is the global flag. - - if (is_fully_defined() && - (!other.is_fully_defined() || (other._flags & F_global) == 0)) { - // We win. - _flags |= (other._flags & F_global); - - } else { - // They win. - int old_flags = (_flags & F_global); - (*this) = other; - _flags |= old_flags; - } -} - -/** - * Formats the InterrogateType data for output to a data file. - */ -void InterrogateType:: -output(ostream &out) const { - InterrogateComponent::output(out); - - out << _flags << " "; - idf_output_string(out, _scoped_name); - idf_output_string(out, _true_name); - out << _outer_class << " " - << (int)_atomic_token << " " - << _wrapped_type << " "; - - if (is_array()) { - out << _array_size << " "; - } - - idf_output_vector(out, _constructors); - out << _destructor << " "; - idf_output_vector(out, _elements); - idf_output_vector(out, _methods); - idf_output_vector(out, _make_seqs); - idf_output_vector(out, _casts); - idf_output_vector(out, _derivations); - idf_output_vector(out, _enum_values); - idf_output_vector(out, _nested_types); - idf_output_string(out, _comment, '\n'); -} - -/** - * Reads the data file as previously formatted by output(). - */ -void InterrogateType:: -input(istream &in) { - InterrogateComponent::input(in); - - in >> _flags; - idf_input_string(in, _scoped_name); - idf_input_string(in, _true_name); - - in >> _outer_class; - int token; - in >> token; - _atomic_token = (AtomicToken)token; - in >> _wrapped_type; - - if (is_array()) { - in >> _array_size; - } - - idf_input_vector(in, _constructors); - in >> _destructor; - - idf_input_vector(in, _elements); - idf_input_vector(in, _methods); - idf_input_vector(in, _make_seqs); - idf_input_vector(in, _casts); - idf_input_vector(in, _derivations); - idf_input_vector(in, _enum_values); - idf_input_vector(in, _nested_types); - idf_input_string(in, _comment); -} - -/** - * Remaps all internal index numbers according to the indicated map. This - * called from InterrogateDatabase::remap_indices(). - */ -void InterrogateType:: -remap_indices(const IndexRemapper &remap) { - _outer_class = remap.map_from(_outer_class); - _wrapped_type = remap.map_from(_wrapped_type); - - Functions::iterator fi; - for (fi = _constructors.begin(); fi != _constructors.end(); ++fi) { - (*fi) = remap.map_from(*fi); - } - _destructor = remap.map_from(_destructor); - - Elements::iterator ei; - for (ei = _elements.begin(); ei != _elements.end(); ++ei) { - (*ei) = remap.map_from(*ei); - } - - for (fi = _methods.begin(); fi != _methods.end(); ++fi) { - (*fi) = remap.map_from(*fi); - } - for (fi = _casts.begin(); fi != _casts.end(); ++fi) { - (*fi) = remap.map_from(*fi); - } - - MakeSeqs::iterator si; - for (si = _make_seqs.begin(); si != _make_seqs.end(); ++si) { - (*si) = remap.map_from(*si); - } - - Derivations::iterator di; - for (di = _derivations.begin(); di != _derivations.end(); ++di) { - (*di)._base = remap.map_from((*di)._base); - (*di)._upcast = remap.map_from((*di)._upcast); - (*di)._downcast = remap.map_from((*di)._downcast); - } - - Types::iterator ti; - for (ti = _nested_types.begin(); ti != _nested_types.end(); ++ti) { - (*ti) = remap.map_from(*ti); - } - -} diff --git a/dtool/src/interrogatedb/interrogateType.h b/dtool/src/interrogatedb/interrogateType.h deleted file mode 100644 index c9f67aff26b..00000000000 --- a/dtool/src/interrogatedb/interrogateType.h +++ /dev/null @@ -1,239 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogateType.h - * @author drose - * @date 2000-07-31 - */ - -#ifndef INTERROGATETYPE_H -#define INTERROGATETYPE_H - -#include "dtoolbase.h" - -#include "interrogateComponent.h" - -#include - -class IndexRemapper; -class CPPType; -class CPPScope; - -/** - * An internal representation of a type. - */ -class EXPCL_INTERROGATEDB InterrogateType : public InterrogateComponent { -public: - InterrogateType(InterrogateModuleDef *def = nullptr); - InterrogateType(const InterrogateType ©); - void operator = (const InterrogateType ©); - - INLINE bool is_global() const; - INLINE bool is_deprecated() const; - - INLINE bool has_scoped_name() const; - INLINE const std::string &get_scoped_name() const; - - INLINE bool has_true_name() const; - INLINE const std::string &get_true_name() const; - - INLINE bool has_comment() const; - INLINE const std::string &get_comment() const; - - INLINE bool is_nested() const; - INLINE TypeIndex get_outer_class() const; - - INLINE bool is_atomic() const; - INLINE AtomicToken get_atomic_token() const; - INLINE bool is_unsigned() const; - INLINE bool is_signed() const; - INLINE bool is_long() const; - INLINE bool is_longlong() const; - INLINE bool is_short() const; - - INLINE bool is_wrapped() const; - INLINE bool is_pointer() const; - INLINE bool is_const() const; - INLINE bool is_typedef() const; - INLINE TypeIndex get_wrapped_type() const; - - INLINE bool is_array() const; - INLINE int get_array_size() const; - - INLINE bool is_enum() const; - INLINE bool is_scoped_enum() const; - INLINE int number_of_enum_values() const; - INLINE const std::string &get_enum_value_name(int n) const; - INLINE const std::string &get_enum_value_scoped_name(int n) const; - INLINE const std::string &get_enum_value_comment(int n) const; - INLINE int get_enum_value(int n) const; - - INLINE bool is_struct() const; - INLINE bool is_class() const; - INLINE bool is_union() const; - INLINE bool is_final() const; - - INLINE bool is_fully_defined() const; - INLINE bool is_unpublished() const; - INLINE int number_of_constructors() const; - INLINE FunctionIndex get_constructor(int n) const; - INLINE bool has_destructor() const; - INLINE bool destructor_is_inherited() const; - INLINE bool destructor_is_implicit() const; - INLINE FunctionIndex get_destructor() const; - INLINE int number_of_elements() const; - INLINE ElementIndex get_element(int n) const; - INLINE int number_of_methods() const; - INLINE FunctionIndex get_method(int n) const; - INLINE int number_of_make_seqs() const; - INLINE MakeSeqIndex get_make_seq(int n) const; - - INLINE int number_of_casts() const; - INLINE FunctionIndex get_cast(int n) const; - - INLINE int number_of_derivations() const; - INLINE TypeIndex get_derivation(int n) const; - - INLINE bool derivation_has_upcast(int n) const; - INLINE FunctionIndex derivation_get_upcast(int n) const; - - INLINE bool derivation_downcast_is_impossible(int n) const; - INLINE bool derivation_has_downcast(int n) const; - INLINE FunctionIndex derivation_get_downcast(int n) const; - - INLINE int number_of_nested_types() const; - INLINE TypeIndex get_nested_type(int n) const; - - void merge_with(const InterrogateType &other); - void output(std::ostream &out) const; - void input(std::istream &in); - - void remap_indices(const IndexRemapper &remap); - -private: - enum Flags { - F_global = 0x000001, - F_atomic = 0x000002, - F_unsigned = 0x000004, - F_signed = 0x000008, - F_long = 0x000010, - F_longlong = 0x000020, - F_short = 0x000040, - F_wrapped = 0x000080, - F_pointer = 0x000100, - F_const = 0x000200, - F_struct = 0x000400, - F_class = 0x000800, - F_union = 0x001000, - F_fully_defined = 0x002000, - F_true_destructor = 0x004000, - F_private_destructor = 0x008000, - F_inherited_destructor = 0x010000, - F_implicit_destructor = 0x020000, - F_nested = 0x040000, - F_enum = 0x080000, - F_unpublished = 0x100000, - F_typedef = 0x200000, - F_array = 0x400000, - F_scoped_enum = 0x800000, - F_final =0x1000000, - F_deprecated =0x2000000, - }; - -public: - int _flags; - - std::string _scoped_name; - std::string _true_name; - std::string _comment; - TypeIndex _outer_class; - AtomicToken _atomic_token; - TypeIndex _wrapped_type; - int _array_size; - - typedef std::vector Functions; - Functions _constructors; - FunctionIndex _destructor; - - typedef std::vector Elements; - Elements _elements; - Functions _methods; - Functions _casts; - - typedef std::vector MakeSeqs; - MakeSeqs _make_seqs; - - enum DerivationFlags { - DF_upcast = 0x01, - DF_downcast = 0x02, - DF_downcast_impossible = 0x04 - }; - -public: - // This nested class must be declared public just so we can declare the - // external ostream and istream IO operator functions, on the SGI compiler. - // Arguably a compiler bug, but what can you do. - class Derivation { - public: - void output(std::ostream &out) const; - void input(std::istream &in); - - int _flags; - TypeIndex _base; - FunctionIndex _upcast; - FunctionIndex _downcast; - }; - -private: - typedef std::vector Derivations; - Derivations _derivations; - -public: - // This nested class must also be public, for the same reason. - class EnumValue { - public: - void output(std::ostream &out) const; - void input(std::istream &in); - - std::string _name; - std::string _scoped_name; - std::string _comment; - int _value; - }; - -private: - typedef std::vector EnumValues; - EnumValues _enum_values; - - typedef std::vector Types; - Types _nested_types; - -public: - // The rest of the members in this class aren't part of the public interface - // to interrogate, but are used internally as the interrogate database is - // built. They are valid only during the session of interrogate that - // generates the database, and will not be filled in when the database is - // reloaded from disk. - CPPType *_cpptype; - CPPScope *_cppscope; - - friend class InterrogateBuilder; -}; - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateType &type); -INLINE std::istream &operator >> (std::istream &in, InterrogateType &type); - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateType::Derivation &d); -INLINE std::istream &operator >> (std::istream &in, InterrogateType::Derivation &d); - -INLINE std::ostream &operator << (std::ostream &out, const InterrogateType::EnumValue &d); -INLINE std::istream &operator >> (std::istream &in, InterrogateType::EnumValue &d); - -#include "interrogateType.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogate_datafile.I b/dtool/src/interrogatedb/interrogate_datafile.I deleted file mode 100644 index cb020861e28..00000000000 --- a/dtool/src/interrogatedb/interrogate_datafile.I +++ /dev/null @@ -1,51 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate_datafile.I - * @author drose - * @date 2000-08-09 - */ - -/** - * Writes the indicated vector to the output file. Each component is written - * using its normal ostream output operator. - */ -template -void -idf_output_vector(std::ostream &out, const std::vector &vec) { - out << vec.size() << " "; - typename std::vector::const_iterator vi; - for (vi = vec.begin(); vi != vec.end(); ++vi) { - out << (*vi) << " "; - } -} - - -/** - * Reads the given vector from the input file, as previously written by - * output_string(). Each component is read using its normal istream input - * operator. - */ -template -void -idf_input_vector(std::istream &in, std::vector &vec) { - int length; - in >> length; - if (in.fail()) { - return; - } - - vec.clear(); - vec.reserve(length); - while (length > 0) { - Element elem; - in >> elem; - vec.push_back(elem); - length--; - } -} diff --git a/dtool/src/interrogatedb/interrogate_datafile.cxx b/dtool/src/interrogatedb/interrogate_datafile.cxx deleted file mode 100644 index a61defb368c..00000000000 --- a/dtool/src/interrogatedb/interrogate_datafile.cxx +++ /dev/null @@ -1,98 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate_datafile.cxx - * @author drose - * @date 2000-08-09 - */ - -#include "interrogate_datafile.h" - -using std::istream; -using std::ostream; -using std::string; - - -/** - * Writes the indicated string to the output file. Uses the given whitespace - * character to separate the string's length and its contents. - */ -void -idf_output_string(ostream &out, const string &str, char whitespace) { - out << str.length() << whitespace; - if (!str.empty()) { - out << str << whitespace; - } -} - -/** - * Reads the given string from the input file, as previously written by - * output_string(). - */ -void -idf_input_string(istream &in, string &str) { - int length; - in >> length; - if (in.fail()) { - return; - } - - // Skip one character of whitespace, and then read the string. - in.get(); - str = ""; - while (length > 0) { - str += in.get(); - length--; - } -} - -/** - * Writes the indicated string to the output file. Uses the given whitespace - * character to separate the string's length and its contents. - */ -void -idf_output_string(ostream &out, const char *str, char whitespace) { - if (str == nullptr) { - out << "0 "; - } else { - out << strlen(str) << whitespace; - if (str[0] != '\0') { - out << str << whitespace; - } - } -} - -/** - * Reads the given string from the input file, as previously written by - * output_string(). - */ -void -idf_input_string(istream &in, const char *&str) { - int length; - in >> length; - if (in.fail()) { - return; - } - - if (length == 0) { - // Don't change the string if the input length is zero. - return; - } - - // Skip one character of whitespace, and then read the string. - in.get(); - char *readstr = new char[length + 1]; - int p = 0; - while (p < length) { - readstr[p] = in.get(); - p++; - } - readstr[p] = '\0'; - - str = readstr; -} diff --git a/dtool/src/interrogatedb/interrogate_datafile.h b/dtool/src/interrogatedb/interrogate_datafile.h deleted file mode 100644 index 8432123fdff..00000000000 --- a/dtool/src/interrogatedb/interrogate_datafile.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate_datafile.h - * @author drose - * @date 2000-08-09 - */ - -#ifndef INTERROGATE_DATAFILE_H -#define INTERROGATE_DATAFILE_H - -// This file defines some convenience functions for reading and writing the -// interrogate database files. - -#include "dtoolbase.h" -#include - -void idf_output_string(std::ostream &out, const std::string &str, char whitespace = ' '); -void idf_input_string(std::istream &in, std::string &str); - -void idf_output_string(std::ostream &out, const char *str, char whitespace = ' '); -void idf_input_string(std::istream &in, const char *&str); - -template -void idf_output_vector(std::ostream &out, const std::vector &vec); - -template -void idf_input_vector(std::istream &in, std::vector &vec); - -#include "interrogate_datafile.I" - -#endif diff --git a/dtool/src/interrogatedb/interrogate_interface.cxx b/dtool/src/interrogatedb/interrogate_interface.cxx deleted file mode 100644 index a0b4ff356a7..00000000000 --- a/dtool/src/interrogatedb/interrogate_interface.cxx +++ /dev/null @@ -1,1043 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate_interface.cxx - * @author drose - * @date 2000-07-31 - */ - -#include "interrogate_interface.h" -#include "interrogateDatabase.h" -#include "interrogateType.h" -#include "interrogateFunction.h" -#include "config_interrogatedb.h" - -using std::string; - -// This function adds one more directory to the list of directories search for -// interrogate (*.in) files. In the past, this list has been defined the -// environment variable ETC_PATH, but now it is passed in by the code -// generator. -void -interrogate_add_search_directory(const char *dirname) { - // cerr << "interrogate_add_search_directory(" << dirname << ")\n"; - interrogatedb_path.append_directory(Filename::from_os_specific(dirname)); -} - -// This function works similar to the above, but adds a complete path string-- -// a list of multiple directories, separated by the standard delimiter--to the -// search path. -void -interrogate_add_search_path(const char *pathstring) { - // cerr << "interrogate_add_search_path(" << pathstring << ")\n"; - interrogatedb_path.append_path(pathstring); -} - -bool interrogate_error_flag() { - // cerr << "interrogate_error_flag\n"; - return InterrogateDatabase::get_ptr()->get_error_flag(); -} - -int -interrogate_number_of_manifests() { - // cerr << "interrogate_number_of_manifests\n"; - return InterrogateDatabase::get_ptr()->get_num_global_manifests(); -} - -ManifestIndex -interrogate_get_manifest(int n) { - // cerr << "interrogate_get_manifest(" << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_global_manifest(n); -} - -ManifestIndex -interrogate_get_manifest_by_name(const char *manifest_name) { - // cerr << "interrogate_get_manifest_by_name(" << manifest_name << ")\n"; - return InterrogateDatabase::get_ptr()->lookup_manifest_by_name(manifest_name); -} - -const char * -interrogate_manifest_name(ManifestIndex manifest) { - // cerr << "interrogate_manifest_name(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).get_name().c_str(); -} - -const char * -interrogate_manifest_definition(ManifestIndex manifest) { - // cerr << "interrogate_manifest_definition(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).get_definition().c_str(); -} - -bool -interrogate_manifest_has_type(ManifestIndex manifest) { - // cerr << "interrogate_manifest_has_type(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).has_type(); -} - -TypeIndex -interrogate_manifest_get_type(ManifestIndex manifest) { - // cerr << "interrogate_manifest_get_type(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).get_type(); -} - -bool -interrogate_manifest_has_getter(ManifestIndex manifest) { - // cerr << "interrogate_manifest_has_getter(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).has_getter(); -} - -FunctionIndex -interrogate_manifest_getter(ManifestIndex manifest) { - // cerr << "interrogate_manifest_getter(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).get_getter(); -} - -bool -interrogate_manifest_has_int_value(ManifestIndex manifest) { - // cerr << "interrogate_manifest_has_int_value(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).has_int_value(); -} - -int -interrogate_manifest_get_int_value(ManifestIndex manifest) { - // cerr << "interrogate_manifest_get_int_value(" << manifest << ")\n"; - return InterrogateDatabase::get_ptr()->get_manifest(manifest).get_int_value(); -} - -const char * -interrogate_element_name(ElementIndex element) { - // cerr << "interrogate_element_name(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_name().c_str(); -} - -const char * -interrogate_element_scoped_name(ElementIndex element) { - // cerr << "interrogate_element_scoped_name(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_scoped_name().c_str(); -} - -bool -interrogate_element_has_comment(ElementIndex element) { - // cerr << "interrogate_element_has_comment(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_comment(); -} - -const char * -interrogate_element_comment(ElementIndex element) { - // cerr << "interrogate_element_comment(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_comment().c_str(); -} - -ElementIndex -interrogate_get_element_by_name(const char *element_name) { - // cerr << "interrogate_get_element_by_name(" << element_name << ")\n"; - return InterrogateDatabase::get_ptr()->lookup_element_by_name(element_name); -} - -ElementIndex -interrogate_get_element_by_scoped_name(const char *element_name) { - // cerr << "interrogate_get_element_by_scoped_name(" << element_name << - // ")\n"; - return InterrogateDatabase::get_ptr()->lookup_element_by_scoped_name(element_name); -} - -TypeIndex -interrogate_element_type(ElementIndex element) { - // cerr << "interrogate_element_type(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_type(); -} - -bool -interrogate_element_has_getter(ElementIndex element) { - // cerr << "interrogate_element_has_getter(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_getter(); -} - -FunctionIndex -interrogate_element_getter(ElementIndex element) { - // cerr << "interrogate_element_getter(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_getter(); -} - -bool -interrogate_element_has_setter(ElementIndex element) { - // cerr << "interrogate_element_has_setter(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_setter(); -} - -FunctionIndex -interrogate_element_setter(ElementIndex element) { - // cerr << "interrogate_element_setter(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_setter(); -} - -bool -interrogate_element_has_has_function(ElementIndex element) { - // cerr << "interrogate_element_has_has_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_has_function(); -} - -FunctionIndex -interrogate_element_has_function(ElementIndex element) { - // cerr << "interrogate_element_has_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_has_function(); -} - -bool -interrogate_element_has_clear_function(ElementIndex element) { - // cerr << "interrogate_element_has_clear_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_clear_function(); -} - -FunctionIndex -interrogate_element_clear_function(ElementIndex element) { - // cerr << "interrogate_element_clear_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_clear_function(); -} - -bool -interrogate_element_has_del_function(ElementIndex element) { - // cerr << "interrogate_element_has_del_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_del_function(); -} - -FunctionIndex -interrogate_element_del_function(ElementIndex element) { - // cerr << "interrogate_element_del_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_del_function(); -} - -bool -interrogate_element_has_insert_function(ElementIndex element) { - // cerr << "interrogate_element_has_insert_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_insert_function(); -} - -FunctionIndex -interrogate_element_insert_function(ElementIndex element) { - // cerr << "interrogate_element_insert_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_insert_function(); -} - -bool -interrogate_element_has_getkey_function(ElementIndex element) { - // cerr << "interrogate_element_has_getkey_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).has_getkey_function(); -} - -FunctionIndex -interrogate_element_getkey_function(ElementIndex element) { - // cerr << "interrogate_element_getkey_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_getkey_function(); -} - -FunctionIndex -interrogate_element_length_function(ElementIndex element) { - // cerr << "interrogate_element_length_function(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).get_length_function(); -} - -bool -interrogate_element_is_sequence(ElementIndex element) { - // cerr << "interrogate_element_is_sequence(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).is_sequence(); -} - -bool -interrogate_element_is_mapping(ElementIndex element) { - // cerr << "interrogate_element_is_mapping(" << element << ")\n"; - return InterrogateDatabase::get_ptr()->get_element(element).is_mapping(); -} - -int -interrogate_number_of_globals() { - // cerr << "interrogate_number_of_globals()\n"; - return InterrogateDatabase::get_ptr()->get_num_global_elements(); -} - -ElementIndex -interrogate_get_global(int n) { - // cerr << "interrogate_get_global(" << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_global_element(n); -} - -int -interrogate_number_of_global_functions() { - // cerr << "interrogate_number_of_global_functions()\n"; - return InterrogateDatabase::get_ptr()->get_num_global_functions(); -} - -FunctionIndex -interrogate_get_global_function(int n) { - // cerr << "interrogate_get_global_function(" << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_global_function(n); -} - -int -interrogate_number_of_functions() { - // cerr << "interrogate_number_of_functions()\n"; - return InterrogateDatabase::get_ptr()->get_num_all_functions(); -} - -FunctionIndex -interrogate_get_function(int n) { - // cerr << "interrogate_get_function(" << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_all_function(n); -} - -const char * -interrogate_function_name(FunctionIndex function) { - // cerr << "interrogate_function_name(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_name().c_str(); -} - -const char * -interrogate_function_scoped_name(FunctionIndex function) { - // cerr << "interrogate_function_scoped_name(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_scoped_name().c_str(); -} - -bool -interrogate_function_has_comment(FunctionIndex function) { - // cerr << "interrogate_function_has_comment(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).has_comment(); -} - -const char * -interrogate_function_comment(FunctionIndex function) { - // cerr << "interrogate_function_comment(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_comment().c_str(); -} - -const char * -interrogate_function_prototype(FunctionIndex function) { - // cerr << "interrogate_function_prototype(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_prototype().c_str(); -} - -bool -interrogate_function_is_method(FunctionIndex function) { - // cerr << "interrogate_function_is_method(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).is_method(); -} - -TypeIndex -interrogate_function_class(FunctionIndex function) { - // cerr << "interrogate_function_class(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_class(); -} - -bool -interrogate_function_is_unary_op(FunctionIndex function) { - // cerr << "interrogate_function_is_unary_op(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).is_unary_op(); -} - -bool -interrogate_function_is_operator_typecast(FunctionIndex function) { - // cerr << "interrogate_function_is_operator_typecast(" << function << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).is_operator_typecast(); -} - -bool -interrogate_function_is_constructor(FunctionIndex function) { - // cerr << "interrogate_function_is_constructor(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).is_constructor(); -} - -bool -interrogate_function_is_destructor(FunctionIndex function) { - // cerr << "interrogate_function_is_destructor(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).is_destructor(); -} - -bool -interrogate_function_has_module_name(FunctionIndex function) { - // cerr << "interrogate_function_has_module_name(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).has_module_name(); -} - -const char * -interrogate_function_module_name(FunctionIndex function) { - // cerr << "interrogate_function_module_name(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_module_name(); -} - -bool -interrogate_function_has_library_name(FunctionIndex function) { - // cerr << "interrogate_function_has_library_name(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).has_library_name(); -} - -const char * -interrogate_function_library_name(FunctionIndex function) { - // cerr << "interrogate_function_library_name(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_library_name(); -} - - - -bool -interrogate_function_is_virtual(FunctionIndex function) { - // cerr << "interrogate_function_is_virtual(" << function << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).is_virtual(); -} - -int -interrogate_function_number_of_c_wrappers(FunctionIndex function) { - // cerr << "interrogate_function_number_of_c_wrappers(" << function << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).number_of_c_wrappers(); -} - -FunctionWrapperIndex -interrogate_function_c_wrapper(FunctionIndex function, int n) { - // cerr << "interrogate_function_c_wrapper(" << function << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_c_wrapper(n); -} - -int -interrogate_function_number_of_python_wrappers(FunctionIndex function) { - // cerr << "interrogate_function_number_of_python_wrappers(" << function << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).number_of_python_wrappers(); -} - -FunctionWrapperIndex -interrogate_function_python_wrapper(FunctionIndex function, int n) { - // cerr << "interrogate_function_python_wrapper(" << function << ", " << n - // << ")\n"; - return InterrogateDatabase::get_ptr()->get_function(function).get_python_wrapper(n); -} - -const char * -interrogate_wrapper_name(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_name(" << wrapper << ")\n"; - static string result; - result = InterrogateDatabase::get_ptr()->get_wrapper(wrapper).get_name(); - return result.c_str(); -} - -FunctionIndex -interrogate_wrapper_function(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_function(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).get_function(); -} - -bool -interrogate_wrapper_is_callable_by_name(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_is_callable_by_name(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).is_callable_by_name(); -} - -bool -interrogate_wrapper_is_copy_constructor(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_is_copy_constructor(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).is_copy_constructor(); -} - -bool -interrogate_wrapper_is_coerce_constructor(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_is_coerce_constructor(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).is_coerce_constructor(); -} - -bool -interrogate_wrapper_is_extension(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_is_extension(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).is_extension(); -} - -bool -interrogate_wrapper_is_deprecated(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_is_deprecated(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).is_deprecated(); -} - -bool -interrogate_wrapper_has_comment(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_has_comment(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).has_comment(); -} - -const char * -interrogate_wrapper_comment(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_comment(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).get_comment().c_str(); -} - -bool -interrogate_wrapper_has_return_value(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_has_return_value(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).has_return_value(); -} - -TypeIndex -interrogate_wrapper_return_type(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_return_type(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).get_return_type(); -} - -bool -interrogate_wrapper_caller_manages_return_value(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_caller_manages_return_value(" << wrapper << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).caller_manages_return_value(); -} - -FunctionIndex -interrogate_wrapper_return_value_destructor(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_return_value_destructor(" << wrapper << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).get_return_value_destructor(); -} - -int -interrogate_wrapper_number_of_parameters(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_number_of_parameters(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).number_of_parameters(); -} - -TypeIndex -interrogate_wrapper_parameter_type(FunctionWrapperIndex wrapper, int n) { - // cerr << "interrogate_wrapper_parameter_type(" << wrapper << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).parameter_get_type(n); -} - -bool -interrogate_wrapper_parameter_has_name(FunctionWrapperIndex wrapper, int n) { - // cerr << "interrogate_wrapper_parameter_has_name(" << wrapper << ", " << n - // << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).parameter_has_name(n); -} - -const char * -interrogate_wrapper_parameter_name(FunctionWrapperIndex wrapper, int n) { - // cerr << "interrogate_wrapper_parameter_name(" << wrapper << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).parameter_get_name(n).c_str(); -} - -bool -interrogate_wrapper_parameter_is_this(FunctionWrapperIndex wrapper, int n) { - // cerr << "interrogate_wrapper_is_this(" << wrapper << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).parameter_is_this(n); -} - -bool -interrogate_wrapper_parameter_is_optional(FunctionWrapperIndex wrapper, int n) { - // cerr << "interrogate_wrapper_is_optional(" << wrapper << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper(wrapper).parameter_is_optional(n); -} - -bool -interrogate_wrapper_has_pointer(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_has_pointer(" << wrapper << ")\n"; - return (InterrogateDatabase::get_ptr()->get_fptr(wrapper) != nullptr); -} - -void * -interrogate_wrapper_pointer(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_pointer(" << wrapper << ")\n"; - return InterrogateDatabase::get_ptr()->get_fptr(wrapper); -} - -const char * -interrogate_wrapper_unique_name(FunctionWrapperIndex wrapper) { - // cerr << "interrogate_wrapper_unique_name(" << wrapper << ")\n"; - static string result; - result = InterrogateDatabase::get_ptr()->get_wrapper(wrapper).get_unique_name(); - return result.c_str(); -} - -FunctionWrapperIndex -interrogate_get_wrapper_by_unique_name(const char *unique_name) { - // cerr << "interrogate_get_wrapper_by_unique_name(" << unique_name << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_wrapper_by_unique_name(unique_name); -} - -const char * -interrogate_make_seq_seq_name(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_seq_name(" << make_seq << ")\n"; - static string result; - result = InterrogateDatabase::get_ptr()->get_make_seq(make_seq).get_name(); - return result.c_str(); -} - -const char * -interrogate_make_seq_scoped_name(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_seq_name(" << make_seq << ")\n"; - static string result; - result = InterrogateDatabase::get_ptr()->get_make_seq(make_seq).get_scoped_name(); - return result.c_str(); -} - -bool -interrogate_make_seq_has_comment(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_has_comment(" << make_seq << ")\n"; - return InterrogateDatabase::get_ptr()->get_make_seq(make_seq).has_comment(); -} - -const char * -interrogate_make_seq_comment(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_comment(" << make_seq << ")\n"; - return InterrogateDatabase::get_ptr()->get_make_seq(make_seq).get_comment().c_str(); -} - -const char * -interrogate_make_seq_num_name(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_num_name(" << make_seq << ")\n"; - FunctionIndex function = InterrogateDatabase::get_ptr()->get_make_seq(make_seq).get_length_getter(); - return interrogate_function_name(function); -} - -const char * -interrogate_make_seq_element_name(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_element_name(" << make_seq << ")\n"; - FunctionIndex function = InterrogateDatabase::get_ptr()->get_make_seq(make_seq).get_element_getter(); - return interrogate_function_name(function); -} - -FunctionIndex -interrogate_make_seq_num_getter(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_num_getter(" << make_seq << ")\n"; - return InterrogateDatabase::get_ptr()->get_make_seq(make_seq).get_length_getter(); -} - -FunctionIndex -interrogate_make_seq_element_getter(MakeSeqIndex make_seq) { - // cerr << "interrogate_make_seq_element_getter(" << make_seq << ")\n"; - return InterrogateDatabase::get_ptr()->get_make_seq(make_seq).get_element_getter(); -} - -int -interrogate_number_of_global_types() { - // cerr << "interrogate_number_of_global_types()\n"; - return InterrogateDatabase::get_ptr()->get_num_global_types(); -} - -TypeIndex -interrogate_get_global_type(int n) { - // cerr << "interrogate_get_global_type(" << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_global_type(n); -} - -int -interrogate_number_of_types() { - // cerr << "interrogate_number_of_types()\n"; - return InterrogateDatabase::get_ptr()->get_num_all_types(); -} - -TypeIndex -interrogate_get_type(int n) { - // cerr << "interrogate_get_type(" << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_all_type(n); -} - -TypeIndex -interrogate_get_type_by_name(const char *type_name) { - // cerr << "interrogate_get_type_by_name(" << type_name << ")\n"; - return InterrogateDatabase::get_ptr()->lookup_type_by_name(type_name); -} - -TypeIndex -interrogate_get_type_by_scoped_name(const char *type_name) { - // cerr << "interrogate_get_type_by_scoped_name(" << type_name << ")\n"; - return InterrogateDatabase::get_ptr()->lookup_type_by_scoped_name(type_name); -} - -TypeIndex -interrogate_get_type_by_true_name(const char *type_name) { - // cerr << "interrogate_get_type_by_true_name(" << type_name << ")\n"; - return InterrogateDatabase::get_ptr()->lookup_type_by_true_name(type_name); -} - -bool -interrogate_type_is_global(TypeIndex type) { - // cerr << "interrogate_type_is_global(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_global(); -} - -bool -interrogate_type_is_deprecated(TypeIndex type) { - // cerr << "interrogate_type_is_deprecated(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_deprecated(); -} - -const char * -interrogate_type_name(TypeIndex type) { - // cerr << "interrogate_type_name(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_name().c_str(); -} - -const char * -interrogate_type_scoped_name(TypeIndex type) { - // cerr << "interrogate_type_scoped_name(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_scoped_name().c_str(); -} - -const char * -interrogate_type_true_name(TypeIndex type) { - // cerr << "interrogate_type_true_name(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_true_name().c_str(); -} - -bool -interrogate_type_is_nested(TypeIndex type) { - // cerr << "interrogate_type_is_nested(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_nested(); -} - -TypeIndex -interrogate_type_outer_class(TypeIndex type) { - // cerr << "interrogate_type_outer_class(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_outer_class(); -} - -bool -interrogate_type_has_comment(TypeIndex type) { - // cerr << "interrogate_type_has_comment(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).has_comment(); -} - -const char * -interrogate_type_comment(TypeIndex type) { - // cerr << "interrogate_type_comment(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_comment().c_str(); -} - -bool -interrogate_type_has_module_name(TypeIndex type) { - // cerr << "interrogate_type_has_module_name(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).has_module_name(); -} - -const char * -interrogate_type_module_name(TypeIndex type) { - // cerr << "interrogate_type_module_name(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_module_name(); -} - -bool -interrogate_type_has_library_name(TypeIndex type) { - // cerr << "interrogate_type_has_library_name(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).has_library_name(); -} - -const char * -interrogate_type_library_name(TypeIndex type) { - // cerr << "interrogate_type_library_name(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_library_name(); -} - - -bool -interrogate_type_is_atomic(TypeIndex type) { - // cerr << "interrogate_type_is_atomic(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_atomic(); -} - -AtomicToken -interrogate_type_atomic_token(TypeIndex type) { - // cerr << "interrogate_type_atomic_token(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_atomic_token(); -} - -bool -interrogate_type_is_unsigned(TypeIndex type) { - // cerr << "interrogate_type_is_unsigned(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_unsigned(); -} - -bool -interrogate_type_is_signed(TypeIndex type) { - // cerr << "interrogate_type_is_signed(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_signed(); -} - -bool -interrogate_type_is_long(TypeIndex type) { - // cerr << "interrogate_type_is_long(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_long(); -} - -bool -interrogate_type_is_longlong(TypeIndex type) { - // cerr << "interrogate_type_is_longlong(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_longlong(); -} - -bool -interrogate_type_is_short(TypeIndex type) { - // cerr << "interrogate_type_is_short(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_short(); -} - -bool -interrogate_type_is_wrapped(TypeIndex type) { - // cerr << "interrogate_type_is_wrapped(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_wrapped(); -} - -bool -interrogate_type_is_pointer(TypeIndex type) { - // cerr << "interrogate_type_is_pointer(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_pointer(); -} - -bool -interrogate_type_is_const(TypeIndex type) { - // cerr << "interrogate_type_is_const(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_const(); -} - -bool -interrogate_type_is_typedef(TypeIndex type) { - // cerr << "interrogate_type_is_typedef(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_typedef(); -} - -TypeIndex -interrogate_type_wrapped_type(TypeIndex type) { - // cerr << "interrogate_type_wrapped_type(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_wrapped_type(); -} - -bool -interrogate_type_is_array(TypeIndex type) { - // cerr << "interrogate_type_is_array(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_array(); -} - -int -interrogate_type_array_size(TypeIndex type) { - // cerr << "interrogate_type_array_size(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_array_size(); -} - -bool -interrogate_type_is_enum(TypeIndex type) { - // cerr << "interrogate_type_is_enum(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_enum(); -} - -bool -interrogate_type_is_scoped_enum(TypeIndex type) { - // cerr << "interrogate_type_is_scoped_enum(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_scoped_enum(); -} - -int -interrogate_type_number_of_enum_values(TypeIndex type) { - // cerr << "interrogate_type_number_of_enum_values(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_enum_values(); -} - -const char * -interrogate_type_enum_value_name(TypeIndex type, int n) { - // cerr << "interrogate_type_enum_value_name(" << type << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_enum_value_name(n).c_str(); -} - -const char * -interrogate_type_enum_value_scoped_name(TypeIndex type, int n) { - // cerr << "interrogate_type_enum_value_scoped_name(" << type << ", " << n - // << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_enum_value_scoped_name(n).c_str(); -} - -const char * -interrogate_type_enum_value_comment(TypeIndex type, int n) { - // cerr << "interrogate_type_enum_value_comment(" << type << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_enum_value_comment(n).c_str(); -} - -int -interrogate_type_enum_value(TypeIndex type, int n) { - // cerr << "interrogate_type_enum_value(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_enum_value(n); -} - -bool -interrogate_type_is_struct(TypeIndex type) { - // cerr << "interrogate_type_is_struct(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_struct(); -} - -bool -interrogate_type_is_class(TypeIndex type) { - // cerr << "interrogate_type_is_class(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_class(); -} - -bool -interrogate_type_is_union(TypeIndex type) { - // cerr << "interrogate_type_is_union(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_union(); -} - -bool -interrogate_type_is_fully_defined(TypeIndex type) { - // cerr << "interrogate_type_is_fully_defined(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_fully_defined(); -} - -bool -interrogate_type_is_unpublished(TypeIndex type) { - // cerr << "interrogate_type_is_unpublished(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_unpublished(); -} - -int -interrogate_type_number_of_constructors(TypeIndex type) { - // cerr << "interrogate_type_number_of_constructors(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_constructors(); -} - -FunctionIndex -interrogate_type_get_constructor(TypeIndex type, int n) { - // cerr << "interrogate_type_get_constructor(" << type << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_constructor(n); -} - -bool -interrogate_type_has_destructor(TypeIndex type) { - // cerr << "interrogate_type_has_destructor(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).has_destructor(); -} - -bool -interrogate_type_destructor_is_inherited(TypeIndex type) { - // cerr << "interrogate_type_destructor_is_inherited(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).destructor_is_inherited(); -} - -FunctionIndex -interrogate_type_get_destructor(TypeIndex type) { - // cerr << "interrogate_type_get_destructor(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_destructor(); -} - -int -interrogate_type_number_of_elements(TypeIndex type) { - // cerr << "interrogate_type_number_of_elements(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_elements(); -} - -ElementIndex -interrogate_type_get_element(TypeIndex type, int n) { - // cerr << "interrogate_type_get_element(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_element(n); -} - -int -interrogate_type_number_of_methods(TypeIndex type) { - // cerr << "interrogate_type_number_of_methods(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_methods(); -} - -FunctionIndex -interrogate_type_get_method(TypeIndex type, int n) { - // cerr << "interrogate_type_get_method(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_method(n); -} - -int -interrogate_type_number_of_make_seqs(TypeIndex type) { - // cerr << "interrogate_type_number_of_make_seqs(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_make_seqs(); -} - -MakeSeqIndex -interrogate_type_get_make_seq(TypeIndex type, int n) { - // cerr << "interrogate_type_get_make_seq(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_make_seq(n); -} - -int -interrogate_type_number_of_casts(TypeIndex type) { - // cerr << "interrogate_type_number_of_casts(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_casts(); -} - -FunctionIndex -interrogate_type_get_cast(TypeIndex type, int n) { - // cerr << "interrogate_type_get_cast(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_cast(n); -} - -int -interrogate_type_number_of_derivations(TypeIndex type) { - // cerr << "interrogate_type_number_of_derivations(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_derivations(); -} - -TypeIndex -interrogate_type_get_derivation(TypeIndex type, int n) { - // cerr << "interrogate_type_get_derivation(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_derivation(n); -} - -bool -interrogate_type_is_final(TypeIndex type) { - // cerr << "interrogate_type_is_final(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).is_final(); -} - -bool -interrogate_type_derivation_has_upcast(TypeIndex type, int n) { - // cerr << "interrogate_type_derivation_has_upcast(" << type << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).derivation_has_upcast(n); -} - -FunctionIndex -interrogate_type_get_upcast(TypeIndex type, int n) { - // cerr << "interrogate_type_get_upcast(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).derivation_get_upcast(n); -} - -bool -interrogate_type_derivation_downcast_is_impossible(TypeIndex type, int n) { - // cerr << "interrogate_type_derivation_downcast_is_impossible(" << type << - // ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).derivation_downcast_is_impossible(n); -} - -bool -interrogate_type_derivation_has_downcast(TypeIndex type, int n) { - // cerr << "interrogate_type_derivation_has_downcast(" << type << ", " << n - // << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).derivation_has_downcast(n); -} - -FunctionIndex -interrogate_type_get_downcast(TypeIndex type, int n) { - // cerr << "interrogate_type_get_downcast(" << type << ", " << n << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).derivation_get_downcast(n); -} - -int -interrogate_type_number_of_nested_types(TypeIndex type) { - // cerr << "interrogate_type_number_of_nested_types(" << type << ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).number_of_nested_types(); -} - -TypeIndex -interrogate_type_get_nested_type(TypeIndex type, int n) { - // cerr << "interrogate_type_get_nested_type(" << type << ", " << n << - // ")\n"; - return InterrogateDatabase::get_ptr()->get_type(type).get_nested_type(n); -} diff --git a/dtool/src/interrogatedb/interrogate_interface.h b/dtool/src/interrogatedb/interrogate_interface.h deleted file mode 100644 index 6ae1bdcb24f..00000000000 --- a/dtool/src/interrogatedb/interrogate_interface.h +++ /dev/null @@ -1,581 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate_interface.h - * @author frang - * @date 1999-11-09 - */ - -#ifndef INTERROGATE_INTERFACE_H -#define INTERROGATE_INTERFACE_H - -#include "dtoolbase.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// This file defines the interface to the interrogate database. This database -// is generated by running interrogate on a package's source code; interrogate -// parses the C++ syntax, determines the public interface, generates C-style -// wrapper functions where necessary, and builds up a table of functions and -// classes and their relationships. - -/* - * Some of this data (in particular, the wrapper functions, and the table of - * unique names for these functions) is linked in along with the codebase, - * permanently a part of the library file, and is always available; the rest - * of it is stored in external files (named *.in) and read in when needed. - * For this reason, most of the interface functions defined here will force a - * load of the complete interrogate database the first time any of them are - * called. The three exceptions are noted below; they are - * interrogate_wrapper_has_pointer(), interrogate_wrapper_pointer(), and - * interrogate_get_wrapper_by_unique_name(). - */ - - -// The interface here is intentionally made to be as simple as possible, to -// maximize portability. All that is required of a scripting language is a -// foreign function interface capable of calling C functions. - - -// In general, the interrogate database consists of a number of query -// functions that allow the caller to walk through the list of available -// types, functions, manifests, etc. For each of these, a unique index number -// is returned; this index number may then be used to query details about the -// type, function, etc. The index numbers are only guaranteed to remain -// unchanged during a particular session; from one session to another they may -// differ. - -// All index numbers are ordinary integers. Each has a unique typedef here -// for clarity of meaning, but they may be treated as ordinary integers by the -// caller. -typedef int ManifestIndex; -typedef int ElementIndex; -typedef int TypeIndex; -typedef int FunctionIndex; -typedef int FunctionWrapperIndex; -typedef int MakeSeqIndex; - -// Atomic types are those that are built in to C. This enumerated value is -// returned by interrogate_type_atomic_token() when a type is known to be one -// of the atomic types. -enum AtomicToken { - AT_not_atomic = 0, - AT_int = 1, - AT_float = 2, - AT_double = 3, - AT_bool = 4, - AT_char = 5, - AT_void = 6, - - // There isn't an atomic string type in C, but there is one in almost all - // other languages. If -string is supplied to the interrogate command line, - // functions may be reported as returning and accepting objects of type - // atomic string. For the C calling convention wrappers, atomic string - // means (const char *); for other calling convention wrappers, atomic - // string means whatever the native string representation is. - AT_string = 7, - - AT_longlong = 8, - - // This is not a type that C has, but C++ and many scripting languages do; - // it indicates a null value, or the absence of any value. - AT_null = 9, -}; - -EXPCL_INTERROGATEDB void interrogate_add_search_directory(const char *dirname); -EXPCL_INTERROGATEDB void interrogate_add_search_path(const char *pathstring); -EXPCL_INTERROGATEDB bool interrogate_error_flag(); - -// Manifest Symbols - -/* - * These correspond to #define constants that appear in the C code. (These - * are only the manifest constants--those #define's that take no parameters. - * Manifest functions, #define's that take one or more parameters, are not - * exported.) They cannot be set, of course, but they often have a meaningful - * value that may be get. The scripting language may choose to get the value - * as a literal string via interrogate_manifest_definition(), or as a value of - * a particular type (whatever type interrogate thinks it is), as returned by - * the getter function given by interrogate_manifest_getter(). - */ - -EXPCL_INTERROGATEDB int interrogate_number_of_manifests(); -EXPCL_INTERROGATEDB ManifestIndex interrogate_get_manifest(int n); -EXPCL_INTERROGATEDB ManifestIndex interrogate_get_manifest_by_name(const char *manifest_name); -EXPCL_INTERROGATEDB const char *interrogate_manifest_name(ManifestIndex manifest); -EXPCL_INTERROGATEDB const char *interrogate_manifest_definition(ManifestIndex manifest); -EXPCL_INTERROGATEDB bool interrogate_manifest_has_type(ManifestIndex manifest); -EXPCL_INTERROGATEDB TypeIndex interrogate_manifest_get_type(ManifestIndex manifest); -EXPCL_INTERROGATEDB bool interrogate_manifest_has_getter(ManifestIndex manifest); -EXPCL_INTERROGATEDB FunctionIndex interrogate_manifest_getter(ManifestIndex manifest); - -// An exception is made for manifest constants that have an integer type -// value, since these are so common. The scripting language can query these -// values directly, which saves having to generate a wrapper function for each -// stupid little manifest. In this case, there will be no getter function -// available. -EXPCL_INTERROGATEDB bool interrogate_manifest_has_int_value(ManifestIndex manifest); -EXPCL_INTERROGATEDB int interrogate_manifest_get_int_value(ManifestIndex manifest); - - -// Data Elements - -// These correspond to data members of a class, or global data elements. -// Interrogate automatically generates a getter function and, if possible, a -// setter function. - -EXPCL_INTERROGATEDB const char *interrogate_element_name(ElementIndex element); -EXPCL_INTERROGATEDB const char *interrogate_element_scoped_name(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_has_comment(ElementIndex element); -EXPCL_INTERROGATEDB const char *interrogate_element_comment(ElementIndex element); -EXPCL_INTERROGATEDB ElementIndex interrogate_get_element_by_name(const char *element_name); -EXPCL_INTERROGATEDB ElementIndex interrogate_get_element_by_scoped_name(const char *element_name); - -// Be careful with this function. The element's bare type is not likely to be -// directly useful to the scripting language. This is a different answer than -// the return value of the getter. - -// The element type might well be something concrete that the scripting -// language can't handle directly, e.g. a Node, while the getter will return -// (and the setter accept) a pointer to a Node, which is what the scripting -// language actually works with. -EXPCL_INTERROGATEDB TypeIndex interrogate_element_type(ElementIndex element); - -EXPCL_INTERROGATEDB bool interrogate_element_has_getter(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_getter(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_has_setter(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_setter(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_has_has_function(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_has_function(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_has_clear_function(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_clear_function(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_has_del_function(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_del_function(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_has_insert_function(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_insert_function(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_has_getkey_function(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_getkey_function(ElementIndex element); -EXPCL_INTERROGATEDB FunctionIndex interrogate_element_length_function(ElementIndex element); - -EXPCL_INTERROGATEDB bool interrogate_element_is_sequence(ElementIndex element); -EXPCL_INTERROGATEDB bool interrogate_element_is_mapping(ElementIndex element); - -// Global Data - -// This is the list of global data elements. - -EXPCL_INTERROGATEDB int interrogate_number_of_globals(); -EXPCL_INTERROGATEDB ElementIndex interrogate_get_global(int n); - -// Functions - -// There is a unique FunctionIndex associated with each of the functions that -// interrogate knows about. This includes member functions, nonmember -// functions, synthesized getters and setters, and upcastdowncast functions. - - -// These are the global (nonmember) functions that appear outside of any class -// definition. -EXPCL_INTERROGATEDB int interrogate_number_of_global_functions(); -EXPCL_INTERROGATEDB FunctionIndex interrogate_get_global_function(int n); - -// This can be used to traverse through *all* the functions known to -// interrogate. It's usually not what you want, since this includes global -// functions, class methods, and synthesized functions like upcasts and -// downcasts. You probably want to use instead -// interrogate_number_of_global_functions(), above. -EXPCL_INTERROGATEDB int interrogate_number_of_functions(); -EXPCL_INTERROGATEDB FunctionIndex interrogate_get_function(int n); - -// This is the function's name. It is not unique; it may be shared between -// multiple different functions that have the same name but different -// parameter types (this is C++'s function overloading). Two different classes -// might also have member functions that have the same name, or the same name -// as a global function (but also see the scoped_name, below). -EXPCL_INTERROGATEDB const char *interrogate_function_name(FunctionIndex function); - -// The scoped name is the function name prefixed with the name of the class -// that includes the function, if the function is a class method. If it is a -// global function, the scoped name is the same as the name returned above. -// In the absence of C++ function overloading, this name will be unique to -// each function. -EXPCL_INTERROGATEDB const char *interrogate_function_scoped_name(FunctionIndex function); - -// This returns the C++ comment written for the function, either in the header -// file or in the .C file, or both. -EXPCL_INTERROGATEDB bool interrogate_function_has_comment(FunctionIndex function); -EXPCL_INTERROGATEDB const char *interrogate_function_comment(FunctionIndex function); - -// This defines the function prototype as it appears in the C++ source, useful -// primarily for documentation purposes. -EXPCL_INTERROGATEDB const char *interrogate_function_prototype(FunctionIndex function); - -// This can be used to determine the class that the function is a method for, -// if the function is a class method. -EXPCL_INTERROGATEDB bool interrogate_function_is_method(FunctionIndex function); -EXPCL_INTERROGATEDB TypeIndex interrogate_function_class(FunctionIndex function); -EXPCL_INTERROGATEDB bool interrogate_function_is_unary_op(FunctionIndex function); -EXPCL_INTERROGATEDB bool interrogate_function_is_operator_typecast(FunctionIndex function); -EXPCL_INTERROGATEDB bool interrogate_function_is_constructor(FunctionIndex function); -EXPCL_INTERROGATEDB bool interrogate_function_is_destructor(FunctionIndex function); - -// This returns the module name reported for the function, if available. -EXPCL_INTERROGATEDB bool interrogate_function_has_module_name(FunctionIndex function); -EXPCL_INTERROGATEDB const char *interrogate_function_module_name(FunctionIndex function); - -// This returns the library name reported for the function, if available. -EXPCL_INTERROGATEDB bool interrogate_function_has_library_name(FunctionIndex function); -EXPCL_INTERROGATEDB const char *interrogate_function_library_name(FunctionIndex function); - -// This is true for virtual member functions. It's not likely that this will -// be important to the scripting language. -EXPCL_INTERROGATEDB bool interrogate_function_is_virtual(FunctionIndex function); - - -// The actual callable function interface is defined via one or more wrappers -// for each function. (There might be multiple wrappers for the same function -// to allow for default parameter values.) - -// At present, interrogate can generate wrappers that use the C calling -// convention or the Python calling convention. The set of wrappers that will -// actually be available depends on the parameters passed to the interrogate -// command line. -EXPCL_INTERROGATEDB int interrogate_function_number_of_c_wrappers(FunctionIndex function); -EXPCL_INTERROGATEDB FunctionWrapperIndex interrogate_function_c_wrapper(FunctionIndex function, int n); - -EXPCL_INTERROGATEDB int interrogate_function_number_of_python_wrappers(FunctionIndex function); -EXPCL_INTERROGATEDB FunctionWrapperIndex interrogate_function_python_wrapper(FunctionIndex function, int n); - -// Function wrappers - -// These define the way to call a given function. Depending on the parameters -// supplied to interrogate, a function wrapper may be able to supply either a -// void * pointer to the function, or the name of the function in the library, -// or both. - - -// This returns the actual name of the wrapper function, as opposed to the -// name of the function it wraps. It's probably not terribly useful to the -// scripting language, unless the -fnames option was given to interrogate, in -// which case this name may be used to call the wrapper function (see -// is_callable_by_name, below). It will usually be an ugly hashed name, not -// intended for human consumption. - -// Don't confuse this with the unique_name, below. The two are related, but -// not identical. -EXPCL_INTERROGATEDB const char *interrogate_wrapper_name(FunctionWrapperIndex wrapper); - -// Returns the function that this wrapper belongs to. -EXPCL_INTERROGATEDB FunctionIndex interrogate_wrapper_function(FunctionWrapperIndex wrapper); - -// This returns true if -fnames was given to interrogate, making the wrapper -// function callable directly by its name. -EXPCL_INTERROGATEDB bool interrogate_wrapper_is_callable_by_name(FunctionWrapperIndex wrapper); - -// This returns true if this is a copy constructor. -EXPCL_INTERROGATEDB bool interrogate_wrapper_is_copy_constructor(FunctionWrapperIndex wrapper); - -// This returns true if this is a constructor that is not marked "explicit". -EXPCL_INTERROGATEDB bool interrogate_wrapper_is_coerce_constructor(FunctionWrapperIndex wrapper); - -// This returns true if this is an extension function, rather than a real -// function defined in the C++ code. -EXPCL_INTERROGATEDB bool interrogate_wrapper_is_extension(FunctionWrapperIndex wrapper); - -// This returns true if function is marked as deprecated. -EXPCL_INTERROGATEDB bool interrogate_wrapper_is_deprecated(FunctionWrapperIndex wrapper); - -// This returns the C++ comment written for the function wrapper, usually from -// the .cpp file. There may be a different comment for each overload of a -// given function. -EXPCL_INTERROGATEDB bool interrogate_wrapper_has_comment(FunctionWrapperIndex wrapper); -EXPCL_INTERROGATEDB const char *interrogate_wrapper_comment(FunctionWrapperIndex wrapper); - -// Every function wrapper has zero or more parameters and may or may not have -// a return value. Each parameter has a type and may or may not have a name. -// For member functions, the first parameter may be a 'this' parameter, which -// should receive a pointer to the class object. (If a member function does -// not have a 'this' parameter as its first parameter, it is a static member -// function, also called a class method.) - -EXPCL_INTERROGATEDB bool interrogate_wrapper_has_return_value(FunctionWrapperIndex wrapper); -EXPCL_INTERROGATEDB TypeIndex interrogate_wrapper_return_type(FunctionWrapperIndex wrapper); - -/* - * Sometimes interrogate must synthesize a wrapper that allocates its return - * value from the free store. Other times (especially if -refcount is - * supplied to interrogate), interrogate will automatically increment the - * count of a reference-counted object that it returns. In cases like these, - * interrogate_wrapper_caller_manages_return_value() will return true, and it - * is the responsibility of the scripting language to eventually call the - * destructor supplied by interrogate_wrapper_return_value_destructor() on - * this value when it is no longer needed (which will generally be the same - * destructor as that for the class). Otherwise, this function will return - * false, and the scripting language should *not* call any destructor on this - * value. - */ -EXPCL_INTERROGATEDB bool interrogate_wrapper_caller_manages_return_value(FunctionWrapperIndex wrapper); -EXPCL_INTERROGATEDB FunctionIndex interrogate_wrapper_return_value_destructor(FunctionWrapperIndex wrapper); - -// These define the parameters of the function. -EXPCL_INTERROGATEDB int interrogate_wrapper_number_of_parameters(FunctionWrapperIndex wrapper); -EXPCL_INTERROGATEDB TypeIndex interrogate_wrapper_parameter_type(FunctionWrapperIndex wrapper, int n); -EXPCL_INTERROGATEDB bool interrogate_wrapper_parameter_has_name(FunctionWrapperIndex wrapper, int n); -EXPCL_INTERROGATEDB const char *interrogate_wrapper_parameter_name(FunctionWrapperIndex wrapper, int n); -EXPCL_INTERROGATEDB bool interrogate_wrapper_parameter_is_this(FunctionWrapperIndex wrapper, int n); -EXPCL_INTERROGATEDB bool interrogate_wrapper_parameter_is_optional(FunctionWrapperIndex wrapper, int n); - -// This returns a pointer to a function that may be called to invoke the -// function, if the -fptrs option to return function pointers was specified to -// interrogate. Be sure to push the required parameters on the stack, -// according to the calling convention, before calling the function. - -// These two functions may be called without forcing a load of the complete -// interrogate database. -EXPCL_INTERROGATEDB bool interrogate_wrapper_has_pointer(FunctionWrapperIndex wrapper); -EXPCL_INTERROGATEDB void *interrogate_wrapper_pointer(FunctionWrapperIndex wrapper); - -// This function will return a name that is guaranteed to be unique to this -// particular function wrapper, and that will (usually) be consistent across -// multiple runtime sessions. (It will only change between sessions if the -// database was regenerated in the interim with some new function that -// happened to introduce a hash conflict.) - -// The unique name is an ugly hashed name, not safe for human consumption. -// Its sole purpose is to provide some consistent way to identify function -// wrappers between sessions. -EXPCL_INTERROGATEDB const char *interrogate_wrapper_unique_name(FunctionWrapperIndex wrapper); - -// This function provides a reverse-lookup on the above unique name, returning -// the wrapper index corresponding to the given name. It depends on data -// having been compiled directly into the library, and thus is only available -// if the option -unique-names was given to interrogate. - -// This function may be called without forcing a load of the complete -// interrogate database. -EXPCL_INTERROGATEDB FunctionWrapperIndex interrogate_get_wrapper_by_unique_name(const char *unique_name); - -// MakeSeqs - -// These are special synthesized methods that iterate through a list. They -// are generated in C++ code via the MAKE_SEQ macro. The normal pattern is -// that a pair of actual C++ methods like get_num_things() and get_thing(n) -// are used to synthesize a new method called get_things(). - -EXPCL_INTERROGATEDB const char *interrogate_make_seq_seq_name(MakeSeqIndex make_seq); -EXPCL_INTERROGATEDB const char *interrogate_make_seq_scoped_name(MakeSeqIndex make_seq); -EXPCL_INTERROGATEDB bool interrogate_make_seq_has_comment(ElementIndex element); -EXPCL_INTERROGATEDB const char *interrogate_make_seq_comment(ElementIndex element); -// The name of the real method that returns the length, e.g. "get_num_things" -EXPCL_INTERROGATEDB const char *interrogate_make_seq_num_name(MakeSeqIndex make_seq); -// The name of the real method that returns the nth element, e.g. "get_thing" -EXPCL_INTERROGATEDB const char *interrogate_make_seq_element_name(MakeSeqIndex make_seq); -EXPCL_INTERROGATEDB FunctionIndex interrogate_make_seq_num_getter(MakeSeqIndex make_seq); -EXPCL_INTERROGATEDB FunctionIndex interrogate_make_seq_element_getter(MakeSeqIndex make_seq); - -// Types - -// These are all the types that interrogate knows about. This includes atomic -// types like ints and floats, type wrappers like pointers and const pointers, -// enumerated types, and classes. - -/* - * Two lists of types are maintained: the list of global types, which includes - * only those types intended to be wrapped in the API (for instance, all of - * the classes). The second list is the complete list of all types, which - * probably does not need to be traversed--this includes *all* types known to - * the interrogate database, including simple types and pointers and const - * pointers to classes. These types are necessary to fully define all of the - * function parameters, but need not themselves be wrapped. - */ - -EXPCL_INTERROGATEDB int interrogate_number_of_global_types(); -EXPCL_INTERROGATEDB TypeIndex interrogate_get_global_type(int n); -EXPCL_INTERROGATEDB int interrogate_number_of_types(); -EXPCL_INTERROGATEDB TypeIndex interrogate_get_type(int n); -EXPCL_INTERROGATEDB TypeIndex interrogate_get_type_by_name(const char *type_name); -EXPCL_INTERROGATEDB TypeIndex interrogate_get_type_by_scoped_name(const char *type_name); -EXPCL_INTERROGATEDB TypeIndex interrogate_get_type_by_true_name(const char *type_name); -EXPCL_INTERROGATEDB bool interrogate_type_is_global(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_deprecated(TypeIndex type); -EXPCL_INTERROGATEDB const char *interrogate_type_name(TypeIndex type); -EXPCL_INTERROGATEDB const char *interrogate_type_scoped_name(TypeIndex type); -EXPCL_INTERROGATEDB const char *interrogate_type_true_name(TypeIndex type); - -// A given type might be a nested type, meaning it is entirely defined within -// (and scoped within) some different C++ class. In this case, the -// type_name() will return the local name of the type as seen within the -// class, while the scoped_name() will return the fully-qualified name of the -// type, and is_nested() and outer_class() can be used to determine the class -// it is nested within. -EXPCL_INTERROGATEDB bool interrogate_type_is_nested(TypeIndex type); -EXPCL_INTERROGATEDB TypeIndex interrogate_type_outer_class(TypeIndex type); - -EXPCL_INTERROGATEDB bool interrogate_type_has_comment(TypeIndex type); -EXPCL_INTERROGATEDB const char *interrogate_type_comment(TypeIndex type); - -// This returns the module name reported for the type, if available. -EXPCL_INTERROGATEDB bool interrogate_type_has_module_name(TypeIndex type); -EXPCL_INTERROGATEDB const char *interrogate_type_module_name(TypeIndex type); - -// This returns the library name reported for the type, if available. -EXPCL_INTERROGATEDB bool interrogate_type_has_library_name(TypeIndex type); -EXPCL_INTERROGATEDB const char *interrogate_type_library_name(TypeIndex type); - - -// If interrogate_type_is_atomic() returns true, the type is one of the basic -// C types enumerated in AtomicToken, above. The type may then be further -// modified by one or more of unsigned, signed, long, longlong, or short. -// However, it will not be a pointer. -EXPCL_INTERROGATEDB bool interrogate_type_is_atomic(TypeIndex type); -EXPCL_INTERROGATEDB AtomicToken interrogate_type_atomic_token(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_unsigned(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_signed(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_long(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_longlong(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_short(TypeIndex type); - -// If interrogate_type_is_wrapped() returns true, this is a composite type -// "wrapped" around some simpler type, for instance a pointer to a class. The -// type will be either a pointer or a const wrapper--it cannot be a -// combination of these. (When combinations are required, they use multiple -// wrappers. A const char pointer, for example, is represented as a pointer -// wrapper around a const wrapper around an atomic char.) -EXPCL_INTERROGATEDB bool interrogate_type_is_wrapped(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_pointer(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_const(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_typedef(TypeIndex type); -EXPCL_INTERROGATEDB TypeIndex interrogate_type_wrapped_type(TypeIndex type); - -// If interrogate_type_is_array() returns true, this is an array type. -EXPCL_INTERROGATEDB bool interrogate_type_is_array(TypeIndex type); -EXPCL_INTERROGATEDB int interrogate_type_array_size(TypeIndex type); - -// If interrogate_type_is_enum() returns true, this is an enumerated type, -// which means it may take any one of a number of named integer values. -EXPCL_INTERROGATEDB bool interrogate_type_is_enum(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_scoped_enum(TypeIndex type); -EXPCL_INTERROGATEDB int interrogate_type_number_of_enum_values(TypeIndex type); -EXPCL_INTERROGATEDB const char *interrogate_type_enum_value_name(TypeIndex type, int n); -EXPCL_INTERROGATEDB const char *interrogate_type_enum_value_scoped_name(TypeIndex type, int n); -EXPCL_INTERROGATEDB const char *interrogate_type_enum_value_comment(TypeIndex type, int n); -EXPCL_INTERROGATEDB int interrogate_type_enum_value(TypeIndex type, int n); - -// If none of the above is true, the type is some extension type. It may be a -// struct, class, or union (and the distinction between these three is not -// likely to be important to the scripting language). In any case, it may -// contain zero or more constructors, zero or one destructor, zero or more -// member functions, and zero or more data members; all of the remaining type -// functions may apply. -EXPCL_INTERROGATEDB bool interrogate_type_is_struct(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_class(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_is_union(TypeIndex type); - -// If is_fully_defined() returns false, this classstruct was a forward -// reference, and we really don't know anything about it. (In this case, it -// will appear to have no methods or members.) -EXPCL_INTERROGATEDB bool interrogate_type_is_fully_defined(TypeIndex type); - -// If is_unpublished() returns false, the classstruct is unknown because it -// was not marked to be published (or, in promiscuous mode, it is a protected -// or private nested class). -EXPCL_INTERROGATEDB bool interrogate_type_is_unpublished(TypeIndex type); - -/* - * Otherwise, especially if the type is a struct or class, we may have a - * number of member functions, including zero or more constructors and zero or - * one destructor. A constructor function may be called to allocate a new - * instance of the type; its return value will be a pointer to the new - * instance. The destructor may be called to destroy the instance; however, - * it usually should not be explicitly called by the user, since the proper - * support of the interrogate_caller_manages_return_value() interface, above, - * will ensure that the appropriate destructors are called when they should - * be. - */ - -/* - * In certain circumstances, the destructor might be inherited from a parent - * or ancestor class. This happens when the destructor wrapper from the - * ancestor class is an acceptable substitute for this destructor; this is - * only possible in the case of a virtual C++ destructor. In this case, the - * destructor returned here will be the same function index as the one - * returned by the ancestor class, and - * interrogate_type_destructor_is_inherited() will return true for this class. - */ -EXPCL_INTERROGATEDB int interrogate_type_number_of_constructors(TypeIndex type); -EXPCL_INTERROGATEDB FunctionIndex interrogate_type_get_constructor(TypeIndex type, int n); -EXPCL_INTERROGATEDB bool interrogate_type_has_destructor(TypeIndex type); -EXPCL_INTERROGATEDB bool interrogate_type_destructor_is_inherited(TypeIndex type); -EXPCL_INTERROGATEDB FunctionIndex interrogate_type_get_destructor(TypeIndex type); - -// This is the set of exposed data elements in the struct or class. -EXPCL_INTERROGATEDB int interrogate_type_number_of_elements(TypeIndex type); -EXPCL_INTERROGATEDB ElementIndex interrogate_type_get_element(TypeIndex type, int n); - -// This is the set of exposed member functions in the struct or class. -EXPCL_INTERROGATEDB int interrogate_type_number_of_methods(TypeIndex type); -EXPCL_INTERROGATEDB FunctionIndex interrogate_type_get_method(TypeIndex type, int n); - -// This is the set of MAKE_SEQ wrappers in the struct or class. -EXPCL_INTERROGATEDB int interrogate_type_number_of_make_seqs(TypeIndex type); -EXPCL_INTERROGATEDB MakeSeqIndex interrogate_type_get_make_seq(TypeIndex type, int n); - -// A C++ class may also define a number of explicit cast operators, which -// define how to convert an object of this type to an object of some other -// type (the type can be inferred by the return type of the cast function). -// This is not related to upcast and downcast, defined below. -EXPCL_INTERROGATEDB int interrogate_type_number_of_casts(TypeIndex type); -EXPCL_INTERROGATEDB FunctionIndex interrogate_type_get_cast(TypeIndex type, int n); - -// A C++ class may inherit from zero or more base classes. This defines the -// list of base classes for this particular type. -EXPCL_INTERROGATEDB int interrogate_type_number_of_derivations(TypeIndex type); -EXPCL_INTERROGATEDB TypeIndex interrogate_type_get_derivation(TypeIndex type, int n); -EXPCL_INTERROGATEDB bool interrogate_type_is_final(TypeIndex type); - -// For each base class, we might need to define an explicit upcast or downcast -// operation to convert the pointer to the derived class to an appropriate -// pointer to its base class (upcast) or vice-versa (downcast). This is -// particularly true in the presence of multiple inheritance or virtual -// inheritance, in which case you cannot simply use the same pointer as either -// type. - -// If interrogate_type_derivation_has_upcast() returns true for a particular -// typederivation combination, you must use the indicated upcast function to -// convert pointers of this type to pointers of the base type before calling -// any of the inherited methods from the base class. If this returns false, -// you may simply use the same pointer as either a derived class pointer or a -// base class pointer without any extra step. -EXPCL_INTERROGATEDB bool interrogate_type_derivation_has_upcast(TypeIndex type, int n); -EXPCL_INTERROGATEDB FunctionIndex interrogate_type_get_upcast(TypeIndex type, int n); - -/* - * Although it is always possible to upcast a pointer to a base class, it is - * not always possible to downcast from a base class to the derived class - * (particularly in the presence of virtual inheritance). If - * interrogate_type_derivation_downcast_is_impossible() returns true, forget - * it. Otherwise, downcasting works the same way as upcasting. (Of course, - * it is the caller's responsibility to guarantee that the pointer actually - * represents an object of the type being downcast to.) - */ -EXPCL_INTERROGATEDB bool interrogate_type_derivation_downcast_is_impossible(TypeIndex type, int n); -EXPCL_INTERROGATEDB bool interrogate_type_derivation_has_downcast(TypeIndex type, int n); -EXPCL_INTERROGATEDB FunctionIndex interrogate_type_get_downcast(TypeIndex type, int n); - -// A C++ class may also define any number of nested types--classes or enums -// defined within the scope of this class. -EXPCL_INTERROGATEDB int interrogate_type_number_of_nested_types(TypeIndex type); -EXPCL_INTERROGATEDB TypeIndex interrogate_type_get_nested_type(TypeIndex type, int n); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/dtool/src/interrogatedb/interrogate_request.cxx b/dtool/src/interrogatedb/interrogate_request.cxx deleted file mode 100644 index 3e02a9eecb6..00000000000 --- a/dtool/src/interrogatedb/interrogate_request.cxx +++ /dev/null @@ -1,37 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file interrogate_request.cxx - * @author drose - * @date 2000-08-01 - */ - -#include "interrogate_request.h" -#include "interrogateDatabase.h" - -#include // for strdup - -void -interrogate_request_database(const char *database_filename) { - InterrogateModuleDef *def = new InterrogateModuleDef; - memset(def, 0, sizeof(InterrogateModuleDef)); -#ifdef _WIN32 - def->database_filename = _strdup(database_filename); -#else - def->database_filename = strdup(database_filename); -#endif - - // Don't think of this as a leak; think of it as a one-time database - // allocation. - InterrogateDatabase::get_ptr()->request_module(def); -} - -void -interrogate_request_module(InterrogateModuleDef *def) { - InterrogateDatabase::get_ptr()->request_module(def); -} diff --git a/dtool/src/interrogatedb/p3interrogatedb_composite1.cxx b/dtool/src/interrogatedb/p3interrogatedb_composite1.cxx deleted file mode 100644 index 4e54cee5a93..00000000000 --- a/dtool/src/interrogatedb/p3interrogatedb_composite1.cxx +++ /dev/null @@ -1,7 +0,0 @@ -#include "config_interrogatedb.cxx" -#include "indexRemapper.cxx" -#include "interrogateComponent.cxx" -#include "interrogateDatabase.cxx" -#include "interrogateElement.cxx" -#include "interrogateFunction.cxx" -#include "interrogateFunctionWrapper.cxx" diff --git a/dtool/src/interrogatedb/p3interrogatedb_composite2.cxx b/dtool/src/interrogatedb/p3interrogatedb_composite2.cxx deleted file mode 100644 index 41453e5f3e7..00000000000 --- a/dtool/src/interrogatedb/p3interrogatedb_composite2.cxx +++ /dev/null @@ -1,6 +0,0 @@ -#include "interrogateMakeSeq.cxx" -#include "interrogateManifest.cxx" -#include "interrogateType.cxx" -#include "interrogate_datafile.cxx" -#include "interrogate_interface.cxx" -#include "interrogate_request.cxx" diff --git a/dtool/src/interrogatedb/py_compat.cxx b/dtool/src/interrogatedb/py_compat.cxx deleted file mode 100644 index 722bc8300bd..00000000000 --- a/dtool/src/interrogatedb/py_compat.cxx +++ /dev/null @@ -1,46 +0,0 @@ -/** - * @file py_compat.cxx - * @author rdb - * @date 2017-12-03 - */ - -#include "py_compat.h" -#include "py_panda.h" - -#ifdef HAVE_PYTHON - -#if PY_MAJOR_VERSION < 3 -/** - * Given a long or int, returns a size_t, or raises an OverflowError if it is - * out of range. - */ -size_t PyLongOrInt_AsSize_t(PyObject *vv) { - if (PyInt_Check(vv)) { - long value = PyInt_AS_LONG(vv); - if (value < 0) { - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to size_t"); - return (size_t)-1; - } - return (size_t)value; - } - - if (!PyLong_Check(vv)) { - Dtool_Raise_TypeError("a long or int was expected"); - return (size_t)-1; - } - - size_t bytes; - int one = 1; - int res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, - SIZEOF_SIZE_T, (int)*(unsigned char*)&one, 0); - - if (res < 0) { - return (size_t)res; - } else { - return bytes; - } -} -#endif - -#endif // HAVE_PYTHON diff --git a/dtool/src/interrogatedb/py_compat.h b/dtool/src/interrogatedb/py_compat.h index 4b67fba763a..70c8b43e91a 100644 --- a/dtool/src/interrogatedb/py_compat.h +++ b/dtool/src/interrogatedb/py_compat.h @@ -65,7 +65,7 @@ typedef int Py_ssize_t; /* Python 2.6 */ -#ifndef Py_TYPE +#if PY_VERSION_HEX < 0x02060000 # define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) #endif @@ -189,6 +189,20 @@ INLINE PyObject *_PyObject_FastCall(PyObject *func, PyObject **args, Py_ssize_t } while (0) #endif +#if PY_VERSION_HEX < 0x03070000 +INLINE PyObject *PyImport_GetModule(PyObject *name) { + PyObject *modules = PyImport_GetModuleDict(); + if (modules != nullptr) { + PyObject *module = PyDict_GetItem(modules, name); + if (module != nullptr) { + Py_INCREF(module); + return module; + } + } + return nullptr; +} +#endif + /* Python 3.8 */ #if PY_VERSION_HEX < 0x03080000 INLINE PyObject *_PyLong_Rshift(PyObject *a, size_t shiftby) { @@ -207,8 +221,12 @@ INLINE PyObject *_PyLong_Lshift(PyObject *a, size_t shiftby) { /* Python 3.9 */ +#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE) +# define Py_IS_TYPE(ob, type) (Py_TYPE((PyObject *)ob) == type) +#endif + #ifndef PyCFunction_CheckExact -# define PyCFunction_CheckExact(op) (Py_TYPE(op) == &PyCFunction_Type) +# define PyCFunction_CheckExact(op) (Py_IS_TYPE(op, &PyCFunction_Type)) #endif #if PY_VERSION_HEX < 0x03090000 @@ -279,6 +297,77 @@ INLINE bool PyLong_IsNonNegative(PyObject *value) { } #endif +/* Python 3.13 */ + +#if PY_VERSION_HEX < 0x030D00A1 +# define PyLong_AsInt(x) (_PyLong_AsInt(x)) +#endif + +#if PY_VERSION_HEX < 0x030D00A1 +ALWAYS_INLINE int +PyModule_Add(PyObject *mod, const char *name, PyObject *value) { + int res = PyModule_AddObjectRef(mod, name, value); + Py_XDECREF(value); + return res; +} +#endif + +#if PY_VERSION_HEX < 0x030D00A1 +INLINE int +PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result) { +#if PY_MAJOR_VERSION >= 3 + PyObject *item = PyDict_GetItemWithError(mp, key); +#else + PyObject *item = _PyDict_GetItemWithError(mp, key); +#endif + if (item != nullptr) { + *result = Py_NewRef(item); + return 1; + } + *result = nullptr; + return PyErr_Occurred() ? -1 : 0; +} + +INLINE int +PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result) { + PyObject *item = nullptr; +#if PY_MAJOR_VERSION >= 3 + PyObject *key_obj = PyUnicode_FromString(key); + item = key_obj ? PyDict_GetItemWithError(mp, key_obj) : nullptr; +#else + PyObject *key_obj = PyString_FromString(key); + item = key_obj ? _PyDict_GetItemWithError(mp, key_obj) : nullptr; +#endif + Py_DECREF(key_obj); + if (item != nullptr) { + *result = Py_NewRef(item); + return 1; + } + *result = nullptr; + return PyErr_Occurred() ? -1 : 0; +} +#endif + +#if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1 +# define PyThreadState_GetUnchecked() (_PyThreadState_UncheckedGet()) +#endif + +#if PY_VERSION_HEX < 0x030D00A2 +# define PyList_Extend(list, iterable) (PyList_SetSlice((list), PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, (iterable))) +# define PyList_Clear(list) (PyList_SetSlice((list), 0, PY_SSIZE_T_MAX, nullptr)) +#endif + +#if PY_VERSION_HEX < 0x030D00A4 +# define PyList_GetItemRef(op, index) (Py_XNewRef(PyList_GetItem((op), (index)))) +#endif + +#if PY_VERSION_HEX < 0x030D00B3 +# define Py_BEGIN_CRITICAL_SECTION(op) { +# define Py_END_CRITICAL_SECTION() } +# define Py_BEGIN_CRITICAL_SECTION2(a, b) { +# define Py_END_CRITICAL_SECTION2() } +#endif + /* Other Python implementations */ #endif // HAVE_PYTHON diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx deleted file mode 100644 index b691fbef481..00000000000 --- a/dtool/src/interrogatedb/py_panda.cxx +++ /dev/null @@ -1,918 +0,0 @@ -/** - * @file py_panda.cxx - * @author drose - * @date 2005-07-04 - */ - -#include "py_panda.h" -#include "config_interrogatedb.h" -#include "executionEnvironment.h" - -#ifdef HAVE_PYTHON - -#define _STRINGIFY_VERSION(a, b) (#a "." #b) -#define STRINGIFY_VERSION(a, b) _STRINGIFY_VERSION(a, b) - -using std::string; - -/** - - */ -void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *classdef, void **answer) { - if (DtoolInstance_Check(self)) { - *answer = DtoolInstance_UPCAST(self, *classdef); - } else { - *answer = nullptr; - } -} - -/** - * This is a support function for the Python bindings: it extracts the - * underlying C++ pointer of the given type for a given Python object. If it - * was of the wrong type, raises an AttributeError. - */ -bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer) { - if (self == nullptr || !DtoolInstance_Check(self) || DtoolInstance_VOID_PTR(self) == nullptr) { - Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed."); - return false; - } - - *answer = DtoolInstance_UPCAST(self, classdef); - return true; -} - -/** - * The same thing as Dtool_Call_ExtractThisPointer, except that it performs - * the additional check that the pointer is a non-const pointer. This is - * called by function wrappers for functions of which all overloads are non- - * const, and saves a bit of code. - * - * The extra method_name argument is used in formatting the error message. - */ -bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef, - void **answer, const char *method_name) { - - if (self == nullptr || !DtoolInstance_Check(self) || DtoolInstance_VOID_PTR(self) == nullptr) { - Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed."); - return false; - } - - if (DtoolInstance_IS_CONST(self)) { - // All overloads of this function are non-const. - PyErr_Format(PyExc_TypeError, - "Cannot call %s() on a const object.", - method_name); - return false; - } - - *answer = DtoolInstance_UPCAST(self, classdef); - return true; -} - -/** - * Extracts the C++ pointer for an object, given its Python wrapper object, - * for passing as the parameter to a C++ function. - * - * self is the Python wrapper object in question. - * - * classdef is the Python class wrapper for the C++ class in which the this - * pointer should be returned. (This may require an upcast operation, if self - * is not already an instance of classdef.) - * - * param and function_name are used for error reporting only, and describe the - * particular function and parameter index for this parameter. - * - * const_ok is true if the function is declared const and can therefore be - * called with either a const or non-const "this" pointer, or false if the - * function is declared non-const, and can therefore be called with only a - * non-const "this" pointer. - * - * The return value is the C++ pointer that was extracted, or NULL if there - * was a problem (in which case the Python exception state will have been - * set). - */ -void * -DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, - int param, const string &function_name, bool const_ok, - bool report_errors) { - // if (PyErr_Occurred()) { return nullptr; } - if (self == nullptr) { - if (report_errors) { - return Dtool_Raise_TypeError("self is nullptr"); - } - return nullptr; - } - - if (DtoolInstance_Check(self)) { - void *result = DtoolInstance_UPCAST(self, *classdef); - - if (result != nullptr) { - if (const_ok || !DtoolInstance_IS_CONST(self)) { - return result; - } - - if (report_errors) { - return PyErr_Format(PyExc_TypeError, - "%s() argument %d may not be const", - function_name.c_str(), param); - } - return nullptr; - } - } - - if (report_errors) { - return Dtool_Raise_ArgTypeError(self, param, function_name.c_str(), classdef->_PyType.tp_name); - } - - return nullptr; -} - -/** - * This is similar to a PyErr_Occurred() check, except that it also checks - * Notify to see if an assertion has occurred. If that is the case, then it - * raises an AssertionError. - * - * Returns true if there is an active exception, false otherwise. - * - * In the NDEBUG case, this is simply a #define to PyErr_Occurred(). - */ -bool _Dtool_CheckErrorOccurred() { - if (PyErr_Occurred()) { - return true; - } - if (Notify::ptr()->has_assert_failed()) { - Dtool_Raise_AssertionError(); - return true; - } - return false; -} - -/** - * Raises an AssertionError containing the last thrown assert message, and - * clears the assertion flag. Returns NULL. - */ -PyObject *Dtool_Raise_AssertionError() { - Notify *notify = Notify::ptr(); -#if PY_MAJOR_VERSION >= 3 - PyObject *message = PyUnicode_FromString(notify->get_assert_error_message().c_str()); -#else - PyObject *message = PyString_FromString(notify->get_assert_error_message().c_str()); -#endif - PyErr_SetObject(PyExc_AssertionError, message); - notify->clear_assert_failed(); - return nullptr; -} - -/** - * Raises a TypeError with the given message, and returns NULL. - */ -PyObject *Dtool_Raise_TypeError(const char *message) { - PyErr_SetString(PyExc_TypeError, message); - return nullptr; -} - -/** - * Raises a TypeError of the form: function_name() argument n must be type, - * not type for a given object passed to a function. - * - * Always returns NULL so that it can be conveniently used as a return - * expression for wrapper functions that return a PyObject pointer. - */ -PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name) { -#if PY_MAJOR_VERSION >= 3 - PyObject *message = PyUnicode_FromFormat( -#else - PyObject *message = PyString_FromFormat( -#endif - "%s() argument %d must be %s, not %s", - function_name, param, type_name, - Py_TYPE(obj)->tp_name); - - PyErr_SetObject(PyExc_TypeError, message); - return nullptr; -} - -/** - * Raises an AttributeError of the form: 'type' has no attribute 'attr' - * - * Always returns NULL so that it can be conveniently used as a return - * expression for wrapper functions that return a PyObject pointer. - */ -PyObject *Dtool_Raise_AttributeError(PyObject *obj, const char *attribute) { -#if PY_MAJOR_VERSION >= 3 - PyObject *message = PyUnicode_FromFormat( -#else - PyObject *message = PyString_FromFormat( -#endif - "'%.100s' object has no attribute '%.200s'", - Py_TYPE(obj)->tp_name, attribute); - - PyErr_SetObject(PyExc_AttributeError, message); - return nullptr; -} - -/** - * Raises a TypeError of the form: Arguments must match: - * - * However, in release builds, this instead is defined to a function that just - * prints out a generic message, to help reduce the amount of strings in the - * compiled library. - * - * If there is already an exception set, does nothing. - * - * Always returns NULL so that it can be conveniently used as a return - * expression for wrapper functions that return a PyObject pointer. - */ -PyObject *_Dtool_Raise_BadArgumentsError(const char *message) { - if (!PyErr_Occurred()) { - return PyErr_Format(PyExc_TypeError, "Arguments must match:\n%s", message); - } - return nullptr; -} - -/** - * Overload that prints a generic message instead. - */ -PyObject *_Dtool_Raise_BadArgumentsError() { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "arguments do not match any function overload"); - } - return nullptr; -} - -/** - * Overload that returns -1 instead of nullptr. - */ -int _Dtool_Raise_BadArgumentsError_Int(const char *message) { - if (!PyErr_Occurred()) { - PyErr_Format(PyExc_TypeError, "Arguments must match:\n%s", message); - } - return -1; -} - -/** - * Overload that returns -1 instead of nullptr and prints a generic message. - */ -int _Dtool_Raise_BadArgumentsError_Int() { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, "arguments do not match any function overload"); - } - return -1; -} - -/** - * Convenience method that checks for exceptions, and if one occurred, returns - * NULL, otherwise Py_None. - */ -PyObject *_Dtool_Return_None() { - if (UNLIKELY(PyErr_Occurred())) { - return nullptr; - } -#ifndef NDEBUG - if (UNLIKELY(Notify::ptr()->has_assert_failed())) { - return Dtool_Raise_AssertionError(); - } -#endif - return Py_NewRef(Py_None); -} - -/** - * Convenience method that checks for exceptions, and if one occurred, returns - * NULL, otherwise the given boolean value as a PyObject *. - */ -PyObject *Dtool_Return_Bool(bool value) { - if (UNLIKELY(PyErr_Occurred())) { - return nullptr; - } -#ifndef NDEBUG - if (UNLIKELY(Notify::ptr()->has_assert_failed())) { - return Dtool_Raise_AssertionError(); - } -#endif - return Py_NewRef(value ? Py_True : Py_False); -} - -/** - * Convenience method that checks for exceptions, and if one occurred, returns - * NULL, otherwise the given return value. Its reference count is not - * increased. - */ -PyObject *_Dtool_Return(PyObject *value) { - if (UNLIKELY(PyErr_Occurred())) { - return nullptr; - } -#ifndef NDEBUG - if (UNLIKELY(Notify::ptr()->has_assert_failed())) { - return Dtool_Raise_AssertionError(); - } -#endif - return value; -} - -#if PY_VERSION_HEX < 0x03040000 -/** - * This function converts an int value to the appropriate enum instance. - */ -static PyObject *Dtool_EnumType_New(PyTypeObject *subtype, PyObject *args, PyObject *kwds) { - PyObject *arg; - if (!Dtool_ExtractArg(&arg, args, kwds, "value")) { - return PyErr_Format(PyExc_TypeError, - "%s() missing 1 required argument: 'value'", - subtype->tp_name); - } - - if (Py_TYPE(arg) == subtype) { - return Py_NewRef(arg); - } - - PyObject *value2member = PyDict_GetItemString(subtype->tp_dict, "_value2member_map_"); - nassertr_always(value2member != nullptr, nullptr); - - PyObject *member = PyDict_GetItem(value2member, arg); - if (member != nullptr) { - return Py_NewRef(member); - } - - PyObject *repr = PyObject_Repr(arg); - PyErr_Format(PyExc_ValueError, "%s is not a valid %s", -#if PY_MAJOR_VERSION >= 3 - PyUnicode_AS_STRING(repr), -#else - PyString_AS_STRING(repr), -#endif - subtype->tp_name); - Py_DECREF(repr); - return nullptr; -} - -static PyObject *Dtool_EnumType_Str(PyObject *self) { - PyObject *name = PyObject_GetAttrString(self, "name"); -#if PY_MAJOR_VERSION >= 3 - PyObject *repr = PyUnicode_FromFormat("%s.%s", Py_TYPE(self)->tp_name, PyString_AS_STRING(name)); -#else - PyObject *repr = PyString_FromFormat("%s.%s", Py_TYPE(self)->tp_name, PyString_AS_STRING(name)); -#endif - Py_DECREF(name); - return repr; -} - -static PyObject *Dtool_EnumType_Repr(PyObject *self) { - PyObject *name = PyObject_GetAttrString(self, "name"); - PyObject *value = PyObject_GetAttrString(self, "value"); -#if PY_MAJOR_VERSION >= 3 - PyObject *repr = PyUnicode_FromFormat("<%s.%s: %ld>", Py_TYPE(self)->tp_name, PyString_AS_STRING(name), PyLongOrInt_AS_LONG(value)); -#else - PyObject *repr = PyString_FromFormat("<%s.%s: %ld>", Py_TYPE(self)->tp_name, PyString_AS_STRING(name), PyLongOrInt_AS_LONG(value)); -#endif - Py_DECREF(name); - Py_DECREF(value); - return repr; -} -#endif - -/** - * Creates a Python 3.4-style enum type. Steals reference to 'names', which - * should be a tuple of (name, value) pairs. - */ -PyTypeObject *Dtool_EnumType_Create(const char *name, PyObject *names, const char *module) { - static PyObject *enum_class = nullptr; -#if PY_VERSION_HEX >= 0x03040000 - static PyObject *enum_meta = nullptr; - static PyObject *enum_create = nullptr; - if (enum_meta == nullptr) { - PyObject *enum_module = PyImport_ImportModule("enum"); - nassertr_always(enum_module != nullptr, nullptr); - - enum_class = PyObject_GetAttrString(enum_module, "Enum"); - enum_meta = PyObject_GetAttrString(enum_module, "EnumMeta"); - enum_create = PyObject_GetAttrString(enum_meta, "_create_"); - nassertr(enum_meta != nullptr, nullptr); - } - - PyObject *result = PyObject_CallFunction(enum_create, (char *)"OsN", enum_class, name, names); - nassertr(result != nullptr, nullptr); -#else - static PyObject *name_str; - static PyObject *name_sunder_str; - static PyObject *value_str; - static PyObject *value_sunder_str; - static PyObject *value2member_map_sunder_str; - // Emulate something vaguely like the enum module. - if (enum_class == nullptr) { -#if PY_MAJOR_VERSION >= 3 - name_str = PyUnicode_InternFromString("name"); - value_str = PyUnicode_InternFromString("value"); - name_sunder_str = PyUnicode_InternFromString("_name_"); - value_sunder_str = PyUnicode_InternFromString("_value_"); - value2member_map_sunder_str = PyUnicode_InternFromString("_value2member_map_"); -#else - name_str = PyString_InternFromString("name"); - value_str = PyString_InternFromString("value"); - name_sunder_str = PyString_InternFromString("_name_"); - value_sunder_str = PyString_InternFromString("_value_"); - value2member_map_sunder_str = PyString_InternFromString("_value2member_map_"); -#endif - PyObject *name_value_tuple = PyTuple_New(4); - PyTuple_SET_ITEM(name_value_tuple, 0, Py_NewRef(name_str)); - PyTuple_SET_ITEM(name_value_tuple, 1, Py_NewRef(value_str)); - PyTuple_SET_ITEM(name_value_tuple, 2, name_sunder_str); - PyTuple_SET_ITEM(name_value_tuple, 3, value_sunder_str); - - PyObject *slots_dict = PyDict_New(); - PyDict_SetItemString(slots_dict, "__slots__", name_value_tuple); - Py_DECREF(name_value_tuple); - - enum_class = PyObject_CallFunction((PyObject *)&PyType_Type, (char *)"s()N", "Enum", slots_dict); - nassertr(enum_class != nullptr, nullptr); - } - - // Create a subclass of this generic Enum class we just created. - PyObject *value2member = PyDict_New(); - PyObject *dict = PyDict_New(); - PyDict_SetItem(dict, value2member_map_sunder_str, value2member); - PyObject *result = PyObject_CallFunction((PyObject *)&PyType_Type, (char *)"s(O)N", name, enum_class, dict); - nassertr(result != nullptr, nullptr); - - ((PyTypeObject *)result)->tp_new = Dtool_EnumType_New; - ((PyTypeObject *)result)->tp_str = Dtool_EnumType_Str; - ((PyTypeObject *)result)->tp_repr = Dtool_EnumType_Repr; - - PyObject *empty_tuple = PyTuple_New(0); - - // Copy the names as instances of the above to the class dict, and create a - // reverse mapping in the _value2member_map_ dict. - Py_ssize_t size = PyTuple_GET_SIZE(names); - for (Py_ssize_t i = 0; i < size; ++i) { - PyObject *item = PyTuple_GET_ITEM(names, i); - PyObject *name = PyTuple_GET_ITEM(item, 0); - PyObject *value = PyTuple_GET_ITEM(item, 1); - PyObject *member = PyType_GenericNew((PyTypeObject *)result, empty_tuple, nullptr); - PyObject_SetAttr(member, name_str, name); - PyObject_SetAttr(member, name_sunder_str, name); - PyObject_SetAttr(member, value_str, value); - PyObject_SetAttr(member, value_sunder_str, value); - PyObject_SetAttr(result, name, member); - PyDict_SetItem(value2member, value, member); - Py_DECREF(member); - } - Py_DECREF(names); - Py_DECREF(value2member); - Py_DECREF(empty_tuple); -#endif - - if (module != nullptr) { - PyObject *modstr = PyUnicode_FromString(module); - PyObject_SetAttrString(result, "__module__", modstr); - Py_DECREF(modstr); - } - nassertr(PyType_Check(result), nullptr); - return (PyTypeObject *)result; -} - -/** - - */ -PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int type_index) { - // We can't do the NULL check here like in DTool_CreatePyInstance, since the - // caller will have to get the type index to pass to this function to begin - // with. That code probably would have crashed by now if it was really NULL - // for whatever reason. - nassertr(local_this_in != nullptr, nullptr); - - // IF the class is possibly a run time typed object - if (type_index > 0) { - // get best fit class... - Dtool_PyInstDef *self = (Dtool_PyInstDef *)TypeHandle::from_index(type_index).wrap_python(local_this_in, &known_class_type._PyType); - if (self != nullptr) { - self->_memory_rules = memory_rules; - self->_is_const = is_const; - return (PyObject *)self; - } - } - - // if we get this far .. just wrap the thing in the known type ?? better - // than aborting...I guess.... - Dtool_PyInstDef *self = (Dtool_PyInstDef *)PyType_GenericAlloc(&known_class_type._PyType, 0); - if (self != nullptr) { - self->_signature = PY_PANDA_SIGNATURE; - self->_My_Type = &known_class_type; - self->_ptr_to_object = local_this_in; - self->_memory_rules = memory_rules; - self->_is_const = is_const; - } - return (PyObject *)self; -} - -// DTool_CreatePyInstance .. wrapper function to finalize the existance of a -// general dtool py instance.. -PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const) { - if (local_this == nullptr) { - // This is actually a very common case, so let's allow this, but return - // Py_None consistently. This eliminates code in the wrappers. - return Py_NewRef(Py_None); - } - - Dtool_PyInstDef *self = (Dtool_PyInstDef *)PyType_GenericAlloc(&in_classdef._PyType, 0); - if (self != nullptr) { - self->_signature = PY_PANDA_SIGNATURE; - self->_My_Type = &in_classdef; - self->_ptr_to_object = local_this; - self->_memory_rules = memory_rules; - self->_is_const = is_const; - self->_My_Type = &in_classdef; - } - return (PyObject *)self; -} - -/** - * Returns a borrowed reference to the global type dictionary. - */ -Dtool_TypeMap *Dtool_GetGlobalTypeMap() { - PyObject *capsule = PySys_GetObject((char *)"_interrogate_types"); - if (capsule != nullptr) { - return (Dtool_TypeMap *)PyCapsule_GetPointer(capsule, nullptr); - } else { - Dtool_TypeMap *type_map = new Dtool_TypeMap; - capsule = PyCapsule_New((void *)type_map, nullptr, nullptr); - PySys_SetObject((char *)"_interrogate_types", capsule); - Py_DECREF(capsule); - return type_map; - } -} - -/** - * - */ -void DtoolProxy_Init(DtoolProxy *proxy, PyObject *self, - Dtool_PyTypedObject &classdef, - TypeRegistry::PythonWrapFunc *wrap_func) { - if (proxy == nullptr) { - // Out of memory, the generated code will handle this. - return; - } - - proxy->_self = Py_NewRef(self); - PyTypeObject *cls = Py_TYPE(self); - if (cls != &classdef._PyType) { - TypeRegistry *registry = TypeRegistry::ptr(); - TypeHandle handle = registry->register_dynamic_type(cls->tp_name); - registry->record_derivation(handle, classdef._type); - //TODO unregister type when it is unloaded? weak callback? - PyTypeObject *cls_ref = (PyTypeObject *)Py_NewRef((PyObject *)cls); - registry->record_python_type(handle, cls_ref, wrap_func); - proxy->_type = handle; - } else { - proxy->_type = classdef._type; - } -} - -#define PY_MAJOR_VERSION_STR #PY_MAJOR_VERSION "." #PY_MINOR_VERSION - -#if PY_MAJOR_VERSION >= 3 -PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], PyModuleDef *module_def) { -#else -PyObject *Dtool_PyModuleInitHelper(const LibraryDef *defs[], const char *modulename) { -#endif - // Check the version so we can print a helpful error if it doesn't match. - string version = Py_GetVersion(); - size_t version_len = version.find('.', 2); - if (version_len != string::npos) { - version.resize(version_len); - } - - if (version != STRINGIFY_VERSION(PY_MAJOR_VERSION, PY_MINOR_VERSION)) { - // Raise a helpful error message. We can safely do this because the - // signature and behavior for PyErr_SetString has remained consistent. - std::ostringstream errs; - errs << "this module was compiled for Python " - << PY_MAJOR_VERSION << "." << PY_MINOR_VERSION << ", which is " - << "incompatible with Python " << version; - string error = errs.str(); - PyErr_SetString(PyExc_ImportError, error.c_str()); - return nullptr; - } - - Dtool_TypeMap *type_map = Dtool_GetGlobalTypeMap(); - - // the module level function inits.... - MethodDefmap functions; - for (size_t i = 0; defs[i] != nullptr; i++) { - const LibraryDef &def = *defs[i]; - - // Accumulate method definitions. - for (PyMethodDef *meth = def._methods; meth->ml_name != nullptr; meth++) { - if (functions.find(meth->ml_name) == functions.end()) { - functions[meth->ml_name] = meth; - } - } - - // Define exported types. - const Dtool_TypeDef *types = def._types; - if (types != nullptr) { - while (types->name != nullptr) { - (*type_map)[std::string(types->name)] = types->type; - ++types; - } - } - } - - // Resolve external types, in a second pass. - for (size_t i = 0; defs[i] != nullptr; i++) { - const LibraryDef &def = *defs[i]; - - Dtool_TypeDef *types = def._external_types; - if (types != nullptr) { - while (types->name != nullptr) { - auto it = type_map->find(std::string(types->name)); - if (it != type_map->end()) { - types->type = it->second; - } else { - return PyErr_Format(PyExc_NameError, "name '%s' is not defined", types->name); - } - ++types; - } - } - } - - PyMethodDef *newdef = new PyMethodDef[functions.size() + 1]; - MethodDefmap::iterator mi; - int offset = 0; - for (mi = functions.begin(); mi != functions.end(); mi++, offset++) { - newdef[offset] = *mi->second; - } - newdef[offset].ml_doc = nullptr; - newdef[offset].ml_name = nullptr; - newdef[offset].ml_meth = nullptr; - newdef[offset].ml_flags = 0; - -#if PY_MAJOR_VERSION >= 3 - module_def->m_methods = newdef; - PyObject *module = PyModule_Create(module_def); -#else - PyObject *module = Py_InitModule((char *)modulename, newdef); -#endif - - if (module == nullptr) { -#if PY_MAJOR_VERSION >= 3 - return Dtool_Raise_TypeError("PyModule_Create returned NULL"); -#else - return Dtool_Raise_TypeError("Py_InitModule returned NULL"); -#endif - } - - // MAIN_DIR needs to be set very early; this seems like a convenient place - // to do that. Perhaps we'll find a better place for this in the future. - static bool initialized_main_dir = false; - if (!initialized_main_dir) { - if (interrogatedb_cat.is_debug()) { - // Good opportunity to print this out once, at startup. - interrogatedb_cat.debug() - << "Python " << version << "\n"; - } - - if (!ExecutionEnvironment::has_environment_variable("MAIN_DIR")) { - // Grab the __main__ module. - PyObject *main_module = PyImport_ImportModule("__main__"); - if (main_module == NULL) { - interrogatedb_cat.warning() << "Unable to import __main__\n"; - } - - // Extract the __file__ attribute, if present. - Filename main_dir; - PyObject *file_attr = nullptr; - if (main_module != nullptr) { - file_attr = PyObject_GetAttrString(main_module, "__file__"); - } - if (file_attr == nullptr) { - // Must be running in the interactive interpreter. Use the CWD. - main_dir = ExecutionEnvironment::get_cwd(); - } else { -#if PY_MAJOR_VERSION >= 3 - Py_ssize_t length; - wchar_t *buffer = PyUnicode_AsWideCharString(file_attr, &length); - if (buffer != nullptr) { - main_dir = Filename::from_os_specific_w(std::wstring(buffer, length)); - main_dir.make_absolute(); - main_dir = main_dir.get_dirname(); - PyMem_Free(buffer); - } -#else - char *buffer; - Py_ssize_t length; - if (PyString_AsStringAndSize(file_attr, &buffer, &length) != -1) { - main_dir = Filename::from_os_specific(std::string(buffer, length)); - main_dir.make_absolute(); - main_dir = main_dir.get_dirname(); - } -#endif - else { - interrogatedb_cat.warning() << "Invalid string for __main__.__file__\n"; - } - } - ExecutionEnvironment::shadow_environment_variable("MAIN_DIR", main_dir.to_os_specific()); - PyErr_Clear(); - } - initialized_main_dir = true; - - // Also, while we are at it, initialize the thread swap hook. -#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) - global_thread_state_swap = PyThreadState_Swap; -#endif - } - - PyModule_AddIntConstant(module, "Dtool_PyNativeInterface", 1); - return module; -} - -// HACK.... Be careful Dtool_BorrowThisReference This function can be used to -// grab the "THIS" pointer from an object and use it Required to support -// historical inheritance in the form of "is this instance of".. -PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args) { - PyObject *from_in = nullptr; - PyObject *to_in = nullptr; - if (PyArg_UnpackTuple(args, "Dtool_BorrowThisReference", 2, 2, &to_in, &from_in)) { - - if (DtoolInstance_Check(from_in) && DtoolInstance_Check(to_in)) { - Dtool_PyInstDef *from = (Dtool_PyInstDef *) from_in; - Dtool_PyInstDef *to = (Dtool_PyInstDef *) to_in; - - // if (PyObject_TypeCheck(to_in, Py_TYPE(from_in))) { - if (from->_My_Type == to->_My_Type) { - to->_memory_rules = false; - to->_is_const = from->_is_const; - to->_ptr_to_object = from->_ptr_to_object; - - return Py_NewRef(Py_None); - } - - return PyErr_Format(PyExc_TypeError, "types %s and %s do not match", - Py_TYPE(from)->tp_name, Py_TYPE(to)->tp_name); - } else { - return Dtool_Raise_TypeError("One of these does not appear to be DTOOL Instance ??"); - } - } - return nullptr; -} - -// We do expose a dictionay for dtool classes .. this should be removed at -// some point.. -EXPCL_PYPANDA PyObject * -Dtool_AddToDictionary(PyObject *self1, PyObject *args) { - PyObject *self; - PyObject *subject; - PyObject *key; - if (PyArg_ParseTuple(args, "OSO", &self, &key, &subject)) { - PyObject *dict = ((PyTypeObject *)self)->tp_dict; - if (dict == nullptr || !PyDict_Check(dict)) { - return Dtool_Raise_TypeError("No dictionary On Object"); - } else { - PyDict_SetItem(dict, key, subject); - } - } - if (PyErr_Occurred()) { - return nullptr; - } - return Py_NewRef(Py_None); -} - -/** - * This is a support function for a synthesized __copy__() method from a C++ - * make_copy() method. - */ -PyObject *copy_from_make_copy(PyObject *self, PyObject *noargs) { - PyObject *callable = PyObject_GetAttrString(self, "make_copy"); - if (callable == nullptr) { - return nullptr; - } - PyObject *result = PyObject_CallNoArgs(callable); - Py_DECREF(callable); - return result; -} - -/** - * This is a support function for a synthesized __copy__() method from a C++ - * copy constructor. - */ -PyObject *copy_from_copy_constructor(PyObject *self, PyObject *noargs) { - PyObject *callable = (PyObject *)Py_TYPE(self); - return PyObject_CallOneArg(callable, self); -} - -/** - * This is a support function for a synthesized __deepcopy__() method for any - * class that has a __copy__() method. The sythethic method simply invokes - * __copy__(). - */ -PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) { - PyObject *callable = PyObject_GetAttrString(self, "__copy__"); - if (callable == nullptr) { - return nullptr; - } - PyObject *result = PyObject_CallNoArgs(callable); - Py_DECREF(callable); - return result; -} - -/** - * A more efficient version of PyArg_ParseTupleAndKeywords for the special - * case where there is only a single PyObject argument. - */ -bool Dtool_ExtractArg(PyObject **result, PyObject *args, PyObject *kwds, - const char *keyword) { - - if (PyTuple_GET_SIZE(args) == 1) { - if (kwds == nullptr || PyDict_GET_SIZE(kwds) == 0) { - *result = PyTuple_GET_ITEM(args, 0); - return true; - } - } - else if (!keyword || !keyword[0]) { - return false; - } - else if (PyTuple_GET_SIZE(args) == 0) { - PyObject *key; - Py_ssize_t ppos = 0; - if (kwds != nullptr && PyDict_GET_SIZE(kwds) == 1 && - PyDict_Next(kwds, &ppos, &key, result)) { - // We got the item, we just need to make sure that it had the right key. -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_CheckExact(key) && PyUnicode_CompareWithASCIIString(key, keyword) == 0; -#else - return PyString_CheckExact(key) && strcmp(PyString_AS_STRING(key), keyword) == 0; -#endif - } - } - - return false; -} - -/** - * Variant of Dtool_ExtractArg that does not accept a keyword argument. - */ -bool Dtool_ExtractArg(PyObject **result, PyObject *args, PyObject *kwds) { - if (PyTuple_GET_SIZE(args) == 1 && - (kwds == nullptr || PyDict_GET_SIZE(kwds) == 0)) { - *result = PyTuple_GET_ITEM(args, 0); - return true; - } - return false; -} - -/** - * A more efficient version of PyArg_ParseTupleAndKeywords for the special - * case where there is only a single optional PyObject argument. - * - * Returns true if valid (including if there were 0 items), false if there was - * an error, such as an invalid number of parameters. - */ -bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds, - const char *keyword) { - - if (PyTuple_GET_SIZE(args) == 1) { - if (kwds == nullptr || PyDict_GET_SIZE(kwds) == 0) { - *result = PyTuple_GET_ITEM(args, 0); - return true; - } - } - else if (!keyword || !keyword[0]) { - return (kwds == nullptr || PyDict_GET_SIZE(kwds) == 0); - } - else if (PyTuple_GET_SIZE(args) == 0) { - if (kwds != nullptr && PyDict_GET_SIZE(kwds) == 1) { - PyObject *key; - Py_ssize_t ppos = 0; - if (!PyDict_Next(kwds, &ppos, &key, result)) { - return true; - } - - // We got the item, we just need to make sure that it had the right key. -#if PY_VERSION_HEX >= 0x03060000 - return PyUnicode_CheckExact(key) && _PyUnicode_EqualToASCIIString(key, keyword); -#elif PY_MAJOR_VERSION >= 3 - return PyUnicode_CheckExact(key) && PyUnicode_CompareWithASCIIString(key, keyword) == 0; -#else - return PyString_CheckExact(key) && strcmp(PyString_AS_STRING(key), keyword) == 0; -#endif - } else { - return true; - } - } - - return false; -} - -/** - * Variant of Dtool_ExtractOptionalArg that does not accept a keyword argument. - */ -bool Dtool_ExtractOptionalArg(PyObject **result, PyObject *args, PyObject *kwds) { - if (kwds != nullptr && PyDict_GET_SIZE(kwds) != 0) { - return false; - } - if (PyTuple_GET_SIZE(args) == 1) { - *result = PyTuple_GET_ITEM(args, 0); - return true; - } - return (PyTuple_GET_SIZE(args) == 0); -} - -#endif // HAVE_PYTHON diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index 9d8fc113ff7..d57af784f79 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -16,6 +16,7 @@ #include "pnotify.h" #include "vector_uchar.h" #include "register_type.h" +#include "interrogate_request.h" #if defined(HAVE_PYTHON) && !defined(CPPPARSER) @@ -162,6 +163,9 @@ static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\ Py_TYPE(self)->tp_free(self);\ } +// Extract the PyTypeObject pointer corresponding to a Dtool_PyTypedObject. +#define Dtool_GetPyTypeObject(type) (&(type)->_PyType) + // Use DtoolInstance_Check to check whether a PyObject* is a DtoolInstance. #define DtoolInstance_Check(obj) \ (Py_TYPE(obj)->tp_basicsize >= (int)sizeof(Dtool_PyInstDef) && \ @@ -178,7 +182,14 @@ static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\ // forward declared of typed object. We rely on the fact that typed objects // are uniquly defined by an integer. +#if PY_VERSION_HEX >= 0x030d0000 +class Dtool_TypeMap : public std::map { +public: + PyMutex _lock { 0 }; +}; +#else typedef std::map Dtool_TypeMap; +#endif EXPCL_PYPANDA Dtool_TypeMap *Dtool_GetGlobalTypeMap(); @@ -335,6 +346,7 @@ struct LibraryDef { PyMethodDef *const _methods; const Dtool_TypeDef *const _types; Dtool_TypeDef *const _external_types; + const InterrogateModuleDef *const _module_def; }; #if PY_MAJOR_VERSION >= 3 diff --git a/dtool/src/interrogatedb/py_wrappers.cxx b/dtool/src/interrogatedb/py_wrappers.cxx deleted file mode 100644 index f0be01a3fbc..00000000000 --- a/dtool/src/interrogatedb/py_wrappers.cxx +++ /dev/null @@ -1,1778 +0,0 @@ -/** - * @file py_wrappers.cxx - * @author rdb - * @date 2017-11-26 - */ - -#include "py_wrappers.h" - -#ifdef HAVE_PYTHON - -#if PY_VERSION_HEX >= 0x03040000 -#define _COLLECTIONS_ABC "_collections_abc" -#elif PY_VERSION_HEX >= 0x03030000 -#define _COLLECTIONS_ABC "collections.abc" -#else -#define _COLLECTIONS_ABC "_abcoll" -#endif - -static void _register_collection(PyTypeObject *type, const char *abc) { - PyObject *sys_modules = PyImport_GetModuleDict(); - if (sys_modules != nullptr) { - PyObject *module = PyDict_GetItemString(sys_modules, _COLLECTIONS_ABC); - if (module != nullptr) { - PyObject *dict = PyModule_GetDict(module); - if (module != nullptr) { -#if PY_MAJOR_VERSION >= 3 - static PyObject *register_str = PyUnicode_InternFromString("register"); -#else - static PyObject *register_str = PyString_InternFromString("register"); -#endif - PyObject *sequence = PyDict_GetItemString(dict, abc); - if (sequence != nullptr) { - if (PyObject_CallMethodOneArg(sequence, register_str, (PyObject *)type) == nullptr) { - PyErr_Print(); - } - } - } - } - } -} - -/** - * These classes are returned from properties that require a subscript - * interface, ie. something.children[i] = 3. - */ -static void Dtool_WrapperBase_dealloc(PyObject *self) { - Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self; - nassertv(wrap); - Py_XDECREF(wrap->_self); - Py_TYPE(self)->tp_free(self); -} - -static PyObject *Dtool_WrapperBase_repr(PyObject *self) { - Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self; - nassertr(wrap, nullptr); - - PyObject *repr = PyObject_Repr(wrap->_self); - PyObject *result; -#if PY_MAJOR_VERSION >= 3 - result = PyUnicode_FromFormat("<%s[] of %s>", wrap->_name, PyUnicode_AsUTF8(repr)); -#else - result = PyString_FromFormat("<%s[] of %s>", wrap->_name, PyString_AS_STRING(repr)); -#endif - Py_DECREF(repr); - return result; -} - -static PyObject *Dtool_SequenceWrapper_repr(PyObject *self) { - Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self; - nassertr(wrap, nullptr); - - Py_ssize_t len = -1; - if (wrap->_len_func != nullptr) { - len = wrap->_len_func(wrap->_base._self); - } - - if (len < 0) { - PyErr_Clear(); - return Dtool_WrapperBase_repr(self); - } - - PyObject *repr = PyObject_Repr(wrap->_base._self); - PyObject *result; -#if PY_MAJOR_VERSION >= 3 - result = PyUnicode_FromFormat("<%s[%zd] of %s>", wrap->_base._name, len, PyUnicode_AsUTF8(repr)); -#else - result = PyString_FromFormat("<%s[%zd] of %s>", wrap->_base._name, len, PyString_AS_STRING(repr)); -#endif - Py_DECREF(repr); - return result; -} - -static Py_ssize_t Dtool_SequenceWrapper_length(PyObject *self) { - Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self; - nassertr(wrap, -1); - if (wrap->_len_func != nullptr) { - return wrap->_len_func(wrap->_base._self); - } else { - Dtool_Raise_TypeError("property does not support len()"); - return -1; - } -} - -static PyObject *Dtool_SequenceWrapper_getitem(PyObject *self, Py_ssize_t index) { - Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_getitem_func, nullptr); - return wrap->_getitem_func(wrap->_base._self, index); -} - -/** - * Implementation of (x in property) - */ -static int Dtool_SequenceWrapper_contains(PyObject *self, PyObject *value) { - Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self; - nassertr(wrap, -1); - nassertr(wrap->_len_func, -1); - nassertr(wrap->_getitem_func, -1); - - Py_ssize_t length = wrap->_len_func(wrap->_base._self); - - // Iterate through the items, invoking the equality function for each, until - // we have found the matching one. - for (Py_ssize_t index = 0; index < length; ++index) { - PyObject *item = wrap->_getitem_func(wrap->_base._self, index); - if (item != nullptr) { - int cmp = PyObject_RichCompareBool(item, value, Py_EQ); - if (cmp > 0) { - return 1; - } - if (cmp < 0) { - return -1; - } - } else { - return -1; - } - } - return 0; -} - -/** - * Implementation of property.index(x) which returns the index of the first - * occurrence of x in the sequence, or raises a ValueError if it isn't found. - */ -static PyObject *Dtool_SequenceWrapper_index(PyObject *self, PyObject *value) { - Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_len_func, nullptr); - nassertr(wrap->_getitem_func, nullptr); - - Py_ssize_t length = wrap->_len_func(wrap->_base._self); - - // Iterate through the items, invoking the equality function for each, until - // we have found the right one. - for (Py_ssize_t index = 0; index < length; ++index) { - PyObject *item = wrap->_getitem_func(wrap->_base._self, index); - if (item != nullptr) { - int cmp = PyObject_RichCompareBool(item, value, Py_EQ); - if (cmp > 0) { - return Dtool_WrapValue(index); - } - if (cmp < 0) { - return nullptr; - } - } else { - return nullptr; - } - } - // Not found, raise ValueError. - return PyErr_Format(PyExc_ValueError, "%s.index() did not find value", wrap->_base._name); -} - -/** - * Implementation of property.count(x) which returns the number of occurrences - * of x in the sequence. - */ -static PyObject *Dtool_SequenceWrapper_count(PyObject *self, PyObject *value) { - Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)self; - nassertr(wrap, nullptr); - Py_ssize_t index = 0; - if (wrap->_len_func != nullptr) { - index = wrap->_len_func(wrap->_base._self); - } else { - return Dtool_Raise_TypeError("property does not support count()"); - } - // Iterate through the items, invoking the == operator for each. - long count = 0; - nassertr(wrap->_getitem_func, nullptr); - while (index > 0) { - --index; - PyObject *item = wrap->_getitem_func(wrap->_base._self, index); - if (item == nullptr) { - return nullptr; - } - int cmp = PyObject_RichCompareBool(item, value, Py_EQ); - if (cmp > 0) { - ++count; - } - if (cmp < 0) { - return nullptr; - } - } -#if PY_MAJOR_VERSION >= 3 - return PyLong_FromLong(count); -#else - return PyInt_FromLong(count); -#endif -} - -/** - * Implementation of `property[i] = x` - */ -static int Dtool_MutableSequenceWrapper_setitem(PyObject *self, Py_ssize_t index, PyObject *value) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self; - nassertr(wrap, -1); - if (wrap->_setitem_func != nullptr) { - return wrap->_setitem_func(wrap->_base._self, index, value); - } else { - Dtool_Raise_TypeError("property does not support item assignment"); - return -1; - } -} - -/** - * Implementation of property.clear() which removes all elements in the - * sequence, starting with the last. - */ -static PyObject *Dtool_MutableSequenceWrapper_clear(PyObject *self, PyObject *) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self; - nassertr(wrap, nullptr); - Py_ssize_t index = 0; - if (wrap->_len_func != nullptr && wrap->_setitem_func != nullptr) { - index = wrap->_len_func(wrap->_base._self); - } else { - return Dtool_Raise_TypeError("property does not support clear()"); - } - - // Iterate through the items, invoking the delete function for each. We do - // this in reverse order, which may be more efficient. - while (index > 0) { - --index; - if (wrap->_setitem_func(wrap->_base._self, index, nullptr) != 0) { - return nullptr; - } - } - return Py_NewRef(Py_None); -} - -/** - * Implementation of property.remove(x) which removes the first occurrence of - * x in the sequence, or raises a ValueError if it isn't found. - */ -static PyObject *Dtool_MutableSequenceWrapper_remove(PyObject *self, PyObject *value) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self; - nassertr(wrap, nullptr); - Py_ssize_t length = 0; - if (wrap->_len_func != nullptr && wrap->_setitem_func != nullptr) { - length = wrap->_len_func(wrap->_base._self); - } else { - return Dtool_Raise_TypeError("property does not support remove()"); - } - - // Iterate through the items, invoking the equality function for each, until - // we have found the right one. - nassertr(wrap->_getitem_func, nullptr); - for (Py_ssize_t index = 0; index < length; ++index) { - PyObject *item = wrap->_getitem_func(wrap->_base._self, index); - if (item != nullptr) { - int cmp = PyObject_RichCompareBool(item, value, Py_EQ); - if (cmp > 0) { - if (wrap->_setitem_func(wrap->_base._self, index, nullptr) == 0) { - return Py_NewRef(Py_None); - } else { - return nullptr; - } - } - if (cmp < 0) { - return nullptr; - } - } else { - return nullptr; - } - } - // Not found, raise ValueError. - return PyErr_Format(PyExc_ValueError, "%s.remove() did not find value", wrap->_base._name); -} - -/** - * Implementation of property.pop([i=-1]) which returns and removes the - * element at the indicated index in the sequence. If no index is provided, - * it removes from the end of the list. - */ -static PyObject *Dtool_MutableSequenceWrapper_pop(PyObject *self, PyObject *args) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self; - nassertr(wrap, nullptr); - if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr || - wrap->_len_func == nullptr) { - return Dtool_Raise_TypeError("property does not support pop()"); - } - - Py_ssize_t length = wrap->_len_func(wrap->_base._self); - Py_ssize_t index; - switch (PyTuple_GET_SIZE(args)) { - case 0: - index = length - 1; - break; - case 1: - index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 0), PyExc_IndexError); - if (index == -1 && PyErr_Occurred()) { - return nullptr; - } - if (index < 0) { - index += length; - } - break; - default: - return Dtool_Raise_TypeError("pop([i=-1]) takes 0 or 1 arguments"); - } - - if (length <= 0) { - return PyErr_Format(PyExc_IndexError, "%s.pop() from empty sequence", wrap->_base._name); - } - - // Index error will be caught by getitem_func. - PyObject *value = wrap->_getitem_func(wrap->_base._self, index); - if (value != nullptr) { - if (wrap->_setitem_func(wrap->_base._self, index, nullptr) != 0) { - return nullptr; - } - return value; - } - return nullptr; -} - -/** - * Implementation of property.append(x) which is an alias for - * property.insert(len(property), x). - */ -static PyObject *Dtool_MutableSequenceWrapper_append(PyObject *self, PyObject *arg) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self; - nassertr(wrap, nullptr); - if (wrap->_insert_func == nullptr) { - return Dtool_Raise_TypeError("property does not support append()"); - } - return wrap->_insert_func(wrap->_base._self, (size_t)-1, arg); -} - -/** - * Implementation of property.insert(i, x) which inserts the given item at the - * given position. - */ -static PyObject *Dtool_MutableSequenceWrapper_insert(PyObject *self, PyObject *args) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self; - nassertr(wrap, nullptr); - if (wrap->_insert_func == nullptr) { - return Dtool_Raise_TypeError("property does not support insert()"); - } - if (PyTuple_GET_SIZE(args) != 2) { - return Dtool_Raise_TypeError("insert() takes exactly 2 arguments"); - } - Py_ssize_t index = PyNumber_AsSsize_t(PyTuple_GET_ITEM(args, 0), PyExc_IndexError); - if (index == -1 && PyErr_Occurred()) { - return nullptr; - } - if (index < 0) { - if (wrap->_len_func != nullptr) { - index += wrap->_len_func(wrap->_base._self); - } else { - return PyErr_Format(PyExc_TypeError, "%s.insert() does not support negative indices", wrap->_base._name); - } - } - return wrap->_insert_func(wrap->_base._self, (size_t)std::max(index, (Py_ssize_t)0), PyTuple_GET_ITEM(args, 1)); -} - -/** - * Implementation of property.extend(seq) which is equivalent to: - * @code - * for x in seq: - * property.append(seq) - * @endcode - */ -static PyObject *Dtool_MutableSequenceWrapper_extend(PyObject *self, PyObject *arg) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)self; - nassertr(wrap, nullptr); - if (wrap->_insert_func == nullptr) { - return Dtool_Raise_TypeError("property does not support extend()"); - } - PyObject *iter = PyObject_GetIter(arg); - if (iter == nullptr) { - return nullptr; - } - PyObject *next = PyIter_Next(iter); - PyObject *retval = nullptr; - while (next != nullptr) { - retval = wrap->_insert_func(wrap->_base._self, (size_t)-1, next); - Py_DECREF(next); - if (retval == nullptr) { - Py_DECREF(iter); - return nullptr; - } - Py_DECREF(retval); - next = PyIter_Next(iter); - } - - Py_DECREF(iter); - return Py_NewRef(Py_None); -} - -/** - * Implementation of `x in mapping`. - */ -static int Dtool_MappingWrapper_contains(PyObject *self, PyObject *key) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, -1); - nassertr(wrap->_getitem_func, -1); - PyObject *value = wrap->_getitem_func(wrap->_base._self, key); - if (value != nullptr) { - Py_DECREF(value); - return 1; - } else if (PyErr_ExceptionMatches(PyExc_KeyError) || - PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Clear(); - return 0; - } else { - return -1; - } -} - -static PyObject *Dtool_MappingWrapper_getitem(PyObject *self, PyObject *key) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_getitem_func, nullptr); - return wrap->_getitem_func(wrap->_base._self, key); -} - -/** - * Implementation of iter(property) that returns an iterable over all the - * keys. - */ -static PyObject *Dtool_MappingWrapper_iter(PyObject *self) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - - if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) { - return PyErr_Format(PyExc_TypeError, "%s is not iterable", wrap->_base._name); - } - - Dtool_SequenceWrapper *keys = Dtool_NewSequenceWrapper(wrap->_base._self, wrap->_base._name); - if (keys != nullptr) { - keys->_len_func = wrap->_keys._len_func; - keys->_getitem_func = wrap->_keys._getitem_func; - return PySeqIter_New((PyObject *)keys); - } else { - return nullptr; - } -} - -/** - * Implementation of property.get(key[,def=None]) which returns the value with - * the given key in the mapping, or the given default value (which defaults to - * None) if the key isn't found in the mapping. - */ -static PyObject *Dtool_MappingWrapper_get(PyObject *self, PyObject *args) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_getitem_func, nullptr); - Py_ssize_t size = PyTuple_GET_SIZE(args); - if (size != 1 && size != 2) { - return PyErr_Format(PyExc_TypeError, "%s.get() takes 1 or 2 arguments", wrap->_base._name); - } - PyObject *defvalue = Py_None; - if (size >= 2) { - defvalue = PyTuple_GET_ITEM(args, 1); - } - PyObject *key = PyTuple_GET_ITEM(args, 0); - PyObject *value = wrap->_getitem_func(wrap->_base._self, key); - if (value != nullptr) { - return value; - } else if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - return Py_NewRef(defvalue); - } else { - return nullptr; - } -} - -/** - * This is returned by mapping.keys(). - */ -static PyObject *Dtool_MappingWrapper_Keys_repr(PyObject *self) { - Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self; - nassertr(wrap, nullptr); - - PyObject *repr = PyObject_Repr(wrap->_self); - PyObject *result; -#if PY_MAJOR_VERSION >= 3 - result = PyUnicode_FromFormat("<%s.keys() of %s>", wrap->_name, PyUnicode_AsUTF8(repr)); -#else - result = PyString_FromFormat("<%s.keys() of %s>", wrap->_name, PyString_AS_STRING(repr)); -#endif - Py_DECREF(repr); - return result; -} - -/** - * Implementation of property.keys(...) that returns a view of all the keys. - */ -static PyObject *Dtool_MappingWrapper_keys(PyObject *self, PyObject *) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - - if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) { - return Dtool_Raise_TypeError("property does not support keys()"); - } - - Dtool_MappingWrapper *keys = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper)); - if (keys == nullptr) { - return PyErr_NoMemory(); - } - - static PySequenceMethods seq_methods = { - Dtool_SequenceWrapper_length, - nullptr, // sq_concat - nullptr, // sq_repeat - Dtool_SequenceWrapper_getitem, - nullptr, // sq_slice - nullptr, // sq_ass_item - nullptr, // sq_ass_slice - Dtool_SequenceWrapper_contains, - nullptr, // sq_inplace_concat - nullptr, // sq_inplace_repeat - }; - - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "sequence wrapper", - sizeof(Dtool_SequenceWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - Dtool_MappingWrapper_Keys_repr, - nullptr, // tp_as_number - &seq_methods, - nullptr, // tp_as_mapping - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - PySeqIter_New, - nullptr, // tp_iternext - nullptr, // tp_methods - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - static bool registered = false; - if (!registered) { - registered = true; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - // If the collections.abc module is loaded, register this as a subclass. - _register_collection((PyTypeObject *)&wrapper_type, "MappingView"); - } - - (void)PyObject_INIT(keys, &wrapper_type); - keys->_base._self = Py_XNewRef(wrap->_base._self); - keys->_base._name = wrap->_base._name; - keys->_keys._len_func = wrap->_keys._len_func; - keys->_keys._getitem_func = wrap->_keys._getitem_func; - keys->_getitem_func = wrap->_getitem_func; - keys->_setitem_func = nullptr; - return (PyObject *)keys; -} - -/** - * This is returned by mapping.values(). - */ -static PyObject *Dtool_MappingWrapper_Values_repr(PyObject *self) { - Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self; - nassertr(wrap, nullptr); - - PyObject *repr = PyObject_Repr(wrap->_self); - PyObject *result; -#if PY_MAJOR_VERSION >= 3 - result = PyUnicode_FromFormat("<%s.values() of %s>", wrap->_name, PyUnicode_AsUTF8(repr)); -#else - result = PyString_FromFormat("<%s.values() of %s>", wrap->_name, PyString_AS_STRING(repr)); -#endif - Py_DECREF(repr); - return result; -} - -static PyObject *Dtool_MappingWrapper_Values_getitem(PyObject *self, Py_ssize_t index) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_keys._getitem_func, nullptr); - - PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, index); - if (key != nullptr) { - PyObject *value = wrap->_getitem_func(wrap->_base._self, key); - Py_DECREF(key); - return value; - } - return nullptr; -} - -/** - * Implementation of property.values(...) that returns a view of the values. - */ -static PyObject *Dtool_MappingWrapper_values(PyObject *self, PyObject *) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_getitem_func, nullptr); - - if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) { - return Dtool_Raise_TypeError("property does not support values()"); - } - - Dtool_MappingWrapper *values = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper)); - if (values == nullptr) { - return PyErr_NoMemory(); - } - - static PySequenceMethods seq_methods = { - Dtool_SequenceWrapper_length, - nullptr, // sq_concat - nullptr, // sq_repeat - Dtool_MappingWrapper_Values_getitem, - nullptr, // sq_slice - nullptr, // sq_ass_item - nullptr, // sq_ass_slice - Dtool_MappingWrapper_contains, - nullptr, // sq_inplace_concat - nullptr, // sq_inplace_repeat - }; - - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "sequence wrapper", - sizeof(Dtool_MappingWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - Dtool_MappingWrapper_Values_repr, - nullptr, // tp_as_number - &seq_methods, - nullptr, // tp_as_mapping - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - PySeqIter_New, - nullptr, // tp_iternext - nullptr, // tp_methods - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - static bool registered = false; - if (!registered) { - registered = true; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - // If the collections.abc module is loaded, register this as a subclass. - _register_collection((PyTypeObject *)&wrapper_type, "ValuesView"); - } - - (void)PyObject_INIT(values, &wrapper_type); - values->_base._self = Py_XNewRef(wrap->_base._self); - values->_base._name = wrap->_base._name; - values->_keys._len_func = wrap->_keys._len_func; - values->_keys._getitem_func = wrap->_keys._getitem_func; - values->_getitem_func = wrap->_getitem_func; - values->_setitem_func = nullptr; - return (PyObject *)values; -} - -/** - * This is returned by mapping.items(). - */ -static PyObject *Dtool_MappingWrapper_Items_repr(PyObject *self) { - Dtool_WrapperBase *wrap = (Dtool_WrapperBase *)self; - nassertr(wrap, nullptr); - - PyObject *repr = PyObject_Repr(wrap->_self); - PyObject *result; -#if PY_MAJOR_VERSION >= 3 - result = PyUnicode_FromFormat("<%s.items() of %s>", wrap->_name, PyUnicode_AsUTF8(repr)); -#else - result = PyString_FromFormat("<%s.items() of %s>", wrap->_name, PyString_AS_STRING(repr)); -#endif - Py_DECREF(repr); - return result; -} - -static PyObject *Dtool_MappingWrapper_Items_getitem(PyObject *self, Py_ssize_t index) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_keys._getitem_func, nullptr); - - PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, index); - if (key != nullptr) { - PyObject *value = wrap->_getitem_func(wrap->_base._self, key); - if (value != nullptr) { - // PyTuple_SET_ITEM steals the reference. - PyObject *item = PyTuple_New(2); - PyTuple_SET_ITEM(item, 0, key); - PyTuple_SET_ITEM(item, 1, value); - return item; - } else { - Py_DECREF(key); - } - } - return nullptr; -} - -/** - * Implementation of property.items(...) that returns an iterable yielding a - * `(key, value)` tuple for every item. - */ -static PyObject *Dtool_MappingWrapper_items(PyObject *self, PyObject *) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_getitem_func, nullptr); - - if (wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) { - return Dtool_Raise_TypeError("property does not support items()"); - } - - Dtool_MappingWrapper *items = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper)); - if (items == nullptr) { - return PyErr_NoMemory(); - } - - static PySequenceMethods seq_methods = { - Dtool_SequenceWrapper_length, - nullptr, // sq_concat - nullptr, // sq_repeat - Dtool_MappingWrapper_Items_getitem, - nullptr, // sq_slice - nullptr, // sq_ass_item - nullptr, // sq_ass_slice - Dtool_MappingWrapper_contains, - nullptr, // sq_inplace_concat - nullptr, // sq_inplace_repeat - }; - - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "sequence wrapper", - sizeof(Dtool_MappingWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - Dtool_MappingWrapper_Items_repr, - nullptr, // tp_as_number - &seq_methods, - nullptr, // tp_as_mapping - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - PySeqIter_New, - nullptr, // tp_iternext - nullptr, // tp_methods - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - static bool registered = false; - if (!registered) { - registered = true; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - // If the collections.abc module is loaded, register this as a subclass. - _register_collection((PyTypeObject *)&wrapper_type, "MappingView"); - } - - (void)PyObject_INIT(items, &wrapper_type); - items->_base._self = Py_XNewRef(wrap->_base._self); - items->_base._name = wrap->_base._name; - items->_keys._len_func = wrap->_keys._len_func; - items->_keys._getitem_func = wrap->_keys._getitem_func; - items->_getitem_func = wrap->_getitem_func; - items->_setitem_func = nullptr; - return (PyObject *)items; -} - -/** - * Implementation of `property[key] = value` - */ -static int Dtool_MutableMappingWrapper_setitem(PyObject *self, PyObject *key, PyObject *value) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap->_setitem_func != nullptr, -1); - return wrap->_setitem_func(wrap->_base._self, key, value); -} - -/** - * Implementation of property.pop(key[,def=None]) which is the same as get() - * except that it also removes the element from the mapping. - */ -static PyObject *Dtool_MutableMappingWrapper_pop(PyObject *self, PyObject *args) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) { - return Dtool_Raise_TypeError("property does not support pop()"); - } - - Py_ssize_t size = PyTuple_GET_SIZE(args); - if (size != 1 && size != 2) { - return PyErr_Format(PyExc_TypeError, "%s.pop() takes 1 or 2 arguments", wrap->_base._name); - } - PyObject *defvalue = Py_None; - if (size >= 2) { - defvalue = PyTuple_GET_ITEM(args, 1); - } - - PyObject *key = PyTuple_GET_ITEM(args, 0); - PyObject *value = wrap->_getitem_func(wrap->_base._self, key); - if (value != nullptr) { - // OK, now set unset this value. - if (wrap->_setitem_func(wrap->_base._self, key, nullptr) == 0) { - return value; - } else { - Py_DECREF(value); - return nullptr; - } - } else if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - return Py_NewRef(defvalue); - } else { - return nullptr; - } -} - -/** - * Implementation of property.popitem() which returns and removes an arbitrary - * (key, value) pair from the mapping. Useful for destructive iteration. - */ -static PyObject *Dtool_MutableMappingWrapper_popitem(PyObject *self, PyObject *) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr || - wrap->_keys._len_func == nullptr || wrap->_keys._getitem_func == nullptr) { - return Dtool_Raise_TypeError("property does not support popitem()"); - } - - Py_ssize_t length = wrap->_keys._len_func(wrap->_base._self); - if (length < 1) { - return PyErr_Format(PyExc_KeyError, "%s is empty", wrap->_base._name); - } - - PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, length - 1); - if (key != nullptr) { - PyObject *value = wrap->_getitem_func(wrap->_base._self, key); - if (value != nullptr) { - // OK, now set unset this value. - if (wrap->_setitem_func(wrap->_base._self, key, nullptr) == 0) { - PyObject *item = PyTuple_New(2); - PyTuple_SET_ITEM(item, 0, key); - PyTuple_SET_ITEM(item, 1, value); - return item; - } - Py_DECREF(value); - } - } - return nullptr; -} - -/* - * Implementation of property.clear() which removes all elements in the - * mapping. - */ -static PyObject *Dtool_MutableMappingWrapper_clear(PyObject *self, PyObject *) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - Py_ssize_t index = 0; - if (wrap->_keys._len_func != nullptr && wrap->_keys._getitem_func != nullptr && - wrap->_setitem_func != nullptr) { - index = wrap->_keys._len_func(wrap->_base._self); - } else { - return Dtool_Raise_TypeError("property does not support clear()"); - } - - // Iterate through the items, invoking the delete function for each. We do - // this in reverse order, which may be more efficient. - while (index > 0) { - --index; - PyObject *key = wrap->_keys._getitem_func(wrap->_base._self, index); - if (key != nullptr) { - int result = wrap->_setitem_func(wrap->_base._self, key, nullptr); - Py_DECREF(key); - if (result != 0) { - return nullptr; - } - } - } - return Py_NewRef(Py_None); -} - -/** - * Implementation of property.setdefault(key[,def=None]) which is the same as - * get() except that it also writes the default value back to the mapping if - * the key was not found is missing. - */ -static PyObject *Dtool_MutableMappingWrapper_setdefault(PyObject *self, PyObject *args) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - - if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) { - return Dtool_Raise_TypeError("property does not support setdefault()"); - } - - Py_ssize_t size = PyTuple_GET_SIZE(args); - if (size != 1 && size != 2) { - return PyErr_Format(PyExc_TypeError, "%s.setdefault() takes 1 or 2 arguments", wrap->_base._name); - } - PyObject *defvalue = Py_None; - if (size >= 2) { - defvalue = PyTuple_GET_ITEM(args, 1); - } - PyObject *key = PyTuple_GET_ITEM(args, 0); - PyObject *value = wrap->_getitem_func(wrap->_base._self, key); - if (value != nullptr) { - return value; - } else if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - if (wrap->_setitem_func(wrap->_base._self, key, defvalue) == 0) { - return Py_NewRef(defvalue); - } - } - return nullptr; -} - -/** - * Implementation of property.update(...) which sets multiple values in one - * go. It accepts either a single dictionary or keyword arguments, not both. - */ -static PyObject *Dtool_MutableMappingWrapper_update(PyObject *self, PyObject *args, PyObject *kwargs) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)self; - nassertr(wrap, nullptr); - - if (wrap->_getitem_func == nullptr || wrap->_setitem_func == nullptr) { - return Dtool_Raise_TypeError("property does not support update()"); - } - - // We accept either a dict argument or keyword arguments, but not both. - PyObject *dict; - switch (PyTuple_GET_SIZE(args)) { - case 0: - if (kwargs == nullptr) { - // This is legal. - return Py_NewRef(Py_None); - } - dict = kwargs; - break; - case 1: - if (PyDict_Check(PyTuple_GET_ITEM(args, 0)) && (kwargs == nullptr || Py_SIZE(kwargs) == 0)) { - dict = PyTuple_GET_ITEM(args, 0); - break; - } - // Fall through - default: - return PyErr_Format(PyExc_TypeError, "%s.update() takes either a dict argument or keyword arguments", wrap->_base._name); - } - - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(dict, &pos, &key, &value)) { - if (wrap->_setitem_func(wrap->_base._self, key, value) != 0) { - return nullptr; - } - } - return Py_NewRef(Py_None); -} - -/** - * This variant defines only a generator interface. - */ -static PyObject *Dtool_GeneratorWrapper_iternext(PyObject *self) { - Dtool_GeneratorWrapper *wrap = (Dtool_GeneratorWrapper *)self; - nassertr(wrap, nullptr); - nassertr(wrap->_iternext_func, nullptr); - return wrap->_iternext_func(wrap->_base._self); -} - -/** - * This is a variant of the Python getset mechanism that permits static - * properties. - */ -static void -Dtool_StaticProperty_dealloc(PyDescrObject *descr) { -#if PY_VERSION_HEX >= 0x03080000 - PyObject_GC_UnTrack(descr); -#else - _PyObject_GC_UNTRACK(descr); -#endif - Py_XDECREF(descr->d_type); - Py_XDECREF(descr->d_name); -//#if PY_MAJOR_VERSION >= 3 -// Py_XDECREF(descr->d_qualname); -//#endif - PyObject_GC_Del(descr); -} - -static PyObject * -Dtool_StaticProperty_repr(PyDescrObject *descr, const char *format) { -#if PY_MAJOR_VERSION >= 3 - return PyUnicode_FromFormat("", - PyUnicode_AsUTF8(descr->d_name), - descr->d_type->tp_name); -#else - return PyString_FromFormat("", - PyString_AS_STRING(descr->d_name), - descr->d_type->tp_name); -#endif -} - -static int -Dtool_StaticProperty_traverse(PyObject *self, visitproc visit, void *arg) { - PyDescrObject *descr = (PyDescrObject *)self; - Py_VISIT(descr->d_type); - return 0; -} - -static PyObject * -Dtool_StaticProperty_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) { - if (descr->d_getset->get != nullptr) { - return descr->d_getset->get(obj, descr->d_getset->closure); - } else { - return PyErr_Format(PyExc_AttributeError, - "attribute '%s' of type '%.100s' is not readable", -#if PY_MAJOR_VERSION >= 3 - PyUnicode_AsUTF8(((PyDescrObject *)descr)->d_name), -#else - PyString_AS_STRING(((PyDescrObject *)descr)->d_name), -#endif - ((PyDescrObject *)descr)->d_type->tp_name); - } -} - -static int -Dtool_StaticProperty_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) { - if (descr->d_getset->set != nullptr) { - return descr->d_getset->set(obj, value, descr->d_getset->closure); - } else { - PyErr_Format(PyExc_AttributeError, - "attribute '%s' of type '%.100s' is not writable", -#if PY_MAJOR_VERSION >= 3 - PyUnicode_AsUTF8(((PyDescrObject *)descr)->d_name), -#else - PyString_AS_STRING(((PyDescrObject *)descr)->d_name), -#endif - ((PyDescrObject *)descr)->d_type->tp_name); - return -1; - } -} - -/** - * This wraps around a property that exposes a sequence interface. - */ -Dtool_SequenceWrapper *Dtool_NewSequenceWrapper(PyObject *self, const char *name) { - Dtool_SequenceWrapper *wrap = (Dtool_SequenceWrapper *)PyObject_MALLOC(sizeof(Dtool_SequenceWrapper)); - if (wrap == nullptr) { - return (Dtool_SequenceWrapper *)PyErr_NoMemory(); - } - - static PySequenceMethods seq_methods = { - Dtool_SequenceWrapper_length, - nullptr, // sq_concat - nullptr, // sq_repeat - Dtool_SequenceWrapper_getitem, - nullptr, // sq_slice - nullptr, // sq_ass_item - nullptr, // sq_ass_slice - Dtool_SequenceWrapper_contains, - nullptr, // sq_inplace_concat - nullptr, // sq_inplace_repeat - }; - - static PyMethodDef methods[] = { - {"index", &Dtool_SequenceWrapper_index, METH_O, nullptr}, - {"count", &Dtool_SequenceWrapper_count, METH_O, nullptr}, - {nullptr, nullptr, 0, nullptr} - }; - - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "sequence wrapper", - sizeof(Dtool_SequenceWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - Dtool_SequenceWrapper_repr, - nullptr, // tp_as_number - &seq_methods, - nullptr, // tp_as_mapping - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - PySeqIter_New, - nullptr, // tp_iternext - methods, - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - static bool registered = false; - if (!registered) { - registered = true; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - // If the collections.abc module is loaded, register this as a subclass. - _register_collection((PyTypeObject *)&wrapper_type, "Sequence"); - } - - (void)PyObject_INIT(wrap, &wrapper_type); - wrap->_base._self = Py_XNewRef(self); - wrap->_base._name = name; - wrap->_len_func = nullptr; - wrap->_getitem_func = nullptr; - return wrap; -} - -/** - * This wraps around a property that exposes a mutable sequence interface. - */ -Dtool_MutableSequenceWrapper *Dtool_NewMutableSequenceWrapper(PyObject *self, const char *name) { - Dtool_MutableSequenceWrapper *wrap = (Dtool_MutableSequenceWrapper *)PyObject_MALLOC(sizeof(Dtool_MutableSequenceWrapper)); - if (wrap == nullptr) { - return (Dtool_MutableSequenceWrapper *)PyErr_NoMemory(); - } - - static PySequenceMethods seq_methods = { - Dtool_SequenceWrapper_length, - nullptr, // sq_concat - nullptr, // sq_repeat - Dtool_SequenceWrapper_getitem, - nullptr, // sq_slice - Dtool_MutableSequenceWrapper_setitem, - nullptr, // sq_ass_slice - Dtool_SequenceWrapper_contains, - Dtool_MutableSequenceWrapper_extend, - nullptr, // sq_inplace_repeat - }; - - static PyMethodDef methods[] = { - {"index", &Dtool_SequenceWrapper_index, METH_O, nullptr}, - {"count", &Dtool_SequenceWrapper_count, METH_O, nullptr}, - {"clear", &Dtool_MutableSequenceWrapper_clear, METH_NOARGS, nullptr}, - {"pop", &Dtool_MutableSequenceWrapper_pop, METH_VARARGS, nullptr}, - {"remove", &Dtool_MutableSequenceWrapper_remove, METH_O, nullptr}, - {"append", &Dtool_MutableSequenceWrapper_append, METH_O, nullptr}, - {"insert", &Dtool_MutableSequenceWrapper_insert, METH_VARARGS, nullptr}, - {"extend", &Dtool_MutableSequenceWrapper_extend, METH_O, nullptr}, - {nullptr, nullptr, 0, nullptr} - }; - - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "sequence wrapper", - sizeof(Dtool_MutableSequenceWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - Dtool_SequenceWrapper_repr, - nullptr, // tp_as_number - &seq_methods, - nullptr, // tp_as_mapping - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - PySeqIter_New, - nullptr, // tp_iternext - methods, - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - static bool registered = false; - if (!registered) { - registered = true; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - // If the collections.abc module is loaded, register this as a subclass. - _register_collection((PyTypeObject *)&wrapper_type, "MutableSequence"); - } - - (void)PyObject_INIT(wrap, &wrapper_type); - wrap->_base._self = Py_XNewRef(self); - wrap->_base._name = name; - wrap->_len_func = nullptr; - wrap->_getitem_func = nullptr; - wrap->_setitem_func = nullptr; - wrap->_insert_func = nullptr; - return wrap; -} - -/** - * This wraps around a mapping interface, with getitem function. - */ -Dtool_MappingWrapper *Dtool_NewMappingWrapper(PyObject *self, const char *name) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper)); - if (wrap == nullptr) { - return (Dtool_MappingWrapper *)PyErr_NoMemory(); - } - - static PySequenceMethods seq_methods = { - Dtool_SequenceWrapper_length, - nullptr, // sq_concat - nullptr, // sq_repeat - nullptr, // sq_item - nullptr, // sq_slice - nullptr, // sq_ass_item - nullptr, // sq_ass_slice - Dtool_MappingWrapper_contains, - nullptr, // sq_inplace_concat - nullptr, // sq_inplace_repeat - }; - - static PyMappingMethods map_methods = { - Dtool_SequenceWrapper_length, - Dtool_MappingWrapper_getitem, - nullptr, // mp_ass_subscript - }; - - static PyMethodDef methods[] = { - {"get", &Dtool_MappingWrapper_get, METH_VARARGS, nullptr}, - {"keys", &Dtool_MappingWrapper_keys, METH_NOARGS, nullptr}, - {"values", &Dtool_MappingWrapper_values, METH_NOARGS, nullptr}, - {"items", &Dtool_MappingWrapper_items, METH_NOARGS, nullptr}, - {nullptr, nullptr, 0, nullptr} - }; - - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "mapping wrapper", - sizeof(Dtool_MappingWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - Dtool_WrapperBase_repr, - nullptr, // tp_as_number - &seq_methods, - &map_methods, - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - Dtool_MappingWrapper_iter, - nullptr, // tp_iternext - methods, - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - static bool registered = false; - if (!registered) { - registered = true; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - // If the collections.abc module is loaded, register this as a subclass. - _register_collection((PyTypeObject *)&wrapper_type, "Mapping"); - } - - (void)PyObject_INIT(wrap, &wrapper_type); - wrap->_base._self = Py_XNewRef(self); - wrap->_base._name = name; - wrap->_keys._len_func = nullptr; - wrap->_keys._getitem_func = nullptr; - wrap->_getitem_func = nullptr; - wrap->_setitem_func = nullptr; - return wrap; -} - -/** - * This wraps around a mapping interface, with getitem/setitem functions. - */ -Dtool_MappingWrapper *Dtool_NewMutableMappingWrapper(PyObject *self, const char *name) { - Dtool_MappingWrapper *wrap = (Dtool_MappingWrapper *)PyObject_MALLOC(sizeof(Dtool_MappingWrapper)); - if (wrap == nullptr) { - return (Dtool_MappingWrapper *)PyErr_NoMemory(); - } - - static PySequenceMethods seq_methods = { - Dtool_SequenceWrapper_length, - nullptr, // sq_concat - nullptr, // sq_repeat - nullptr, // sq_item - nullptr, // sq_slice - nullptr, // sq_ass_item - nullptr, // sq_ass_slice - Dtool_MappingWrapper_contains, - nullptr, // sq_inplace_concat - nullptr, // sq_inplace_repeat - }; - - static PyMappingMethods map_methods = { - Dtool_SequenceWrapper_length, - Dtool_MappingWrapper_getitem, - Dtool_MutableMappingWrapper_setitem, - }; - - static PyMethodDef methods[] = { - {"get", &Dtool_MappingWrapper_get, METH_VARARGS, nullptr}, - {"pop", &Dtool_MutableMappingWrapper_pop, METH_VARARGS, nullptr}, - {"popitem", &Dtool_MutableMappingWrapper_popitem, METH_NOARGS, nullptr}, - {"clear", &Dtool_MutableMappingWrapper_clear, METH_VARARGS, nullptr}, - {"setdefault", &Dtool_MutableMappingWrapper_setdefault, METH_VARARGS, nullptr}, - {"update", (PyCFunction) &Dtool_MutableMappingWrapper_update, METH_VARARGS | METH_KEYWORDS, nullptr}, - {"keys", &Dtool_MappingWrapper_keys, METH_NOARGS, nullptr}, - {"values", &Dtool_MappingWrapper_values, METH_NOARGS, nullptr}, - {"items", &Dtool_MappingWrapper_items, METH_NOARGS, nullptr}, - {nullptr, nullptr, 0, nullptr} - }; - - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "mapping wrapper", - sizeof(Dtool_MappingWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - Dtool_WrapperBase_repr, - nullptr, // tp_as_number - &seq_methods, - &map_methods, - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - Dtool_MappingWrapper_iter, - nullptr, // tp_iternext - methods, - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - static bool registered = false; - if (!registered) { - registered = true; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - // If the collections.abc module is loaded, register this as a subclass. - _register_collection((PyTypeObject *)&wrapper_type, "MutableMapping"); - } - - (void)PyObject_INIT(wrap, &wrapper_type); - wrap->_base._self = Py_XNewRef(self); - wrap->_base._name = name; - wrap->_keys._len_func = nullptr; - wrap->_keys._getitem_func = nullptr; - wrap->_getitem_func = nullptr; - wrap->_setitem_func = nullptr; - return wrap; -} - -/** - * Creates a generator that invokes a given function with the given self arg. - */ -PyObject * -Dtool_NewGenerator(PyObject *self, iternextfunc gen_next) { - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(nullptr, 0) - "generator wrapper", - sizeof(Dtool_GeneratorWrapper), - 0, // tp_itemsize - Dtool_WrapperBase_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_compare - nullptr, // tp_repr - nullptr, // tp_as_number - nullptr, // tp_as_sequence - nullptr, // tp_as_mapping - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - PyObject_GenericSetAttr, - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, - nullptr, // tp_doc - nullptr, // tp_traverse - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - PyObject_SelfIter, - Dtool_GeneratorWrapper_iternext, - nullptr, // tp_methods - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - nullptr, // tp_descr_get - nullptr, // tp_descr_set - 0, // tp_dictoffset - nullptr, // tp_init - PyType_GenericAlloc, - nullptr, // tp_new - PyObject_Del, - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - Dtool_GeneratorWrapper *gen; - gen = (Dtool_GeneratorWrapper *)PyType_GenericAlloc(&wrapper_type, 0); - if (gen != nullptr) { - gen->_base._self = Py_NewRef(self); - gen->_iternext_func = gen_next; - } - return (PyObject *)gen; -} - -/** - * This is a variant of the Python getset mechanism that permits static - * properties. - */ -PyObject * -Dtool_NewStaticProperty(PyTypeObject *type, const PyGetSetDef *getset) { - static PyTypeObject wrapper_type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "getset_descriptor", - sizeof(PyGetSetDescrObject), - 0, // tp_itemsize - (destructor)Dtool_StaticProperty_dealloc, - 0, // tp_vectorcall_offset - nullptr, // tp_getattr - nullptr, // tp_setattr - nullptr, // tp_reserved - (reprfunc)Dtool_StaticProperty_repr, - nullptr, // tp_as_number - nullptr, // tp_as_sequence - nullptr, // tp_as_mapping - nullptr, // tp_hash - nullptr, // tp_call - nullptr, // tp_str - PyObject_GenericGetAttr, - nullptr, // tp_setattro - nullptr, // tp_as_buffer - Py_TPFLAGS_DEFAULT, - nullptr, // tp_doc - Dtool_StaticProperty_traverse, - nullptr, // tp_clear - nullptr, // tp_richcompare - 0, // tp_weaklistoffset - nullptr, // tp_iter - nullptr, // tp_iternext - nullptr, // tp_methods - nullptr, // tp_members - nullptr, // tp_getset - nullptr, // tp_base - nullptr, // tp_dict - (descrgetfunc)Dtool_StaticProperty_get, - (descrsetfunc)Dtool_StaticProperty_set, - 0, // tp_dictoffset - nullptr, // tp_init - nullptr, // tp_alloc - nullptr, // tp_new - nullptr, // tp_free - nullptr, // tp_is_gc - nullptr, // tp_bases - nullptr, // tp_mro - nullptr, // tp_cache - nullptr, // tp_subclasses - nullptr, // tp_weaklist - nullptr, // tp_del - 0, // tp_version_tag, -#if PY_VERSION_HEX >= 0x03040000 - nullptr, // tp_finalize -#endif -#if PY_VERSION_HEX >= 0x03080000 - nullptr, // tp_vectorcall -#endif - }; - - if (PyType_Ready(&wrapper_type) < 0) { - return nullptr; - } - - PyGetSetDescrObject *descr; - descr = (PyGetSetDescrObject *)PyType_GenericAlloc(&wrapper_type, 0); - if (descr != nullptr) { - Py_XINCREF(type); - descr->d_getset = (PyGetSetDef *)getset; -#if PY_MAJOR_VERSION >= 3 - descr->d_common.d_type = type; - descr->d_common.d_name = PyUnicode_InternFromString(getset->name); -#if PY_VERSION_HEX >= 0x03030000 - descr->d_common.d_qualname = nullptr; -#endif -#else - descr->d_type = type; - descr->d_name = PyString_InternFromString(getset->name); -#endif - } - return (PyObject *)descr; -} - -#endif // HAVE_PYTHON diff --git a/dtool/src/parser-inc/algorithm b/dtool/src/parser-inc/algorithm index 751a8ec2cbd..52d538e5f28 100644 --- a/dtool/src/parser-inc/algorithm +++ b/dtool/src/parser-inc/algorithm @@ -25,7 +25,11 @@ namespace std { constexpr const T &min(const T &a, const T &b); template constexpr const T &max(const T &a, const T &b); + + template + void sort(RandomIt first, RandomIt last); + template + void sort(RandomIt first, RandomIt last, Compare comp); } #endif - diff --git a/dtool/src/parser-inc/emscripten/heap.h b/dtool/src/parser-inc/emscripten/heap.h new file mode 100644 index 00000000000..b4047a9fb88 --- /dev/null +++ b/dtool/src/parser-inc/emscripten/heap.h @@ -0,0 +1,9 @@ + +#pragma once + +#include +#include +#include + +#define WASM_PAGE_SIZE 65536 +#define EMSCRIPTEN_PAGE_SIZE WASM_PAGE_SIZE diff --git a/dtool/src/prc/notify.cxx b/dtool/src/prc/notify.cxx index 009c6ab818f..ce7df151c62 100644 --- a/dtool/src/prc/notify.cxx +++ b/dtool/src/prc/notify.cxx @@ -467,12 +467,12 @@ config_initialized() { Notify *ptr = Notify::ptr(); - for (int i = 0; i <= NS_fatal; ++i) { + for (int severity = 0; severity <= NS_fatal; ++severity) { int priority = ANDROID_LOG_UNKNOWN; if (severity != NS_unspecified) { - priority = i + 1; + priority = severity + 1; } - ptr->_log_streams[i] = new AndroidLogStream(priority); + ptr->_log_streams[severity] = new AndroidLogStream(priority); } #elif defined(__EMSCRIPTEN__) diff --git a/dtool/src/test_interrogate/test_interrogate.cxx b/dtool/src/test_interrogate/test_interrogate.cxx deleted file mode 100644 index a518f12cc43..00000000000 --- a/dtool/src/test_interrogate/test_interrogate.cxx +++ /dev/null @@ -1,615 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file test_interrogate.cxx - * @author drose - * @date 1999-12-09 - */ - -#include "dtoolbase.h" - -#include "interrogate_interface.h" -#include "interrogate_request.h" -#include "load_dso.h" -#include "filename.h" -#include "panda_getopt.h" -#include "preprocess_argv.h" - -#include - -using std::cerr; -using std::cout; -using std::ostream; -using std::string; - -static ostream & -indent(ostream &out, int indent_level) { - for (int i = 0; i < indent_level; i++) { - out << ' '; - } - return out; -} - -// Indents one or more lines of text, breaking the text up at newline -// characters. -static ostream & -hanging_indent(ostream &out, const string &text, int first_indent_level, - int next_indent_level = -1) { - if (next_indent_level < 0) { - next_indent_level = first_indent_level; - } - - size_t start = 0; - size_t newline = text.find('\n'); - int indent_level = first_indent_level; - while (newline != string::npos) { - indent(out, indent_level) - << text.substr(start, newline - start) << "\n"; - start = newline + 1; - newline = text.find('\n', start); - indent_level = next_indent_level; - } - indent(out, indent_level) - << text.substr(start) << "\n"; - - return out; -} - -void -show_type(int type, bool verbose = false) { - cout << interrogate_type_name(type) << " "; - if (verbose) { - if (strcmp(interrogate_type_name(type), - interrogate_type_true_name(type)) != 0) { - cout << "(" << interrogate_type_true_name(type) << ") "; - } - } - cout << "(" << type << ")"; -} - -void -show_function(int function) { - cout << interrogate_function_scoped_name(function) << " (" << function << ")"; -} - -void -describe_wrapper(int wrapper, int indent_level) { - indent(cout, indent_level) - << "Wrapper (" << wrapper << ")"; - - if (interrogate_wrapper_has_return_value(wrapper)) { - cout << " returns "; - show_type(interrogate_wrapper_return_type(wrapper)); - } else { - cout << " no return value"; - } - - int num_params = interrogate_wrapper_number_of_parameters(wrapper); - cout << ", "; - if (num_params == 0) { - cout << "no parameters.\n"; - } else if (num_params == 1) { - cout << "1 parameter:\n"; - } else { - cout << num_params << " parameters:\n"; - } - - for (int i = 0; i < num_params; i++) { - indent(cout, indent_level + 4); - if (interrogate_wrapper_parameter_is_this(wrapper, i)) { - cout << "*"; - } else { - cout << i; - } - cout << ": "; - show_type(interrogate_wrapper_parameter_type(wrapper, i)); - if (interrogate_wrapper_parameter_has_name(wrapper, i)) { - cout << " '" << interrogate_wrapper_parameter_name(wrapper, i) << "'"; - } else { - cout << " (no name)"; - } - cout << "\n"; - } - - if (interrogate_wrapper_has_comment(wrapper)) { - string comment = interrogate_wrapper_comment(wrapper); - hanging_indent(cout, comment, indent_level + 2); - } - - - if (interrogate_wrapper_caller_manages_return_value(wrapper)) { - indent(cout, indent_level + 2) - << "Caller manages return value using "; - show_function(interrogate_wrapper_return_value_destructor(wrapper)); - cout << "\n"; - } - - indent(cout, indent_level + 2) - << "Wrapper name: " << interrogate_wrapper_name(wrapper); - if (interrogate_wrapper_is_callable_by_name(wrapper)) { - cout << " (callable)"; - } - cout << "\n"; - if (interrogate_wrapper_has_pointer(wrapper)) { - indent(cout, indent_level + 2) - << "Has pointer: " << interrogate_wrapper_pointer(wrapper) << "\n"; - } - string unique_name = interrogate_wrapper_unique_name(wrapper); - indent(cout, indent_level + 2) - << "Unique name is " << unique_name; - int reverse_lookup = interrogate_get_wrapper_by_unique_name(unique_name.c_str()); - if (reverse_lookup == 0) { - cout << " (no reverse lookup)"; - } else if (reverse_lookup != wrapper) { - cout << " (*** reverse lookup returns " << reverse_lookup << "! ***)"; - } - cout << "\n"; -} - -void -describe_function(int function, int indent_level) { - indent(cout, indent_level) - << "Function " << interrogate_function_scoped_name(function) - << " (" << function << ")\n"; - - indent(cout, indent_level + 2) - << "In C: "; - hanging_indent(cout, interrogate_function_prototype(function), - 0, indent_level + 2 + 6); - - if (interrogate_function_is_method(function)) { - indent(cout, indent_level + 2) - << "Method of "; - show_type(interrogate_function_class(function)); - cout << "\n"; - } - - if (interrogate_function_is_virtual(function)) { - indent(cout, indent_level + 2) << "is virtual.\n"; - } - - int w; - - int num_c_wrappers = interrogate_function_number_of_c_wrappers(function); - if (num_c_wrappers == 0) { - } else if (num_c_wrappers == 1) { - indent(cout, indent_level + 2) - << "1 C-style wrapper:\n"; - } else { - indent(cout, indent_level + 2) - << num_c_wrappers << " C-style wrappers:\n"; - } - for (w = 0; w < num_c_wrappers; w++) { - describe_wrapper(interrogate_function_c_wrapper(function, w), - indent_level + 4); - } - - int num_python_wrappers = - interrogate_function_number_of_python_wrappers(function); - if (num_python_wrappers == 0) { - } else if (num_python_wrappers == 1) { - indent(cout, indent_level + 2) - << "1 Python-style wrapper:\n"; - } else { - indent(cout, indent_level + 2) - << num_python_wrappers << " Python-style wrappers:\n"; - } - for (w = 0; w < num_python_wrappers; w++) { - describe_wrapper(interrogate_function_python_wrapper(function, w), - indent_level + 4); - } -} - -void -describe_make_seq(int make_seq, int indent_level) { - indent(cout, indent_level) - << "MakeSeq " << interrogate_make_seq_seq_name(make_seq) - << " (" << make_seq << "): " - << interrogate_make_seq_num_name(make_seq) - << ", " << interrogate_make_seq_element_name(make_seq) - << "\n"; -} - -void -report_manifests() { - int num_manifests = interrogate_number_of_manifests(); - cout << "\n" << num_manifests << " manifests:\n"; - for (int i = 0; i < num_manifests; i++) { - int manifest = interrogate_get_manifest(i); - - cout << " Manifest " << interrogate_manifest_name(manifest); - if (interrogate_manifest_has_type(manifest)) { - cout << " of type "; - show_type(interrogate_manifest_get_type(manifest)); - cout << "\n"; - } else { - cout << " of unknown type\n"; - } - cout << " definition is \"" - << interrogate_manifest_definition(manifest) << "\"\n"; - - if (interrogate_manifest_has_getter(manifest)) { - cout << " value getter: "; - show_function(interrogate_manifest_getter(manifest)); - cout << "\n"; - } - - if (interrogate_manifest_has_int_value(manifest)) { - cout << " int value = " - << interrogate_manifest_get_int_value(manifest) - << "\n"; - } - } -} - -void -describe_element(int element, int indent_level) { - indent(cout, indent_level) - << "Element " << interrogate_element_scoped_name(element) - << " of type "; - show_type(interrogate_element_type(element)); - cout << "\n"; - - if (interrogate_element_has_getter(element)) { - indent(cout, indent_level + 2) - << "Getter is "; - show_function(interrogate_element_getter(element)); - cout << "\n"; - } - - if (interrogate_element_has_setter(element)) { - indent(cout, indent_level + 2) - << "Setter is "; - show_function(interrogate_element_setter(element)); - cout << "\n"; - } -} - -void -report_globals() { - int num_globals = interrogate_number_of_globals(); - cout << "\n" << num_globals << " globals:\n"; - for (int i = 0; i < num_globals; i++) { - describe_element(interrogate_get_global(i), 2); - } -} - -void -describe_type(int type, int indent_level) { - indent(cout, indent_level) << "Type "; - show_type(type, true); - cout << "\n"; - - if (interrogate_type_has_comment(type)) { - string comment = interrogate_type_comment(type); - hanging_indent(cout, comment, indent_level + 2); - } - - if (interrogate_type_is_nested(type)) { - indent(cout, indent_level + 2) - << "Nested within "; - show_type(interrogate_type_outer_class(type)); - cout << "\n"; - } - if (interrogate_type_is_atomic(type)) { - indent(cout, indent_level + 2) - << "atomic " << (int)interrogate_type_atomic_token(type) << "\n"; - } - if (interrogate_type_is_unsigned(type)) { - indent(cout, indent_level + 2) - << "unsigned\n"; - } - if (interrogate_type_is_signed(type)) { - indent(cout, indent_level + 2) - << "signed\n"; - } - if (interrogate_type_is_long(type)) { - indent(cout, indent_level + 2) - << "long\n"; - } - if (interrogate_type_is_longlong(type)) { - indent(cout, indent_level + 2) - << "long long\n"; - } - if (interrogate_type_is_short(type)) { - indent(cout, indent_level + 2) - << "short\n"; - } - if (interrogate_type_is_wrapped(type)) { - indent(cout, indent_level + 2) - << "wrapped "; - show_type(interrogate_type_wrapped_type(type)); - cout << "\n"; - } - if (interrogate_type_is_pointer(type)) { - indent(cout, indent_level + 2) - << "pointer\n"; - } - if (interrogate_type_is_const(type)) { - indent(cout, indent_level + 2) - << "const\n"; - } - if (interrogate_type_is_fully_defined(type)) { - indent(cout, indent_level + 2) - << "fully defined\n"; - } - if (interrogate_type_is_unpublished(type)) { - indent(cout, indent_level + 2) - << "undefined because unpublished\n"; - } - if (interrogate_type_is_enum(type)) { - indent(cout, indent_level + 2) - << "is enum type\n"; - } - if (interrogate_type_is_struct(type)) { - indent(cout, indent_level + 2) - << "is struct type\n"; - } - if (interrogate_type_is_class(type)) { - indent(cout, indent_level + 2) - << "is class type\n"; - } - if (interrogate_type_is_union(type)) { - indent(cout, indent_level + 2) - << "is union type\n"; - } - int num_enum_values = interrogate_type_number_of_enum_values(type); - if (num_enum_values > 0) { - for (int i = 0; i < num_enum_values; i++) { - indent(cout, indent_level + 4) - << interrogate_type_enum_value_name(type, i) - << " = " << interrogate_type_enum_value(type, i) << "\n"; - } - } - int num_constructors = interrogate_type_number_of_constructors(type); - if (num_constructors > 0) { - indent(cout, indent_level + 2) - << num_constructors << " constructors:\n"; - for (int i = 0; i < num_constructors; i++) { - describe_function(interrogate_type_get_constructor(type, i), 6); - } - } - if (interrogate_type_has_destructor(type)) { - indent(cout, indent_level + 2) - << "destructor:\n"; - describe_function(interrogate_type_get_destructor(type), 6); - } - int num_casts = interrogate_type_number_of_casts(type); - if (num_casts > 0) { - indent(cout, indent_level + 2) - << num_casts << " casts:\n"; - for (int i = 0; i < num_casts; i++) { - describe_function(interrogate_type_get_cast(type, i), 6); - } - } - int num_methods = interrogate_type_number_of_methods(type); - if (num_methods > 0) { - indent(cout, indent_level + 2) - << num_methods << " methods:\n"; - for (int i = 0; i < num_methods; i++) { - describe_function(interrogate_type_get_method(type, i), 6); - } - } - int num_make_seqs = interrogate_type_number_of_make_seqs(type); - if (num_make_seqs > 0) { - indent(cout, indent_level + 2) - << num_make_seqs << " make_seqs:\n"; - for (int i = 0; i < num_make_seqs; i++) { - describe_make_seq(interrogate_type_get_make_seq(type, i), 6); - } - } - int num_elements = interrogate_type_number_of_elements(type); - if (num_elements > 0) { - indent(cout, indent_level + 2) - << num_elements << " elements:\n"; - for (int i = 0; i < num_elements; i++) { - describe_element(interrogate_type_get_element(type, i), indent_level + 2); - } - } - int num_derivations = interrogate_type_number_of_derivations(type); - if (num_derivations > 0) { - indent(cout, indent_level + 2) - << num_derivations << " derivations:\n"; - for (int i = 0; i < num_derivations; i++) { - int derivation = interrogate_type_get_derivation(type, i); - indent(cout, indent_level + 4); - show_type(derivation); - if (interrogate_type_derivation_has_upcast(type, i)) { - cout << " (has upcast)"; - } - if (interrogate_type_derivation_downcast_is_impossible(type, i)) { - cout << " (downcast is impossible)"; - } - if (interrogate_type_derivation_has_downcast(type, i)) { - cout << " (has downcast)"; - } - cout << "\n"; - /* - if (interrogate_type_derivation_has_upcast(type, i)) { - describe_function(interrogate_type_get_upcast(type, i), 8); - } - if (interrogate_type_derivation_has_downcast(type, i)) { - describe_function(interrogate_type_get_downcast(type, i), 8); - } - */ - } - } - int num_nested_types = interrogate_type_number_of_nested_types(type); - if (num_nested_types > 0) { - indent(cout, indent_level + 2) - << num_nested_types << " nested types:\n"; - for (int i = 0; i < num_nested_types; i++) { - indent(cout, indent_level + 4); - show_type(interrogate_type_get_nested_type(type, i)); - cout << "\n"; - } - } -} - -void -report_global_types() { - int num_types = interrogate_number_of_global_types(); - cout << "\n" << num_types << " global types:\n"; - - for (int i = 0; i < num_types; i++) { - int type = interrogate_get_global_type(i); - describe_type(type, 2); - } -} - -void -report_global_functions() { - int num_functions = interrogate_number_of_global_functions(); - cout << "\n" << num_functions << " global functions:\n"; - for (int i = 0; i < num_functions; i++) { - int function = interrogate_get_global_function(i); - describe_function(function, 2); - } -} - -void -report_all_types() { - int num_types = interrogate_number_of_types(); - cout << "\n" << num_types << " total types:\n"; - - for (int i = 0; i < num_types; i++) { - int type = interrogate_get_type(i); - describe_type(type, 2); - } -} - -void -report_all_functions() { - int num_functions = interrogate_number_of_functions(); - cout << "\n" << num_functions << " total functions:\n"; - for (int i = 0; i < num_functions; i++) { - int function = interrogate_get_function(i); - describe_function(function, 2); - } -} - -void -usage() { - cerr << - "\n" - "test_interrogate [opts] libfile.so [libfile.so ...]\n\n" - - "Loads the given shared library or libraries, if possible, and reports the\n" - "symbols, types, and functions available within those libraries as reported\n" - "by interrogate.\n\n" - - "In lieu of loading a shared library, you may also read the interrogate\n" - "database file directly by specifying a filename like libfile.in. This will\n" - "report the symbols defined in that file only (without pulling in dependent\n" - "files), and will not have any function pointers available.\n\n" - - "Options:\n\n" - " -p [path]\n" - " Specify the search path for *.in files. This option may be repeated.\n" - " -f Give a detailed report of each function in the database, including\n" - " synthesized functions like upcasts and downcasts.\n" - " -t Give a detailed report of every type in the database, including types\n" - " like pointers and const pointers.\n" - " -q Quickly load up each shared library, if possible, and then immediately\n" - " exit. Useful for quickly determining whether a library can even load.\n\n"; -} - -int -main(int argc, char **argv) { - extern char *optarg; - extern int optind; - const char *optstr = "p:ftqh"; - - bool all_functions = false; - bool all_types = false; - bool quick_load = false; - preprocess_argv(argc, argv); - int flag = getopt(argc, argv, optstr); - - while (flag != EOF) { - switch (flag) { - case 'p': - interrogate_add_search_path(optarg); - break; - - case 'f': - all_functions = true; - break; - - case 't': - all_types = true; - break; - - case 'q': - quick_load = true; - break; - - case 'h': - usage(); - exit(0); - - default: - exit(1); - } - flag = getopt(argc, argv, optstr); - } - - argc -= (optind-1); - argv += (optind-1); - - if (argc < 2) { - cerr << "No libraries specified.\n"; - exit(1); - } - - int return_status = 0; - - for (int i = 1; i < argc; i++) { - string param = argv[i]; - - if (param.length() > 3 && param.substr(param.length() - 3) == ".in") { - // If the filename ends in ".in", it's an interrogate database file, not - // a shared library--read it directly. - interrogate_request_database(param.c_str()); - - } else { - // Otherwise, assume it's a shared library, and try to load it. - Filename pathname = Filename::dso_filename(argv[i]); - cerr << "Loading " << pathname << "\n"; - -#ifdef _WIN32 - // test_interrogate always wants to show an error dialog. - SetErrorMode(0); -#endif - - void *dl = load_dso(DSearchPath(), pathname); - if (dl == nullptr) { - cerr << "Unable to load: " << load_dso_error() << "\n"; - return_status++; - } - } - } - - if (!quick_load) { - if (all_types) { - report_all_types(); - } - if (all_functions) { - report_all_functions(); - } - - if (!all_types && !all_functions) { - report_manifests(); - report_globals(); - report_global_types(); - report_global_functions(); - } - } - - return (return_status); -} diff --git a/dtool/src/test_interrogate/test_lib.cxx b/dtool/src/test_interrogate/test_lib.cxx deleted file mode 100644 index 89ccafccfca..00000000000 --- a/dtool/src/test_interrogate/test_lib.cxx +++ /dev/null @@ -1,40 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file test_lib.cxx - * @author frang - * @date 2000-06-15 - */ - -#include "test_lib.h" - -int non_member1(float x, float y) { - return (int)(x + y); -} - -my_class1::my_class1(void) {} - -my_class1::my_class1(int) {} - -my_class1::~my_class1(void) {} - -float my_class1::method1(int x) { return (float)(x); } - -int my_class1::method2(float x) { return (int)(x); } - -int stupid_global; - -#include "dconfig.h" - -Configure(test_lib); - -ConfigureFn(test_lib) { - std::cerr << "In test_lib configure function!" << std::endl; -} - -ConfigureLibSym; diff --git a/dtool/src/test_interrogate/test_lib.h b/dtool/src/test_interrogate/test_lib.h deleted file mode 100644 index 9b316c941ea..00000000000 --- a/dtool/src/test_interrogate/test_lib.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file test_lib.h - * @author frang - * @date 2000-06-15 - */ - -#ifndef __TEST_LIB_H__ -#define __TEST_LIB_H__ - -int non_member1(float x, float); - -class my_class1 { -public: - my_class1(void); - my_class1(int); - - float method1(int); - - int _member1; -private: - ~my_class1(void); - - int method2(float); - - int _member2; -}; - -#endif /* __TEST_LIB_H__ */ diff --git a/makepanda/installer.nsi b/makepanda/installer.nsi index ba3cf769a3c..8b1ad01f586 100644 --- a/makepanda/installer.nsi +++ b/makepanda/installer.nsi @@ -86,7 +86,6 @@ LangString DESC_SecPython ${LANG_ENGLISH} "Contains a ${REGVIEW}-bit copy of Pyt LangString DESC_SecEnsurePip ${LANG_ENGLISH} "Installs the pip package manager into the included Python installation." LangString DESC_SecHeadersLibs ${LANG_ENGLISH} "Headers and libraries needed for C++ development with Panda3D." LangString DESC_SecSamples ${LANG_ENGLISH} "The sample programs demonstrate how to make Python applications with Panda3D." -LangString DESC_SecMaxPlugins ${LANG_ENGLISH} "Plug-ins for Autodesk 3ds Max (${REGVIEW}-bit) that can be used to export models to Panda3D." LangString DESC_SecMayaPlugins ${LANG_ENGLISH} "Plug-ins and scripts for Autodesk Maya (${REGVIEW}-bit) that can be used to export models to Panda3D." var READABLE @@ -114,7 +113,6 @@ var READABLE !insertmacro !defineifexist HAVE_BULLET "${BUILT}\bin\libpandabullet.dll" !insertmacro !defineifexist HAVE_ODE "${BUILT}\bin\libpandaode.dll" !insertmacro !defineifexist HAVE_SAMPLES "${SOURCE}\samples" -!insertmacro !defineifexist HAVE_MAX_PLUGINS "${BUILT}\plugins\*.dlo" !insertmacro !defineifexist HAVE_MAYA_PLUGINS "${BUILT}\plugins\*.mll" !macro RemovePythonPath PYVER @@ -147,7 +145,6 @@ var READABLE File /nonfatal /r "${BUILT}\panda3d\direct${EXT_SUFFIX}" File /nonfatal /r "${BUILT}\panda3d\egg${EXT_SUFFIX}" File /nonfatal /r "${BUILT}\panda3d\fx${EXT_SUFFIX}" - File /nonfatal /r "${BUILT}\panda3d\interrogatedb${EXT_SUFFIX}" File /nonfatal /r "${BUILT}\panda3d\physics${EXT_SUFFIX}" File /nonfatal /r "${BUILT}\panda3d\_rplight${EXT_SUFFIX}" File /nonfatal /r "${BUILT}\panda3d\skel${EXT_SUFFIX}" @@ -384,6 +381,7 @@ SectionGroup "Python modules" SecGroupPython !insertmacro PyBindingSection 3.11-32 .cp311-win32.pyd !insertmacro PyBindingSection 3.12-32 .cp312-win32.pyd !insertmacro PyBindingSection 3.13-32 .cp313-win32.pyd + !insertmacro PyBindingSection 3.14-32 .cp314-win32.pyd !else !insertmacro PyBindingSection 3.5 .cp35-win_amd64.pyd !insertmacro PyBindingSection 3.6 .cp36-win_amd64.pyd @@ -394,6 +392,7 @@ SectionGroup "Python modules" SecGroupPython !insertmacro PyBindingSection 3.11 .cp311-win_amd64.pyd !insertmacro PyBindingSection 3.12 .cp312-win_amd64.pyd !insertmacro PyBindingSection 3.13 .cp313-win_amd64.pyd + !insertmacro PyBindingSection 3.14 .cp314-win_amd64.pyd !endif SectionGroupEnd @@ -505,6 +504,7 @@ Function .onInit !insertmacro MaybeEnablePyBindingSection 3.11-32 !insertmacro MaybeEnablePyBindingSection 3.12-32 !insertmacro MaybeEnablePyBindingSection 3.13-32 + !insertmacro MaybeEnablePyBindingSection 3.14-32 ${EndIf} !else !insertmacro MaybeEnablePyBindingSection 3.5 @@ -517,6 +517,7 @@ Function .onInit !insertmacro MaybeEnablePyBindingSection 3.11 !insertmacro MaybeEnablePyBindingSection 3.12 !insertmacro MaybeEnablePyBindingSection 3.13 + !insertmacro MaybeEnablePyBindingSection 3.14 ${EndIf} !endif @@ -542,6 +543,10 @@ Function .onInit SectionSetFlags ${SecPyBindings3.13} ${SF_RO} SectionSetInstTypes ${SecPyBindings3.13} 0 !endif + !ifdef SecPyBindings3.14 + SectionSetFlags ${SecPyBindings3.14} ${SF_RO} + SectionSetInstTypes ${SecPyBindings3.14} 0 + !endif ${EndUnless} FunctionEnd @@ -698,21 +703,6 @@ Section "Sample programs" SecSamples SectionEnd !endif -!ifdef HAVE_MAX_PLUGINS -Section "3ds Max plug-ins" SecMaxPlugins - SectionIn 1 2 - - SetDetailsPrint both - DetailPrint "Installing Autodesk 3ds Max plug-ins..." - SetDetailsPrint listonly - - SetOutPath $INSTDIR\plugins - File /nonfatal /r "${BUILT}\plugins\*.dle" - File /nonfatal /r "${BUILT}\plugins\*.dlo" - File /nonfatal /r "${BUILT}\plugins\*.ms" -SectionEnd -!endif - !ifdef HAVE_MAYA_PLUGINS Section "Maya plug-ins" SecMayaPlugins SectionIn 1 2 @@ -861,6 +851,7 @@ Section Uninstall !insertmacro RemovePythonPath 3.11-32 !insertmacro RemovePythonPath 3.12-32 !insertmacro RemovePythonPath 3.13-32 + !insertmacro RemovePythonPath 3.14-32 !else !insertmacro RemovePythonPath 3.5 !insertmacro RemovePythonPath 3.6 @@ -871,6 +862,7 @@ Section Uninstall !insertmacro RemovePythonPath 3.11 !insertmacro RemovePythonPath 3.12 !insertmacro RemovePythonPath 3.13 + !insertmacro RemovePythonPath 3.14 !endif SetDetailsPrint both @@ -942,6 +934,7 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.11-32} $(DESC_SecPyBindings3.11-32) !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.12-32} $(DESC_SecPyBindings3.12-32) !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.13-32} $(DESC_SecPyBindings3.13-32) + !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.14-32} $(DESC_SecPyBindings3.14-32) !else !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.5} $(DESC_SecPyBindings3.5) !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.6} $(DESC_SecPyBindings3.6) @@ -952,6 +945,7 @@ SectionEnd !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.11} $(DESC_SecPyBindings3.11) !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.12} $(DESC_SecPyBindings3.12) !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.13} $(DESC_SecPyBindings3.13) + !insertmacro MUI_DESCRIPTION_TEXT ${SecPyBindings3.14} $(DESC_SecPyBindings3.14) !endif !ifdef INCLUDE_PYVER !insertmacro MUI_DESCRIPTION_TEXT ${SecPython} $(DESC_SecPython) @@ -961,9 +955,6 @@ SectionEnd !ifdef HAVE_SAMPLES !insertmacro MUI_DESCRIPTION_TEXT ${SecSamples} $(DESC_SecSamples) !endif - !ifdef HAVE_MAX_PLUGINS - !insertmacro MUI_DESCRIPTION_TEXT ${SecMaxPlugins} $(DESC_SecMaxPlugins) - !endif !ifdef HAVE_MAYA_PLUGINS !insertmacro MUI_DESCRIPTION_TEXT ${SecMayaPlugins} $(DESC_SecMayaPlugins) !endif diff --git a/makepanda/installpanda.py b/makepanda/installpanda.py index 6ac2474a50d..1d8f4deef98 100644 --- a/makepanda/installpanda.py +++ b/makepanda/installpanda.py @@ -29,6 +29,9 @@ ("pstats", "Panda3D Profiling Tool", ("pstats",), False), ) +EXCLUDE_BINARIES = ["deploy-stub", "deploy-stubw", "run_tests"] + + def WriteApplicationsFile(fname, appinfo, mimeinfo, bindir): fhandle = open(fname, "w") for app, desc, exts, multiple in appinfo: @@ -265,7 +268,7 @@ def InstallPanda(destdir="", prefix="/usr", outputdir="built", libdir=GetLibDir( oscmd(f"cp -R -P {outputdir}/lib/{base} {dest_libdir}/panda3d/{base}") for base in os.listdir(outputdir + "/bin"): - if not base.startswith("deploy-stub"): + if base not in EXCLUDE_BINARIES: oscmd(f"cp -R -P {outputdir}/bin/{base} {dest_prefix}/bin/{base}") DeleteVCS(dest_prefix + "/share/panda3d") diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index 6bfad076c6d..a46684d7d06 100755 --- a/makepanda/makepackage.py +++ b/makepanda/makepackage.py @@ -125,6 +125,8 @@ fi """ +EXCLUDE_BINARIES = ["deploy-stub", "deploy-stubw", "run_tests"] + def MakeInstallerNSIS(version, file, title, installdir, compressor="lzma", **kwargs): outputdir = GetOutputDir() @@ -404,7 +406,7 @@ def MakeInstallerLinux(version, debversion=None, rpmversion=None, rpmrelease=1, # Add the binaries in /usr/bin explicitly to the spec file for base in os.listdir(outputdir + "/bin"): - if not base.startswith("deploy-stub"): + if base not in EXCLUDE_BINARIES: txt += "/usr/bin/%s\n" % (base) # Write out the spec file. @@ -470,7 +472,7 @@ def MakeInstallerOSX(version, python_versions=[], installdir=None, **kwargs): oscmd("install -m 0644 doc/man/*.1 dstroot/tools/usr/local/share/man/man1/") for base in os.listdir(outputdir + "/bin"): - if not base.startswith("deploy-stub"): + if base not in EXCLUDE_BINARIES: binname = ("dstroot/tools/%s/bin/" % installdir) + base # OSX needs the -R argument to copy symbolic links correctly, it doesn't have -d. How weird. oscmd("cp -R " + outputdir + "/bin/" + base + " " + binname) @@ -795,7 +797,7 @@ def MakeInstallerFreeBSD(version, python_versions=[], **kwargs): oscmd("rm -f %s/tmp/python_dep" % outputdir) if "PYTHONVERSION" in SDK: - pyver_nodot = SDK["PYTHONVERSION"][6:].rstrip('dmu').replace('.', '') + pyver_nodot = SDK["PYTHONVERSION"][6:].rstrip('dmut').replace('.', '') else: pyver_nodot = "%d%d" % (sys.version_info[:2]) @@ -864,7 +866,7 @@ def copy_library(source, base): shutil.copy(source, target) # Walk through the library dependencies. - handle = subprocess.Popen(['readelf', '--dynamic', target], stdout=subprocess.PIPE) + handle = subprocess.Popen(['llvm-readelf', '--dynamic', target], stdout=subprocess.PIPE) for line in handle.communicate()[0].splitlines(): # The line will look something like: # 0x0000000000000001 (NEEDED) Shared library: [libpanda.so] diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 1dcc84af556..33c581f8c27 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -86,7 +86,7 @@ "ODE", "BULLET", "PANDAPHYSICS", # Physics "SPEEDTREE", # SpeedTree "ZLIB", "PNG", "JPEG", "TIFF", "OPENEXR", "SQUISH", # 2D Formats support - ] + MAYAVERSIONS + MAXVERSIONS + [ "FCOLLADA", "ASSIMP", "EGG", # 3D Formats support + "FCOLLADA", "ASSIMP", "EGG", # 3D Formats support "FREETYPE", "HARFBUZZ", # Text rendering "VRPN", "OPENSSL", # Transport "FFTW", # Algorithm helpers @@ -183,7 +183,7 @@ def usage(problem): print(" --everything (enable every third-party lib)") print(" --directx-sdk=X (specify version of DirectX SDK to use: jun2010, aug2009)") print(" --windows-sdk=X (specify Windows SDK version, eg. 7.1, 8.1, 10 or 11. Default is 8.1)") - print(" --msvc-version=X (specify Visual C++ version, eg. 10, 11, 12, 14, 14.1, 14.2, 14.3. Default is 14)") + print(" --msvc-version=X (specify Visual C++ version, eg. 14.1, 14.2, 14.3. Default is 14.1)") print(" --use-icl (experimental setting to use an intel compiler instead of MSVC on Windows)") print("") print("The simplest way to compile panda is to just type:") @@ -203,6 +203,13 @@ def parseopts(args): removedopts = [ "use-touchinput", "no-touchinput", "no-awesomium", "no-directscripts", "no-carbon", "no-physx", "no-rocket", "host", "osxtarget=", + "no-max6", "no-max7", "no-max8", "no-max9", "no-max2009", + "no-max2010", "no-max2011", "no-max2012", "no-max2013", "no-max2014", + "no-maya6", "no-maya65", "no-maya7", "no-maya8", "no-maya85", + "no-maya2008", "no-maya2009", "no-maya2010", "no-maya2011", + "no-maya2012", "no-maya2013", "no-maya20135", "no-maya2014", + "no-maya2015", "no-maya2016", "no-maya20165", "no-maya2017", + "no-maya2018", "no-maya2019", "no-maya2020", "no-maya2022", ] # All recognized options. @@ -288,11 +295,11 @@ def parseopts(args): break elif option == "--" + pkg.lower() + "-incdir": PkgSetCustomLocation(pkg) - IncDirectory(pkg, value) + IncDirectory(pkg, os.path.expanduser(value)) break elif option == "--" + pkg.lower() + "-libdir": PkgSetCustomLocation(pkg) - LibDirectory(pkg, value) + LibDirectory(pkg, os.path.expanduser(value)) break if (option == "--everything" or option == "--archipelago" @@ -333,8 +340,8 @@ def parseopts(args): if GetTarget() == 'windows': if not MSVC_VERSION: - print("No MSVC version specified. Defaulting to 14 (Visual Studio 2015).") - MSVC_VERSION = (14, 0) + print("No MSVC version specified. Defaulting to 14.1 (Visual Studio 2017).") + MSVC_VERSION = (14, 1) else: try: MSVC_VERSION = tuple(int(d) for d in MSVC_VERSION.split('.'))[:2] @@ -343,12 +350,10 @@ def parseopts(args): except: usage("Invalid setting for --msvc-version") - if MSVC_VERSION < (14, 0): + if MSVC_VERSION < (14, 1): warn_prefix = "%sERROR:%s " % (GetColor("red"), GetColor()) print("=========================================================================") - print(warn_prefix + "Support for MSVC versions before 2015 has been discontinued.") - print(warn_prefix + "For more information, or any questions, please visit:") - print(warn_prefix + " https://github.com/panda3d/panda3d/issues/288") + print(warn_prefix + "Support for MSVC versions before 2017 has been discontinued.") print("=========================================================================") sys.stdout.flush() time.sleep(1.0) @@ -447,6 +452,8 @@ def parseopts(args): if arch_tag == 'arm64': PLATFORM = 'macosx-11.0-' + arch_tag + elif sys.version_info >= (3, 13): + PLATFORM = 'macosx-10.13-' + arch_tag else: PLATFORM = 'macosx-10.9-' + arch_tag @@ -509,6 +516,8 @@ def parseopts(args): else: if target_arch == 'amd64': target_arch = 'x86_64' + if target_arch == 'arm' and target == 'android': + target_arch = 'armv7a' PLATFORM = '{0}-{1}'.format(target, target_arch) @@ -551,8 +560,6 @@ def parseopts(args): MakeBuildTree() SdkLocateDirectX(STRDXSDKVERSION) -SdkLocateMaya() -SdkLocateMax() SdkLocateMacOSX(OSX_ARCHS) SdkLocatePython(False) SdkLocateWindows(WINDOWS_SDK) @@ -560,8 +567,6 @@ def parseopts(args): SdkLocateAndroid() SdkAutoDisableDirectX() -SdkAutoDisableMaya() -SdkAutoDisableMax() SdkAutoDisableSpeedTree() if not PkgSkip("PYTHON") and SDK["PYTHONVERSION"] == "python2.7": @@ -588,6 +593,11 @@ def parseopts(args): else: COMPILER = "GCC" +# Ensure we've pip-installed interrogate if we need it before setting +# PYTHONHOME, etc. +if not PkgSkip("PYTHON"): + GetInterrogate() + SetupBuildEnvironment(COMPILER) ######################################################################## @@ -612,20 +622,7 @@ def parseopts(args): SmartPkgEnable("EIGEN", "eigen3", (), ("Eigen/Dense",), target_pkg = 'ALWAYS') for pkg in PkgListGet(): if not PkgSkip(pkg): - if (pkg[:4]=="MAYA"): - IncDirectory(pkg, SDK[pkg] + "/include") - DefSymbol(pkg, "MAYAVERSION", pkg) - DefSymbol(pkg, "MLIBRARY_DONTUSE_MFC_MANIFEST", "") - elif (pkg[:3]=="MAX"): - IncDirectory(pkg, SDK[pkg] + "/include") - IncDirectory(pkg, SDK[pkg] + "/include/CS") - IncDirectory(pkg, SDK[pkg+"CS"] + "/include") - IncDirectory(pkg, SDK[pkg+"CS"] + "/include/CS") - DefSymbol(pkg, "MAX", pkg) - if (int(pkg[3:]) >= 2013): - DefSymbol(pkg, "UNICODE", "") - DefSymbol(pkg, "_UNICODE", "") - elif (pkg[:2]=="DX"): + if (pkg[:2]=="DX"): IncDirectory(pkg, SDK[pkg] + "/include") elif GetThirdpartyDir() is not None: IncDirectory(pkg, GetThirdpartyDir() + pkg.lower() + "/include") @@ -801,21 +798,6 @@ def parseopts(args): if not os.path.isfile(path): path = GetThirdpartyDir() + "opus/lib/{0}.lib".format(lib) LibName("OPUS", path) - for pkg in MAYAVERSIONS: - if not PkgSkip(pkg): - LibName(pkg, '"' + SDK[pkg] + '/lib/Foundation.lib"') - LibName(pkg, '"' + SDK[pkg] + '/lib/OpenMaya.lib"') - LibName(pkg, '"' + SDK[pkg] + '/lib/OpenMayaAnim.lib"') - LibName(pkg, '"' + SDK[pkg] + '/lib/OpenMayaUI.lib"') - for pkg in MAXVERSIONS: - if not PkgSkip(pkg): - LibName(pkg, SDK[pkg] + '/lib/core.lib') - LibName(pkg, SDK[pkg] + '/lib/edmodel.lib') - LibName(pkg, SDK[pkg] + '/lib/gfx.lib') - LibName(pkg, SDK[pkg] + '/lib/geom.lib') - LibName(pkg, SDK[pkg] + '/lib/mesh.lib') - LibName(pkg, SDK[pkg] + '/lib/maxutil.lib') - LibName(pkg, SDK[pkg] + '/lib/paramblk2.lib') if not PkgSkip("SPEEDTREE"): if GetTargetArch() == 'x64': @@ -1077,12 +1059,14 @@ def parseopts(args): # Python may have been compiled with these requirements. # Is there a cleaner way to check this? LinkFlag("PYTHON", "-s USE_BZIP2=1 -s USE_SQLITE3=1") - if not PkgHasCustomLocation("PYTHON"): + if PkgHasCustomLocation("PYTHON"): + python_libdir = FindLibDirectory("PYTHON") + else: python_libdir = GetThirdpartyDir() + "python/lib" - if os.path.isfile(python_libdir + "/libmpdec.a"): - LibName("PYTHON", python_libdir + "/libmpdec.a") - if os.path.isfile(python_libdir + "/libexpat.a"): - LibName("PYTHON", python_libdir + "/libexpat.a") + + for lib in "libmpdec.a", "libexpat.a", "libHacl_Hash_SHA2.a": + if os.path.isfile(python_libdir + "/" + lib): + LibName("PYTHON", python_libdir + "/" + lib) if GetTarget() == "linux": LibName("PYTHON", "-lutil") @@ -1117,28 +1101,6 @@ def parseopts(args): elif not PkgSkip("X11"): LibDirectory("ALWAYS", "/usr/X11R6/lib") - for pkg in MAYAVERSIONS: - if (PkgSkip(pkg)==0 and (pkg in SDK)): - if (GetHost() == "darwin"): - # Sheesh, Autodesk really can't make up their mind - # regarding the location of the Maya devkit on macOS. - if (os.path.isdir(SDK[pkg] + "/Maya.app/Contents/lib")): - LibDirectory(pkg, SDK[pkg] + "/Maya.app/Contents/lib") - if (os.path.isdir(SDK[pkg] + "/Maya.app/Contents/MacOS")): - LibDirectory(pkg, SDK[pkg] + "/Maya.app/Contents/MacOS") - if (os.path.isdir(SDK[pkg] + "/lib")): - LibDirectory(pkg, SDK[pkg] + "/lib") - if (os.path.isdir(SDK[pkg] + "/Maya.app/Contents/include/maya")): - IncDirectory(pkg, SDK[pkg] + "/Maya.app/Contents/include") - if (os.path.isdir(SDK[pkg] + "/devkit/include/maya")): - IncDirectory(pkg, SDK[pkg] + "/devkit/include") - if (os.path.isdir(SDK[pkg] + "/include/maya")): - IncDirectory(pkg, SDK[pkg] + "/include") - else: - LibDirectory(pkg, SDK[pkg] + "/lib") - IncDirectory(pkg, SDK[pkg] + "/include") - DefSymbol(pkg, "MAYAVERSION", pkg) - if GetTarget() == 'darwin': LibName("ALWAYS", "-framework AppKit") LibName("IOKIT", "-framework IOKit") @@ -1166,40 +1128,6 @@ def parseopts(args): LibName("JNIGRAPHICS", '-ljnigraphics') LibName("OPENSLES", '-lOpenSLES') - for pkg in MAYAVERSIONS: - if (PkgSkip(pkg)==0 and (pkg in SDK)): - if GetTarget() == 'darwin': - LibName(pkg, "-Wl,-rpath,/Applications/Autodesk/" + pkg.lower() + "/Maya.app/Contents/MacOS") - else: - LibName(pkg, "-Wl,-rpath," + SDK[pkg] + "/lib") - LibName(pkg, "-lOpenMaya") - LibName(pkg, "-lOpenMayaAnim") - LibName(pkg, "-lOpenMayaUI") - LibName(pkg, "-lAnimSlice") - LibName(pkg, "-lDeformSlice") - LibName(pkg, "-lModifiers") - LibName(pkg, "-lDynSlice") - LibName(pkg, "-lKinSlice") - LibName(pkg, "-lModelSlice") - LibName(pkg, "-lNurbsSlice") - LibName(pkg, "-lPolySlice") - LibName(pkg, "-lProjectSlice") - LibName(pkg, "-lImage") - LibName(pkg, "-lShared") - LibName(pkg, "-lTranslators") - LibName(pkg, "-lDataModel") - LibName(pkg, "-lRenderModel") - LibName(pkg, "-lNurbsEngine") - LibName(pkg, "-lDependEngine") - LibName(pkg, "-lCommandEngine") - LibName(pkg, "-lFoundation") - if pkg not in ("MAYA2020", "MAYA2022"): - LibName(pkg, "-lIMFbase") - if GetTarget() != 'darwin': - LibName(pkg, "-lOpenMayalib") - else: - LibName(pkg, "-dylib_file /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib") - DefSymbol("WITHINPANDA", "WITHIN_PANDA", "1") if GetLinkAllStatic() or GetTarget() == 'emscripten': DefSymbol("ALWAYS", "LINK_ALL_STATIC") @@ -1428,7 +1356,7 @@ def CompileCxx(obj,src,opts): if (COMPILER=="GCC"): if (src.endswith(".c")): cmd = GetCC() +' -fPIC -c -o ' + obj - else: cmd = GetCXX()+' -std=gnu++11 -ftemplate-depth-70 -fPIC -c -o ' + obj + else: cmd = GetCXX()+' -std=gnu++14 -ftemplate-depth-70 -fPIC -c -o ' + obj for (opt, dir) in INCDIRECTORIES: if (opt=="ALWAYS") or (opt in opts): cmd += ' -I' + BracketNameWithQuotes(dir) for (opt, dir) in FRAMEWORKDIRECTORIES: @@ -1479,10 +1407,10 @@ def CompileCxx(obj,src,opts): cmd += ' -gcc-toolchain ' + SDK["ANDROID_GCC_TOOLCHAIN"].replace('\\', '/') cmd += ' -ffunction-sections -funwind-tables' cmd += ' -target ' + SDK["ANDROID_TRIPLE"] - if arch == 'armv7a': + if arch in ('armv7a', 'arm'): cmd += ' -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16' - elif arch == 'arm': - cmd += ' -march=armv5te -mtune=xscale -msoft-float' + #elif arch == 'arm': + # cmd += ' -march=armv5te -mtune=xscale -msoft-float' elif arch == 'mips': cmd += ' -mips32' elif arch == 'mips64': @@ -1605,9 +1533,9 @@ def CompileBison(wobj, wsrc, opts): else: exit('Could not find bison!') else: - oscmd(bison + ' -y -d -o'+GetOutputDir()+'/tmp/'+ifile+'.c -p '+pre+' '+wsrc) - CopyFile(wdstc, GetOutputDir()+"/tmp/"+ifile+".c") - CopyFile(wdsth, GetOutputDir()+"/tmp/"+ifile+".h") + oscmd(bison + ' -y -d -o'+GetOutputDir()+'/tmp/'+ifile[:-4]+'.c -p '+pre+' '+wsrc) + CopyFile(wdstc, GetOutputDir()+"/tmp/"+ifile[:-4]+".c") + CopyFile(wdsth, GetOutputDir()+"/tmp/"+ifile[:-4]+".h") # Finally, compile the generated source file. CompileCxx(wobj, wdstc, opts + ["FLEX"]) @@ -1672,12 +1600,7 @@ def CompileIgate(woutd,wsrc,opts): ConditionalWriteFile(woutd, "") return - if not CrossCompiling(): - # If we're compiling for this platform, we can use the one we've built. - cmd = os.path.join(GetOutputDir(), 'bin', 'interrogate') - else: - # Assume that interrogate is on the PATH somewhere. - cmd = 'interrogate' + cmd = GetInterrogate() if GetVerbose(): cmd += ' -v' @@ -1756,17 +1679,15 @@ def CompileImod(wobj, wsrc, opts): CompileCxx(wobj, woutc, opts) return - if not CrossCompiling(): - # If we're compiling for this platform, we can use the one we've built. - cmd = os.path.join(GetOutputDir(), 'bin', 'interrogate_module') - else: - # Assume that interrogate_module is on the PATH somewhere. - cmd = 'interrogate_module' + cmd = GetInterrogateModule() cmd += ' -oc ' + woutc + ' -module ' + module + ' -library ' + library + ' -python-native' importmod = GetValueOption(opts, "IMPORT:") if importmod: cmd += ' -import ' + importmod + initfunc = GetValueOption(opts, "INIT:") + if initfunc: + cmd += ' -init ' + initfunc for x in wsrc: cmd += ' ' + BracketNameWithQuotes(x) oscmd(cmd) CompileCxx(wobj,woutc,opts) @@ -1850,7 +1771,7 @@ def CompileLink(dll, obj, opts): if "PYTHON" not in opts: pythonv = SDK["PYTHONVERSION"].replace('.', '') if optlevel <= 2: - cmd += ' /NOD:{}d.lib'.format(pythonv) + cmd += ' /NOD:{}_d.lib'.format(pythonv) else: cmd += ' /NOD:{}.lib'.format(pythonv) @@ -1997,6 +1918,8 @@ def CompileLink(dll, obj, opts): if tuple(OSX_ARCHS) == ('arm64',): cmd += " -mmacosx-version-min=11.0" + elif sys.version_info >= (3, 13) and 'PYTHON' in opts: + cmd += " -mmacosx-version-min=10.13" else: cmd += " -mmacosx-version-min=10.9" @@ -2013,18 +1936,21 @@ def CompileLink(dll, obj, opts): cmd += ' -gcc-toolchain ' + SDK["ANDROID_GCC_TOOLCHAIN"].replace('\\', '/') cmd += " -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now" cmd += ' -target ' + SDK["ANDROID_TRIPLE"] - if arch == 'armv7a': + if arch in ('armv7a', 'arm'): cmd += " -march=armv7-a -Wl,--fix-cortex-a8" elif arch == 'mips': cmd += ' -mips32' cmd += ' -lc -lm' elif GetTarget() == 'emscripten': - cmd += " -s WARN_ON_UNDEFINED_SYMBOLS=1" + cmd += " -s WARN_ON_UNDEFINED_SYMBOLS=1 -mbulk-memory" + if GetOrigExt(dll) == ".exe": - cmd += " --memory-init-file 0" cmd += " -s EXIT_RUNTIME=1" + if dll.endswith(".js") and "SUBSYSTEM:WINDOWS" not in opts: + cmd += " --pre-js dtool/src/dtoolutil/console_preamble.js" + else: cmd += " -pthread" if "SYSROOT" in SDK: @@ -2189,13 +2115,23 @@ def CompileJava(target, src, opts): if GetHost() == 'android': cmd = "ecj " else: - cmd = "javac -bootclasspath " + BracketNameWithQuotes(SDK["ANDROID_JAR"]) + " " + cmd = "javac " + home = os.environ.get('JAVA_HOME') + if home: + javac_path = os.path.join(home, 'bin', 'javac') + if GetHost() == 'windows': + javac_path += '.exe' + if os.path.isfile(javac_path): + cmd = BracketNameWithQuotes(javac_path) + " " + + cmd += "-Xlint:deprecation " optlevel = GetOptimizeOption(opts) if optlevel >= 4: cmd += "-debug:none " - cmd += "-cp " + GetOutputDir() + "/classes " + classpath = BracketNameWithQuotes(SDK["ANDROID_JAR"] + ":" + GetOutputDir() + "/classes") + cmd += "-cp " + classpath + " " cmd += "-d " + GetOutputDir() + "/classes " cmd += BracketNameWithQuotes(src) oscmd(cmd) @@ -2456,7 +2392,6 @@ def CompileAnything(target, inputs, opts, progress = None): ("PYTHON_FRAMEWORK", 'UNDEF', 'UNDEF'), ("COMPILE_IN_DEFAULT_FONT", '1', '1'), ("STDFLOAT_DOUBLE", 'UNDEF', 'UNDEF'), - ("HAVE_MAYA", '1', '1'), ("REPORT_OPENSSL_ERRORS", '1', '1'), ("USE_PANDAFILESTREAM", '1', '1'), ("USE_DELETED_CHAIN", '1', '1'), @@ -2635,7 +2570,8 @@ def WriteConfigSettings(): dtool_config["PYTHON_FRAMEWORK"] = 'Python' dtool_config["PHAVE_MALLOC_H"] = 'UNDEF' dtool_config["PHAVE_SYS_MALLOC_H"] = '1' - dtool_config["HAVE_OPENAL_FRAMEWORK"] = '1' + if not os.path.isdir(GetThirdpartyDir() + "openal"): + dtool_config["HAVE_OPENAL_FRAMEWORK"] = '1' dtool_config["HAVE_X11"] = 'UNDEF' # We might have X11, but we don't need it. dtool_config["IS_LINUX"] = 'UNDEF' dtool_config["HAVE_VIDEO4LINUX"] = 'UNDEF' @@ -2901,7 +2837,8 @@ def CreatePandaVersionFiles(): 'direct.py', 'direct.pyc', 'direct.pyo', '_direct.pyd', '_direct.so', 'dtoolconfig.pyd', 'dtoolconfig.so', - 'net.pyd', 'net.so'] + 'net.pyd', 'net.so', + 'interrogatedb.pyd', 'interrogatedb.so'] for basename in del_files: path = os.path.join(GetOutputDir(), 'panda3d', basename) @@ -3038,7 +2975,7 @@ def get_config_express(): # This is just some basic stuff since setuptools just needs this file to # exist, otherwise it will not read the entry_points.txt file. Maybe we will # eventually want to merge this with the metadata generator in makewheel.py. -METADATA = """Metadata-Version: 2.0 +METADATA = """Metadata-Version: 2.1 Name: Panda3D Version: {version} License: BSD @@ -3332,15 +3269,9 @@ def get_config_express(): CopyFile(GetOutputDir()+"/", "doc/LICENSE") CopyFile(GetOutputDir()+"/", "doc/ReleaseNotes") -if not PkgSkip("PANDATOOL"): - CopyAllFiles(GetOutputDir()+"/plugins/", "pandatool/src/scripts/", ".mel") - CopyAllFiles(GetOutputDir()+"/plugins/", "pandatool/src/scripts/", ".ms") - if not PkgSkip("PYTHON") and os.path.isdir(GetThirdpartyBase() + "/Pmw"): CopyTree(GetOutputDir() + "/Pmw", GetThirdpartyBase() + "/Pmw", exclude=["Pmw_1_3", "Pmw_1_3_3"]) -ConditionalWriteFile(GetOutputDir()+'/include/ctl3d.h', '/* dummy file to make MAX happy */') - # Since Eigen is included by all sorts of core headers, as a convenience # to C++ users on Win and Mac, we include it in the Panda include directory. if not PkgSkip("EIGEN") and GetTarget() in ("windows", "darwin") and GetThirdpartyDir(): @@ -3365,13 +3296,10 @@ def get_config_express(): CopyAllHeaders('dtool/src/dtoolutil', skip=["pandaVersion.h", "checkPandaVersion.h"]) CopyFile(GetOutputDir()+'/include/','dtool/src/dtoolutil/vector_src.cxx') CopyAllHeaders('dtool/metalibs/dtool') -CopyAllHeaders('dtool/src/cppparser') CopyAllHeaders('dtool/src/prc', skip=["prc_parameters.h"]) CopyAllHeaders('dtool/src/dconfig') CopyAllHeaders('dtool/src/interrogatedb') CopyAllHeaders('dtool/metalibs/dtoolconfig') -CopyAllHeaders('dtool/src/interrogate') -CopyAllHeaders('dtool/src/test_interrogate') CopyAllHeaders('panda/src/putil') CopyAllHeaders('panda/src/pandabase') CopyAllHeaders('panda/src/express') @@ -3511,10 +3439,6 @@ def get_config_express(): CopyAllHeaders('pandatool/src/lwo') CopyAllHeaders('pandatool/src/lwoegg') CopyAllHeaders('pandatool/src/lwoprogs') - CopyAllHeaders('pandatool/src/maya') - CopyAllHeaders('pandatool/src/mayaegg') - CopyAllHeaders('pandatool/src/maxegg') - CopyAllHeaders('pandatool/src/maxprogs') CopyAllHeaders('pandatool/src/objegg') CopyAllHeaders('pandatool/src/objprogs') CopyAllHeaders('pandatool/src/vrml') @@ -3614,20 +3538,6 @@ def get_config_express(): TargetAdd('libp3dtool.dll', input='p3dtoolbase_lookup3.obj') TargetAdd('libp3dtool.dll', opts=['ADVAPI','WINSHELL','WINKERNEL','MIMALLOC']) -# -# DIRECTORY: dtool/src/cppparser/ -# - -OPTS=['DIR:dtool/src/cppparser', 'BISONPREFIX_cppyy'] -CreateFile(GetOutputDir()+"/include/cppBison.h") -TargetAdd('p3cppParser_cppBison.obj', opts=OPTS, input='cppBison.yxx') -TargetAdd('cppBison.h', input='p3cppParser_cppBison.obj', opts=['DEPENDENCYONLY']) -TargetAdd('p3cppParser_composite1.obj', opts=OPTS, input='p3cppParser_composite1.cxx') -TargetAdd('p3cppParser_composite2.obj', opts=OPTS, input='p3cppParser_composite2.cxx') -TargetAdd('libp3cppParser.ilb', input='p3cppParser_composite1.obj') -TargetAdd('libp3cppParser.ilb', input='p3cppParser_composite2.obj') -TargetAdd('libp3cppParser.ilb', input='p3cppParser_cppBison.obj') - # # DIRECTORY: dtool/src/prc/ # @@ -3648,63 +3558,6 @@ def get_config_express(): TargetAdd('libp3dtoolconfig.dll', input='libp3dtool.dll') TargetAdd('libp3dtoolconfig.dll', opts=['ADVAPI', 'OPENSSL', 'WINGDI', 'WINUSER']) -# -# DIRECTORY: dtool/src/interrogatedb/ -# - -OPTS=['DIR:dtool/src/interrogatedb', 'BUILDING:INTERROGATEDB'] -TargetAdd('p3interrogatedb_composite1.obj', opts=OPTS, input='p3interrogatedb_composite1.cxx') -TargetAdd('p3interrogatedb_composite2.obj', opts=OPTS, input='p3interrogatedb_composite2.cxx') -TargetAdd('libp3interrogatedb.dll', input='p3interrogatedb_composite1.obj') -TargetAdd('libp3interrogatedb.dll', input='p3interrogatedb_composite2.obj') -TargetAdd('libp3interrogatedb.dll', input='libp3dtool.dll') -TargetAdd('libp3interrogatedb.dll', input='libp3dtoolconfig.dll') - -# This used to be called dtoolconfig.pyd, but it just contains the interrogatedb -# stuff, so it has been renamed appropriately. -OPTS=['DIR:dtool/metalibs/dtoolconfig'] -PyTargetAdd('interrogatedb_pydtool.obj', opts=OPTS, input="pydtool.cxx") -PyTargetAdd('interrogatedb.pyd', input='interrogatedb_pydtool.obj') -PyTargetAdd('interrogatedb.pyd', input='libp3dtool.dll') -PyTargetAdd('interrogatedb.pyd', input='libp3dtoolconfig.dll') -PyTargetAdd('interrogatedb.pyd', input='libp3interrogatedb.dll') - -# -# DIRECTORY: dtool/src/interrogate/ -# - -OPTS=['DIR:dtool/src/interrogate', 'DIR:dtool/src/cppparser', 'DIR:dtool/src/interrogatedb'] -TargetAdd('interrogate_composite1.obj', opts=OPTS, input='interrogate_composite1.cxx') -TargetAdd('interrogate_composite2.obj', opts=OPTS, input='interrogate_composite2.cxx') -TargetAdd('interrogate.exe', input='interrogate_composite1.obj') -TargetAdd('interrogate.exe', input='interrogate_composite2.obj') -TargetAdd('interrogate.exe', input='libp3cppParser.ilb') -TargetAdd('interrogate.exe', input=COMMON_DTOOL_LIBS) -TargetAdd('interrogate.exe', input='libp3interrogatedb.dll') -TargetAdd('interrogate.exe', opts=['ADVAPI', 'WINSHELL', 'WINGDI', 'WINUSER']) - -preamble = WriteEmbeddedStringFile('interrogate_preamble_python_native', inputs=[ - 'dtool/src/interrogatedb/py_panda.cxx', - 'dtool/src/interrogatedb/py_compat.cxx', - 'dtool/src/interrogatedb/py_wrappers.cxx', - 'dtool/src/interrogatedb/dtool_super_base.cxx', -]) -TargetAdd('interrogate_module_preamble_python_native.obj', opts=OPTS, input=preamble) -TargetAdd('interrogate_module_interrogate_module.obj', opts=OPTS, input='interrogate_module.cxx') -TargetAdd('interrogate_module.exe', input='interrogate_module_interrogate_module.obj') -TargetAdd('interrogate_module.exe', input='interrogate_module_preamble_python_native.obj') -TargetAdd('interrogate_module.exe', input='libp3cppParser.ilb') -TargetAdd('interrogate_module.exe', input=COMMON_DTOOL_LIBS) -TargetAdd('interrogate_module.exe', input='libp3interrogatedb.dll') -TargetAdd('interrogate_module.exe', opts=['ADVAPI', 'WINSHELL', 'WINGDI', 'WINUSER']) - -TargetAdd('parse_file_parse_file.obj', opts=OPTS, input='parse_file.cxx') -TargetAdd('parse_file.exe', input='parse_file_parse_file.obj') -TargetAdd('parse_file.exe', input='libp3cppParser.ilb') -TargetAdd('parse_file.exe', input=COMMON_DTOOL_LIBS) -TargetAdd('parse_file.exe', input='libp3interrogatedb.dll') -TargetAdd('parse_file.exe', opts=['ADVAPI', 'WINSHELL', 'WINGDI', 'WINUSER']) - # # DIRECTORY: dtool/src/prckeys/ # @@ -3716,17 +3569,6 @@ def get_config_express(): TargetAdd('make-prc-key.exe', input=COMMON_DTOOL_LIBS) TargetAdd('make-prc-key.exe', opts=['ADVAPI', 'OPENSSL', 'WINSHELL', 'WINGDI', 'WINUSER']) -# -# DIRECTORY: dtool/src/test_interrogate/ -# - -OPTS=['DIR:dtool/src/test_interrogate'] -TargetAdd('test_interrogate_test_interrogate.obj', opts=OPTS, input='test_interrogate.cxx') -TargetAdd('test_interrogate.exe', input='test_interrogate_test_interrogate.obj') -TargetAdd('test_interrogate.exe', input='libp3interrogatedb.dll') -TargetAdd('test_interrogate.exe', input=COMMON_DTOOL_LIBS) -TargetAdd('test_interrogate.exe', opts=['ADVAPI', 'WINSHELL', 'WINGDI', 'WINUSER']) - # # DIRECTORY: dtool/src/dtoolbase/ # @@ -4230,7 +4072,9 @@ def get_config_express(): # DIRECTORY: panda/src/pnmimagetypes/ # -OPTS=['DIR:panda/src/pnmimagetypes', 'DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'PNG', 'ZLIB', 'JPEG', 'TIFF', 'OPENEXR', 'EXCEPTIONS'] +OPTS=['DIR:panda/src/pnmimagetypes', 'DIR:panda/src/pnmimage', 'BUILDING:PANDA', 'PNG', 'ZLIB', 'JPEG', 'TIFF', 'OPENEXR'] +if not PkgSkip('OPENEXR') and GetTarget() != 'emscripten': + OPTS.append('EXCEPTIONS') TargetAdd('p3pnmimagetypes_composite1.obj', opts=OPTS, input='p3pnmimagetypes_composite1.cxx') TargetAdd('p3pnmimagetypes_composite2.obj', opts=OPTS, input='p3pnmimagetypes_composite2.cxx') @@ -4374,7 +4218,7 @@ def get_config_express(): if PkgSkip("FREETYPE")==0: PyTargetAdd('core_module.obj', input='libp3pnmtext.in') -PyTargetAdd('core_module.obj', opts=['IMOD:panda3d.core', 'ILIB:core']) +PyTargetAdd('core_module.obj', opts=['IMOD:panda3d.core', 'ILIB:core', 'INIT:pyenv_init']) PyTargetAdd('core.pyd', input='libp3dtoolbase_igate.obj') PyTargetAdd('core.pyd', input='p3dtoolbase_typeHandle_ext.obj') @@ -4432,7 +4276,6 @@ def get_config_express(): PyTargetAdd('core.pyd', input='p3collide_ext_composite.obj') PyTargetAdd('core.pyd', input='core_module.obj') -PyTargetAdd('core.pyd', input='libp3interrogatedb.dll') PyTargetAdd('core.pyd', input=COMMON_PANDA_LIBS) PyTargetAdd('core.pyd', opts=['WINSOCK2']) @@ -4472,7 +4315,6 @@ def get_config_express(): PyTargetAdd('vision.pyd', input='vision_module.obj') PyTargetAdd('vision.pyd', input='libp3vision_igate.obj') PyTargetAdd('vision.pyd', input='libp3vision.dll') - PyTargetAdd('vision.pyd', input='libp3interrogatedb.dll') PyTargetAdd('vision.pyd', input=COMMON_PANDA_LIBS) # @@ -4504,7 +4346,6 @@ def get_config_express(): PyTargetAdd('skel.pyd', input='skel_module.obj') PyTargetAdd('skel.pyd', input='libp3skel_igate.obj') PyTargetAdd('skel.pyd', input='libpandaskel.dll') - PyTargetAdd('skel.pyd', input='libp3interrogatedb.dll') PyTargetAdd('skel.pyd', input=COMMON_PANDA_LIBS) # @@ -4541,7 +4382,6 @@ def get_config_express(): PyTargetAdd('fx.pyd', input='fx_module.obj') PyTargetAdd('fx.pyd', input='libp3distort_igate.obj') PyTargetAdd('fx.pyd', input='libpandafx.dll') - PyTargetAdd('fx.pyd', input='libp3interrogatedb.dll') PyTargetAdd('fx.pyd', input=COMMON_PANDA_LIBS) # @@ -4567,7 +4407,6 @@ def get_config_express(): PyTargetAdd('vrpn.pyd', input='vrpn_module.obj') PyTargetAdd('vrpn.pyd', input='libp3vrpn_igate.obj') PyTargetAdd('vrpn.pyd', input='libp3vrpn.dll') - PyTargetAdd('vrpn.pyd', input='libp3interrogatedb.dll') PyTargetAdd('vrpn.pyd', input=COMMON_PANDA_LIBS) # @@ -4786,7 +4625,6 @@ def get_config_express(): PyTargetAdd('egg.pyd', input='libp3egg_igate.obj') PyTargetAdd('egg.pyd', input='libp3egg2pg_igate.obj') PyTargetAdd('egg.pyd', input='libpandaegg.dll') - PyTargetAdd('egg.pyd', input='libp3interrogatedb.dll') PyTargetAdd('egg.pyd', input=COMMON_PANDA_LIBS) # @@ -4986,7 +4824,6 @@ def get_config_express(): PyTargetAdd('ode.pyd', input='libpandaode_igate.obj') PyTargetAdd('ode.pyd', input='p3ode_ext_composite.obj') PyTargetAdd('ode.pyd', input='libpandaode.dll') - PyTargetAdd('ode.pyd', input='libp3interrogatedb.dll') PyTargetAdd('ode.pyd', input=COMMON_PANDA_LIBS) PyTargetAdd('ode.pyd', opts=['WINUSER', 'ODE']) @@ -5022,7 +4859,6 @@ def get_config_express(): PyTargetAdd('bullet.pyd', input='bullet_module.obj') PyTargetAdd('bullet.pyd', input='libpandabullet_igate.obj') PyTargetAdd('bullet.pyd', input='libpandabullet.dll') - PyTargetAdd('bullet.pyd', input='libp3interrogatedb.dll') PyTargetAdd('bullet.pyd', input=COMMON_PANDA_LIBS) PyTargetAdd('bullet.pyd', opts=['WINUSER', 'BULLET']) @@ -5088,7 +4924,6 @@ def get_config_express(): if not PkgSkip("PANDAPARTICLESYSTEM"): PyTargetAdd('physics.pyd', input='libp3particlesystem_igate.obj') PyTargetAdd('physics.pyd', input='libpandaphysics.dll') - PyTargetAdd('physics.pyd', input='libp3interrogatedb.dll') PyTargetAdd('physics.pyd', input=COMMON_PANDA_LIBS) # @@ -5143,11 +4978,13 @@ def get_config_express(): TargetAdd('org/panda3d/android/NativeIStream.class', opts=OPTS, input='NativeIStream.java') TargetAdd('org/panda3d/android/NativeOStream.class', opts=OPTS, input='NativeOStream.java') TargetAdd('org/panda3d/android/PandaActivity.class', opts=OPTS, input='PandaActivity.java') + TargetAdd('org/panda3d/android/PandaActivity$1.class', opts=OPTS+['DEPENDENCYONLY'], input='PandaActivity.java') TargetAdd('org/panda3d/android/PythonActivity.class', opts=OPTS, input='PythonActivity.java') TargetAdd('classes.dex', input='org/panda3d/android/NativeIStream.class') TargetAdd('classes.dex', input='org/panda3d/android/NativeOStream.class') TargetAdd('classes.dex', input='org/panda3d/android/PandaActivity.class') + TargetAdd('classes.dex', input='org/panda3d/android/PandaActivity$1.class') TargetAdd('classes.dex', input='org/panda3d/android/PythonActivity.class') TargetAdd('p3android_composite1.obj', opts=OPTS, input='p3android_composite1.cxx') @@ -5450,7 +5287,6 @@ def get_config_express(): PyTargetAdd('direct.pyd', input='direct_module.obj') PyTargetAdd('direct.pyd', input='libp3direct.dll') - PyTargetAdd('direct.pyd', input='libp3interrogatedb.dll') PyTargetAdd('direct.pyd', input=COMMON_PANDA_LIBS) PyTargetAdd('direct.pyd', opts=['WINUSER', 'WINGDI', 'WINSOCK2']) @@ -5924,75 +5760,6 @@ def get_config_express(): TargetAdd('lwo2egg.exe', input=COMMON_EGG2X_LIBS) TargetAdd('lwo2egg.exe', opts=['ADVAPI']) -# -# DIRECTORY: pandatool/src/maya/ -# - -for VER in MAYAVERSIONS: - VNUM = VER[4:] - if PkgSkip(VER) or PkgSkip("PANDATOOL"): - continue - - OPTS=['DIR:pandatool/src/maya', VER] - TargetAdd('maya'+VNUM+'_composite1.obj', opts=OPTS, input='p3maya_composite1.cxx') - TargetAdd('libmaya'+VNUM+'.lib', input='maya'+VNUM+'_composite1.obj') - -# -# DIRECTORY: pandatool/src/mayaegg/ -# - -for VER in MAYAVERSIONS: - VNUM = VER[4:] - if PkgSkip(VER) or PkgSkip("PANDATOOL") or PkgSkip("EGG"): - continue - - OPTS=['DIR:pandatool/src/mayaegg', 'DIR:pandatool/src/maya', VER] - TargetAdd('mayaegg'+VNUM+'_loader.obj', opts=OPTS, input='mayaEggLoader.cxx') - TargetAdd('mayaegg'+VNUM+'_composite1.obj', opts=OPTS, input='p3mayaegg_composite1.cxx') - TargetAdd('libmayaegg'+VNUM+'.lib', input='mayaegg'+VNUM+'_loader.obj') - TargetAdd('libmayaegg'+VNUM+'.lib', input='mayaegg'+VNUM+'_composite1.obj') - -# -# DIRECTORY: pandatool/src/maxegg/ -# - -for VER in MAXVERSIONS: - VNUM = VER[3:] - if PkgSkip(VER) or PkgSkip("PANDATOOL") or PkgSkip("EGG"): - continue - - OPTS=['DIR:pandatool/src/maxegg', VER, "WINCOMCTL", "WINCOMDLG", "WINUSER", "MSFORSCOPE", "RTTI"] - TargetAdd('maxEgg'+VNUM+'.res', opts=OPTS, input='maxEgg.rc') - TargetAdd('maxegg'+VNUM+'_loader.obj', opts=OPTS, input='maxEggLoader.cxx') - TargetAdd('maxegg'+VNUM+'_composite1.obj', opts=OPTS, input='p3maxegg_composite1.cxx') - TargetAdd('maxegg'+VNUM+'.dlo', input='maxegg'+VNUM+'_composite1.obj') - TargetAdd('maxegg'+VNUM+'.dlo', input='maxEgg'+VNUM+'.res') - TargetAdd('maxegg'+VNUM+'.dlo', input='maxEgg.def', ipath=OPTS) - TargetAdd('maxegg'+VNUM+'.dlo', input=COMMON_EGG2X_LIBS) - TargetAdd('maxegg'+VNUM+'.dlo', opts=OPTS) - -# -# DIRECTORY: pandatool/src/maxprogs/ -# - -for VER in MAXVERSIONS: - VNUM = VER[3:] - if PkgSkip(VER) or PkgSkip("PANDATOOL") or PkgSkip("EGG"): - continue - - OPTS=['DIR:pandatool/src/maxprogs', VER, "WINCOMCTL", "WINCOMDLG", "WINUSER", "MSFORSCOPE", "RTTI"] - TargetAdd('maxImportRes.res', opts=OPTS, input='maxImportRes.rc') - TargetAdd('maxprogs'+VNUM+'_maxeggimport.obj', opts=OPTS, input='maxEggImport.cxx') - TargetAdd('maxeggimport'+VNUM+'.dle', input='maxegg'+VNUM+'_loader.obj') - TargetAdd('maxeggimport'+VNUM+'.dle', input='maxprogs'+VNUM+'_maxeggimport.obj') - TargetAdd('maxeggimport'+VNUM+'.dle', input='libpandaegg.dll') - TargetAdd('maxeggimport'+VNUM+'.dle', input='libpanda.dll') - TargetAdd('maxeggimport'+VNUM+'.dle', input='libpandaexpress.dll') - TargetAdd('maxeggimport'+VNUM+'.dle', input='maxImportRes.res') - TargetAdd('maxeggimport'+VNUM+'.dle', input='maxEggImport.def', ipath=OPTS) - TargetAdd('maxeggimport'+VNUM+'.dle', input=COMMON_DTOOL_LIBS) - TargetAdd('maxeggimport'+VNUM+'.dle', opts=OPTS) - # # DIRECTORY: pandatool/src/vrml/ # @@ -6197,127 +5964,6 @@ def get_config_express(): TargetAdd('x2egg.exe', input=COMMON_EGG2X_LIBS) TargetAdd('x2egg.exe', opts=['ADVAPI']) -# -# DIRECTORY: pandatool/src/mayaprogs/ -# - -MAYA_BUILT = False - -for VER in MAYAVERSIONS: - VNUM = VER[4:] - if PkgSkip(VER) or PkgSkip("PANDATOOL") or PkgSkip("EGG"): - continue - - if GetTarget() == 'darwin': - if int(VNUM) < 2009: - # No x86_64 support. - continue - if tuple(OSX_ARCHS) == ('arm64',): - # No arm64 support. - continue - ARCH_OPTS = ['NOARCH:ARM64'] - else: - ARCH_OPTS = [] - - MAYA_BUILT = True - - OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'BUILDING:MISC', VER] + ARCH_OPTS - TargetAdd('mayaeggimport'+VNUM+'_mayaeggimport.obj', opts=OPTS, input='mayaEggImport.cxx') - TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaegg'+VNUM+'_loader.obj') - TargetAdd('mayaeggimport'+VNUM+'.mll', input='mayaeggimport'+VNUM+'_mayaeggimport.obj') - TargetAdd('mayaeggimport'+VNUM+'.mll', input='libpandaegg.dll') - TargetAdd('mayaeggimport'+VNUM+'.mll', input=COMMON_PANDA_LIBS) - TargetAdd('mayaeggimport'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS) - - TargetAdd('mayaloader'+VNUM+'_config_mayaloader.obj', opts=OPTS, input='config_mayaloader.cxx') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='mayaloader'+VNUM+'_config_mayaloader.obj') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libmayaegg'+VNUM+'.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3ptloader.dll') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libmaya'+VNUM+'.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3fltegg.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3flt.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3lwoegg.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3lwo.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3dxfegg.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3dxf.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3objegg.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3vrmlegg.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3vrml.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3xfileegg.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3xfile.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3eggbase.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3progbase.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3converter.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libp3pandatoolbase.lib') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input='libpandaegg.dll') - TargetAdd('libp3mayaloader'+VNUM+'.dll', input=COMMON_PANDA_LIBS) - TargetAdd('libp3mayaloader'+VNUM+'.dll', opts=['ADVAPI', VER]+ARCH_OPTS) - - TargetAdd('mayapview'+VNUM+'_mayaPview.obj', opts=OPTS, input='mayaPview.cxx') - TargetAdd('libmayapview'+VNUM+'.mll', input='mayapview'+VNUM+'_mayaPview.obj') - TargetAdd('libmayapview'+VNUM+'.mll', input='libmayaegg'+VNUM+'.lib') - TargetAdd('libmayapview'+VNUM+'.mll', input='libmaya'+VNUM+'.lib') - TargetAdd('libmayapview'+VNUM+'.mll', input='libp3framework.dll') - TargetAdd('libmayapview'+VNUM+'.mll', input=COMMON_EGG2X_LIBS) - TargetAdd('libmayapview'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS) - - TargetAdd('mayaprogs'+VNUM+'_eggToMaya.obj', opts=OPTS, input='eggToMaya.cxx') - TargetAdd('mayaprogs'+VNUM+'_mayaToEgg.obj', opts=OPTS, input='mayaToEgg.cxx') - TargetAdd('mayaprogs_mayaConversionServer.obj', opts=OPTS, input='mayaConversionServer.cxx') - - TargetAdd('maya2egg'+VNUM+'_mayaToEggBin.obj', opts=OPTS, input='mayaToEggBin.cxx') - TargetAdd('maya2egg'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_eggToMaya.obj') - TargetAdd('maya2egg'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_mayaToEgg.obj') - TargetAdd('maya2egg'+VNUM+'_bin.exe', input='mayaprogs_mayaConversionServer.obj') - TargetAdd('maya2egg'+VNUM+'_bin.exe', input='maya2egg'+VNUM+'_mayaToEggBin.obj') - TargetAdd('maya2egg'+VNUM+'_bin.exe', input='libmayaegg'+VNUM+'.lib') - TargetAdd('maya2egg'+VNUM+'_bin.exe', input='libmaya'+VNUM+'.lib') - TargetAdd('maya2egg'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('maya2egg'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS) - - TargetAdd('egg2maya'+VNUM+'_eggToMayaBin.obj', opts=OPTS, input='eggToMayaBin.cxx') - TargetAdd('egg2maya'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_eggToMaya.obj') - TargetAdd('egg2maya'+VNUM+'_bin.exe', input='mayaprogs'+VNUM+'_mayaToEgg.obj') - TargetAdd('egg2maya'+VNUM+'_bin.exe', input='mayaprogs_mayaConversionServer.obj') - TargetAdd('egg2maya'+VNUM+'_bin.exe', input='egg2maya'+VNUM+'_eggToMayaBin.obj') - TargetAdd('egg2maya'+VNUM+'_bin.exe', input='libmayaegg'+VNUM+'.lib') - TargetAdd('egg2maya'+VNUM+'_bin.exe', input='libmaya'+VNUM+'.lib') - TargetAdd('egg2maya'+VNUM+'_bin.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('egg2maya'+VNUM+'_bin.exe', opts=['ADVAPI', VER]+ARCH_OPTS) - - TargetAdd('mayasavepview'+VNUM+'_mayaSavePview.obj', opts=OPTS, input='mayaSavePview.cxx') - TargetAdd('libmayasavepview'+VNUM+'.mll', input='mayasavepview'+VNUM+'_mayaSavePview.obj') - TargetAdd('libmayasavepview'+VNUM+'.mll', opts=['ADVAPI', VER]+ARCH_OPTS) - - TargetAdd('mayapath'+VNUM+'.obj', opts=OPTS, input='mayapath.cxx') - - TargetAdd('maya2egg'+VNUM+'.exe', input='mayapath'+VNUM+'.obj') - TargetAdd('maya2egg'+VNUM+'.exe', input='libpandaexpress.dll') - TargetAdd('maya2egg'+VNUM+'.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('maya2egg'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS) - - TargetAdd('egg2maya'+VNUM+'.exe', input='mayapath'+VNUM+'.obj') - TargetAdd('egg2maya'+VNUM+'.exe', input='libpandaexpress.dll') - TargetAdd('egg2maya'+VNUM+'.exe', input=COMMON_DTOOL_LIBS) - TargetAdd('egg2maya'+VNUM+'.exe', opts=['ADVAPI']+ARCH_OPTS) - -if MAYA_BUILT: - OPTS=['DIR:pandatool/src/mayaprogs', 'DIR:pandatool/src/maya', 'DIR:pandatool/src/mayaegg', 'BUILDING:MISC', 'NOARCH:ARM64'] - - TargetAdd('mayaprogs_mayaConversionClient.obj', opts=OPTS, input='mayaConversionClient.cxx') - - TargetAdd('maya2egg_mayaToEggClient.obj', opts=OPTS, input='mayaToEggClient.cxx') - TargetAdd('maya2egg_client.exe', input='mayaprogs_mayaConversionClient.obj') - TargetAdd('maya2egg_client.exe', input='maya2egg_mayaToEggClient.obj') - TargetAdd('maya2egg_client.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('maya2egg_client.exe', opts=['NOARCH:ARM64']) - - TargetAdd('egg2maya_eggToMayaClient.obj', opts=OPTS, input='eggToMayaClient.cxx') - TargetAdd('egg2maya_client.exe', input='mayaprogs_mayaConversionClient.obj') - TargetAdd('egg2maya_client.exe', input='egg2maya_eggToMayaClient.obj') - TargetAdd('egg2maya_client.exe', input=COMMON_EGG2X_LIBS) - TargetAdd('egg2maya_client.exe', opts=['NOARCH:ARM64']) - # # DIRECTORY: contrib/src/ai/ # @@ -6339,7 +5985,6 @@ def get_config_express(): PyTargetAdd('ai.pyd', input='ai_module.obj') PyTargetAdd('ai.pyd', input='libpandaai_igate.obj') PyTargetAdd('ai.pyd', input='libpandaai.dll') - PyTargetAdd('ai.pyd', input='libp3interrogatedb.dll') PyTargetAdd('ai.pyd', input=COMMON_PANDA_LIBS) # @@ -6360,7 +6005,6 @@ def get_config_express(): PyTargetAdd('_rplight.pyd', input='rplight_module.obj') PyTargetAdd('_rplight.pyd', input='libp3rplight_igate.obj') PyTargetAdd('_rplight.pyd', input='p3rplight_composite1.obj') - PyTargetAdd('_rplight.pyd', input='libp3interrogatedb.dll') PyTargetAdd('_rplight.pyd', input=COMMON_PANDA_LIBS) # @@ -6411,6 +6055,42 @@ def get_config_express(): PyTargetAdd('libdeploy-stubw.dll', input='libp3android.dll') PyTargetAdd('libdeploy-stubw.dll', opts=['DEPLOYSTUB', 'ANDROID']) +# +# Build the test runner for static builds +# +if GetLinkAllStatic(): + if GetTarget() == 'emscripten': + LinkFlag('RUN_TESTS_FLAGS', '-s NODERAWFS') + LinkFlag('RUN_TESTS_FLAGS', '-s ASSERTIONS=2') + LinkFlag('RUN_TESTS_FLAGS', '-s ALLOW_MEMORY_GROWTH') + LinkFlag('RUN_TESTS_FLAGS', '-s INITIAL_HEAP=585302016') + LinkFlag('RUN_TESTS_FLAGS', '-s STACK_SIZE=1048576') + LinkFlag('RUN_TESTS_FLAGS', '--minify 0') + + if not PkgSkip('DIRECT'): + DefSymbol('RUN_TESTS_FLAGS', 'HAVE_DIRECT') + if not PkgSkip('PANDAPHYSICS'): + DefSymbol('RUN_TESTS_FLAGS', 'HAVE_PHYSICS') + if not PkgSkip('EGG'): + DefSymbol('RUN_TESTS_FLAGS', 'HAVE_EGG') + if not PkgSkip('BULLET'): + DefSymbol('RUN_TESTS_FLAGS', 'HAVE_BULLET') + + OPTS=['DIR:tests', 'PYTHON', 'RUN_TESTS_FLAGS', 'SUBSYSTEM:CONSOLE'] + PyTargetAdd('run_tests-main.obj', opts=OPTS, input='main.c') + PyTargetAdd('run_tests.exe', input='run_tests-main.obj') + PyTargetAdd('run_tests.exe', input='core.pyd') + if not PkgSkip('DIRECT'): + PyTargetAdd('run_tests.exe', input='direct.pyd') + if not PkgSkip('PANDAPHYSICS'): + PyTargetAdd('run_tests.exe', input='physics.pyd') + if not PkgSkip('EGG'): + PyTargetAdd('run_tests.exe', input='egg.pyd') + if not PkgSkip('BULLET'): + PyTargetAdd('run_tests.exe', input='bullet.pyd') + PyTargetAdd('run_tests.exe', input=COMMON_PANDA_LIBS) + PyTargetAdd('run_tests.exe', opts=['PYTHON', 'BULLET', 'RUN_TESTS_FLAGS']) + # # Generate the models directory and samples directory # @@ -6572,8 +6252,16 @@ def RunDependencyQueue(tasklist): # Run the test suite. if RUNTESTS: - cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"].replace('\\', '/')) - cmdstr += " -B -m pytest tests" + if GetLinkAllStatic(): + runner = FindLocation("run_tests.exe", []) + if runner.endswith(".js"): + cmdstr = "node " + BracketNameWithQuotes(runner) + else: + cmdstr = BracketNameWithQuotes(runner) + else: + cmdstr = BracketNameWithQuotes(SDK["PYTHONEXEC"].replace('\\', '/')) + cmdstr += " -B -m pytest" + cmdstr += " tests" if GetVerbose(): cmdstr += " --verbose" oscmd(cmdstr) diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 4435c852471..e3a5fded366 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -93,54 +93,11 @@ ######################################################################## ## -## Maya and Max Version List (with registry keys) -## -######################################################################## - -MAYAVERSIONINFO = [("MAYA6", "6.0"), - ("MAYA65", "6.5"), - ("MAYA7", "7.0"), - ("MAYA8", "8.0"), - ("MAYA85", "8.5"), - ("MAYA2008","2008"), - ("MAYA2009","2009"), - ("MAYA2010","2010"), - ("MAYA2011","2011"), - ("MAYA2012","2012"), - ("MAYA2013","2013"), - ("MAYA20135","2013.5"), - ("MAYA2014","2014"), - ("MAYA2015","2015"), - ("MAYA2016","2016"), - ("MAYA20165","2016.5"), - ("MAYA2017","2017"), - ("MAYA2018","2018"), - ("MAYA2019","2019"), - ("MAYA2020","2020"), - ("MAYA2022","2022"), -] - -MAXVERSIONINFO = [("MAX6", "SOFTWARE\\Autodesk\\3DSMAX\\6.0", "installdir", "maxsdk\\cssdk\\include"), - ("MAX7", "SOFTWARE\\Autodesk\\3DSMAX\\7.0", "Installdir", "maxsdk\\include\\CS"), - ("MAX8", "SOFTWARE\\Autodesk\\3DSMAX\\8.0", "Installdir", "maxsdk\\include\\CS"), - ("MAX9", "SOFTWARE\\Autodesk\\3DSMAX\\9.0", "Installdir", "maxsdk\\include\\CS"), - ("MAX2009", "SOFTWARE\\Autodesk\\3DSMAX\\11.0\\MAX-1:409", "Installdir", "maxsdk\\include\\CS"), - ("MAX2010", "SOFTWARE\\Autodesk\\3DSMAX\\12.0\\MAX-1:409", "Installdir", "maxsdk\\include\\CS"), - ("MAX2011", "SOFTWARE\\Autodesk\\3DSMAX\\13.0\\MAX-1:409", "Installdir", "maxsdk\\include\\CS"), - ("MAX2012", "SOFTWARE\\Autodesk\\3DSMAX\\14.0\\MAX-1:409", "Installdir", "maxsdk\\include\\CS"), - ("MAX2013", "SOFTWARE\\Autodesk\\3DSMAX\\15.0\\MAX-1:409", "Installdir", "maxsdk\\include\\CS"), - ("MAX2014", "SOFTWARE\\Autodesk\\3DSMAX\\16.0\\MAX-1:409", "Installdir", "maxsdk\\include\\CS"), -] - -MAYAVERSIONS = [] -MAXVERSIONS = [] -DXVERSIONS = ["DX9"] - -for (ver,key) in MAYAVERSIONINFO: - MAYAVERSIONS.append(ver) +## DirectX Version List +## +######################################################################## -for (ver,key1,key2,subdir) in MAXVERSIONINFO: - MAXVERSIONS.append(ver) +DXVERSIONS = ["DX9"] ######################################################################## ## @@ -400,11 +357,11 @@ def SetTarget(target, arch=None): elif target == 'android' or target.startswith('android-'): if arch is None: - # If compiling on Android, default to same architecture. Otherwise, arm. + # If compiling on Android, default to same architecture. if host == 'android': arch = host_arch else: - arch = 'armv7a' + exit('Specify an Android architecture using --arch') if arch == 'aarch64': arch = 'arm64' @@ -414,12 +371,9 @@ def SetTarget(target, arch=None): target, _, api = target.partition('-') if api: ANDROID_API = int(api) - elif arch in ('mips64', 'arm64', 'x86_64'): - # 64-bit platforms were introduced in Android 21. - ANDROID_API = 21 else: # Default to the lowest API level still supported by Google. - ANDROID_API = 19 + ANDROID_API = 21 # Determine the prefix for our gcc tools, eg. arm-linux-androideabi-gcc global ANDROID_ABI, ANDROID_TRIPLE @@ -612,6 +566,58 @@ def GetSevenZip(): def HasSevenZip(): return GetSevenZip() is not None + +######################################################################## +## +## GetInterrogate[Module] +## +## Installs and locates the interrogate tool. +## +######################################################################## + +INTERROGATE_DIR = None +INTERROGATE_LOCK = threading.Lock() + +def GetInterrogateDir(): + global INTERROGATE_DIR + + if INTERROGATE_DIR: + return INTERROGATE_DIR + + with INTERROGATE_LOCK: + if INTERROGATE_DIR: + return INTERROGATE_DIR + + dir = os.path.join(GetOutputDir(), "tmp", "interrogate") + if not os.path.isdir(os.path.join(dir, "panda3d_interrogate-0.5.0.dist-info")): + oscmd("\"%s\" -m pip install --force-reinstall --upgrade -t \"%s\" panda3d-interrogate==0.5.0" % (sys.executable, dir)) + + INTERROGATE_DIR = dir + + return dir + + +def GetInterrogate(): + path = os.environ.get('INTERROGATE') + if path: + return path + + path = GetInterrogateDir() + '/interrogate/interrogate' + if sys.platform == "win32": + path += ".exe" + return path + + +def GetInterrogateModule(): + path = os.environ.get('INTERROGATE_MODULE') + if path: + return path + + path = GetInterrogateDir() + '/interrogate_module/interrogate_module' + if sys.platform == "win32": + path += ".exe" + return path + ######################################################################## ## ## LocateBinary @@ -660,11 +666,12 @@ def oscmd(cmd, ignoreError = False, cwd=None): print(GetColor("blue") + cmd.split(" ", 1)[0] + " " + GetColor("magenta") + cmd.split(" ", 1)[1] + GetColor()) sys.stdout.flush() + if cmd[0] == '"': + exe = cmd[1 : cmd.index('"', 1)] + else: + exe = cmd.split()[0] + if sys.platform == "win32": - if cmd[0] == '"': - exe = cmd[1 : cmd.index('"', 1)] - else: - exe = cmd.split()[0] exe_path = LocateBinary(exe) if exe_path is None: exit("Cannot find "+exe+" on search path") @@ -700,7 +707,7 @@ def oscmd(cmd, ignoreError = False, cwd=None): exit("") if res != 0 and not ignoreError: - if "interrogate" in cmd.split(" ", 1)[0] and GetVerbose(): + if "interrogate" in exe and "interrogate_module" not in exe and GetVerbose(): print(ColorText("red", "Interrogate failed, retrieving debug output...")) sys.stdout.flush() verbose_cmd = cmd.split(" ", 1)[0] + " -vv " + cmd.split(" ", 1)[1] @@ -1413,6 +1420,9 @@ def GetThirdpartyDir(): elif (target == 'android'): THIRDPARTYDIR = base + "/android-libs-%s/" % (target_arch) + if target_arch == 'armv7a' and not os.path.isdir(THIRDPARTYDIR): + THIRDPARTYDIR = base + "/android-libs-arm/" + elif (target == 'emscripten'): THIRDPARTYDIR = base + "/emscripten-libs/" @@ -1847,7 +1857,7 @@ def SmartPkgEnable(pkg, pkgconfig = None, libs = None, incs = None, defs = None, DefSymbol(target_pkg, d, v) return - elif not custom_loc and GetHost() == "darwin" and framework is not None: + elif not custom_loc and GetHost() == "darwin" and GetTarget() == "darwin" and framework is not None: prefix = SDK["MACOSX"] if (os.path.isdir(prefix + "/Library/Frameworks/%s.framework" % framework) or os.path.isdir(prefix + "/System/Library/Frameworks/%s.framework" % framework) or @@ -2098,46 +2108,6 @@ def SdkLocateDirectX( strMode = 'default' ): if ("DX9" in SDK): SDK["DIRECTCAM"] = SDK["DX9"] -def SdkLocateMaya(): - for (ver, key) in MAYAVERSIONINFO: - if (PkgSkip(ver)==0 and ver not in SDK): - GetSdkDir(ver.lower().replace("x",""), ver) - if (not ver in SDK): - if (GetHost() == "windows"): - for dev in ["Alias|Wavefront","Alias","Autodesk"]: - fullkey="SOFTWARE\\"+dev+"\\Maya\\"+key+"\\Setup\\InstallPath" - res = GetRegistryKey(fullkey, "MAYA_INSTALL_LOCATION", override64=False) - if (res != 0): - res = res.replace("\\", "/").rstrip("/") - SDK[ver] = res - elif (GetHost() == "darwin"): - ddir = "/Applications/Autodesk/maya"+key - if (os.path.isdir(ddir)): SDK[ver] = ddir - else: - if (GetTargetArch() in ("x86_64", "amd64")): - ddir1 = "/usr/autodesk/maya"+key+"-x64" - ddir2 = "/usr/aw/maya"+key+"-x64" - else: - ddir1 = "/usr/autodesk/maya"+key - ddir2 = "/usr/aw/maya"+key - - if (os.path.isdir(ddir1)): SDK[ver] = ddir1 - elif (os.path.isdir(ddir2)): SDK[ver] = ddir2 - -def SdkLocateMax(): - if (GetHost() != "windows"): return - for version,key1,key2,subdir in MAXVERSIONINFO: - if (PkgSkip(version)==0): - if (version not in SDK): - GetSdkDir("maxsdk"+version.lower()[3:], version) - GetSdkDir("maxsdk"+version.lower()[3:], version+"CS") - if (not version in SDK): - top = GetRegistryKey(key1,key2) - if (top != 0): - SDK[version] = top + "maxsdk" - if (os.path.isdir(top + "\\" + subdir)!=0): - SDK[version+"CS"] = top + subdir - def SdkLocatePython(prefer_thirdparty_python=False): if PkgSkip("PYTHON"): # We're not compiling with Python support. We still need to set this @@ -2167,6 +2137,14 @@ def SdkLocatePython(prefer_thirdparty_python=False): SDK["PYTHON"] = sdkdir SDK["PYTHONEXEC"] = SDK["PYTHON"] + "/python" + gil_disabled = locations.get_config_var("Py_GIL_DISABLED") + if gil_disabled and int(gil_disabled): + SDK["PYTHONEXEC"] += "%d.%dt" % sys.version_info[:2] + abiflags = "t" + DefSymbol("PYTHON", "Py_GIL_DISABLED", "1") + else: + abiflags = "" + if (GetOptimize() <= 2): SDK["PYTHONEXEC"] += "_d.exe" else: @@ -2177,11 +2155,11 @@ def SdkLocatePython(prefer_thirdparty_python=False): # Determine which version it is by checking which dll is in the directory. if (GetOptimize() <= 2): - py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]_d.dll") + \ - glob.glob(SDK["PYTHON"] + "/python[0-9][0-9][0-9]_d.dll") + py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]" + abiflags + "_d.dll") + \ + glob.glob(SDK["PYTHON"] + "/python[0-9][0-9][0-9]" + abiflags + "_d.dll") else: - py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9].dll") + \ - glob.glob(SDK["PYTHON"] + "/python[0-9][0-9][0-9].dll") + py_dlls = glob.glob(SDK["PYTHON"] + "/python[0-9][0-9]" + abiflags + ".dll") + \ + glob.glob(SDK["PYTHON"] + "/python[0-9][0-9][0-9]" + abiflags + ".dll") if len(py_dlls) == 0: exit("Could not find the Python dll in %s." % (SDK["PYTHON"])) @@ -2192,37 +2170,62 @@ def SdkLocatePython(prefer_thirdparty_python=False): py_dllver = py_dll.strip(".DHLNOPTY_dhlnopty") ver = py_dllver[0] + '.' + py_dllver[1:] - SDK["PYTHONVERSION"] = "python" + ver - os.environ["PYTHONHOME"] = SDK["PYTHON"] + SDK["PYTHONVERSION"] = "python" + ver + abiflags running_ver = '%d.%d' % sys.version_info[:2] if ver != running_ver: Warn("running makepanda with Python %s, but building Panda3D with Python %s." % (running_ver, ver)) elif CrossCompiling() or (prefer_thirdparty_python and os.path.isdir(os.path.join(GetThirdpartyDir(), "python"))): - tp_python = os.path.join(GetThirdpartyDir(), "python") + if PkgHasCustomLocation("PYTHON"): + incdir = FindIncDirectory("PYTHON") + libdirs = FindLibDirectories("PYTHON") + else: + tp_python = os.path.join(GetThirdpartyDir(), "python") + incdir = tp_python + "/include" + libdirs = [tp_python + "/lib"] + bindir = tp_python + "/bin" if GetTarget() == 'darwin': - py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].dylib") + \ - glob.glob(tp_python + "/lib/libpython[0-9].[0-9][0-9].dylib") + suffix = abiflags + '.dylib' else: - py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].so") + \ - glob.glob(tp_python + "/lib/libpython[0-9].[0-9][0-9].so") + suffix = abiflags + '.so' - if len(py_libs) == 0: - py_libs = glob.glob(tp_python + "/lib/libpython[0-9].[0-9].a") + \ - glob.glob(tp_python + "/lib/libpython[0-9].[0-9][0-9].a") + py_libs = [] + py_static_libs = [] + for libdir in libdirs: + py_libs += glob.glob(libdir + "/libpython[0-9].[0-9]" + suffix) + py_libs += glob.glob(libdir + "/libpython[0-9].[0-9][0-9]" + suffix) + py_static_libs += glob.glob(libdir + "/libpython[0-9].[0-9]" + abiflags + ".a") + py_static_libs += glob.glob(libdir + "/libpython[0-9].[0-9][0-9]" + abiflags + ".a") + + # Prefer dynamic libs over static libs + py_libs += py_static_libs if len(py_libs) == 0: - exit("Could not find the Python library in %s." % (tp_python)) - elif len(py_libs) > 1: - exit("Found multiple Python libraries in %s." % (tp_python)) + exit("Could not find the Python library in %s." % (libdirs)) + elif len(py_libs) == 1: + py_lib = os.path.basename(py_libs[0]) + py_libver = py_lib.lstrip('.abdhilnopsty').rstrip('.abdhilnopsy') + bindir = os.path.dirname(os.path.dirname(py_libs[0])) + "/bin" + else: + # Does one match our version? + gil_disabled = locations.get_config_var("Py_GIL_DISABLED") + abiflags = 't' if gil_disabled and int(gil_disabled) else '' + our_libver = locations.get_python_version() + abiflags + + for py_lib_full in py_libs: + py_lib = os.path.basename(py_lib_full) + py_libver = py_lib.lstrip('.abdhilnopsty').rstrip('.abdhilnopsy') + if py_libver == our_libver: + bindir = os.path.dirname(os.path.dirname(py_lib_full)) + "/bin" + break + else: + exit("Found multiple Python libraries in %s, none matching current version." % (libdirs)) - py_lib = os.path.basename(py_libs[0]) - py_libver = py_lib.strip('.abdhilnopsty') SDK["PYTHONVERSION"] = "python" + py_libver - SDK["PYTHONEXEC"] = tp_python + "/bin/" + SDK["PYTHONVERSION"] - SDK["PYTHON"] = tp_python + "/include/" + SDK["PYTHONVERSION"] + SDK["PYTHONEXEC"] = bindir + "/" + SDK["PYTHONVERSION"] + SDK["PYTHON"] = incdir + "/" + SDK["PYTHONVERSION"] elif GetTarget() == 'darwin' and not PkgHasCustomLocation("PYTHON"): # On macOS, search for the Python framework directory matching the @@ -2230,11 +2233,15 @@ def SdkLocatePython(prefer_thirdparty_python=False): sysroot = SDK.get("MACOSX", "") version = locations.get_python_version() - py_fwx = "{0}/System/Library/Frameworks/Python.framework/Versions/{1}".format(sysroot, version) + framework_name = "Python" + if 't' in abiflags: + framework_name += "T" + + py_fwx = "{0}/System/Library/Frameworks/{1}.framework/Versions/{2}".format(sysroot, framework_name, version) if not os.path.exists(py_fwx): # Fall back to looking on the system. - py_fwx = "/Library/Frameworks/Python.framework/Versions/" + version + py_fwx = "/Library/Frameworks/{0}.framework/Versions/{1}".format(framework_name, version) if not os.path.exists(py_fwx): # Newer macOS versions use this scheme. @@ -2619,6 +2626,8 @@ def SdkLocateAndroid(): # We need to redistribute the C++ standard library. stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'llvm-libc++') stl_lib = os.path.join(stdlibc, 'libs', abi, 'libc++_shared.so') + if not os.path.isfile(stl_lib): + stl_lib = os.path.join(prebuilt_dir, 'sysroot', 'usr', 'lib', ANDROID_TRIPLE.rstrip('0123456789'), 'libc++_shared.so') CopyFile(os.path.join(GetOutputDir(), 'lib', 'libc++_shared.so'), stl_lib) # The Android support library polyfills C++ features not available in the @@ -2683,27 +2692,6 @@ def SdkAutoDisableDirectX(): else: WARNINGS.append("Using "+ver+" sdk: "+SDK[ver]) -def SdkAutoDisableMaya(): - for (ver,key) in MAYAVERSIONINFO: - if (ver not in SDK) and (PkgSkip(ver)==0): - if (GetHost() == "windows"): - WARNINGS.append("The registry does not appear to contain a pointer to the "+ver+" SDK.") - else: - WARNINGS.append("I cannot locate SDK for "+ver) - WARNINGS.append("I have automatically added this command-line option: --no-"+ver.lower()) - PkgDisable(ver) - -def SdkAutoDisableMax(): - for version,key1,key2,subdir in MAXVERSIONINFO: - if (PkgSkip(version)==0) and ((version not in SDK) or (version+"CS" not in SDK)): - if (GetHost() == "windows"): - if (version in SDK): - WARNINGS.append("Your copy of "+version+" does not include the character studio SDK") - else: - WARNINGS.append("The registry does not appear to contain a pointer to "+version) - WARNINGS.append("I have automatically added this command-line option: --no-"+version.lower()) - PkgDisable(version) - def SdkAutoDisableSpeedTree(): if ("SPEEDTREE" not in SDK) and (PkgSkip("SPEEDTREE")==0): PkgDisable("SPEEDTREE") @@ -2894,6 +2882,13 @@ def FindLibDirectory(opt): if mod == opt: return os.path.abspath(dir) +def FindLibDirectories(opt): + result = [] + for mod, dir in LIBDIRECTORIES: + if mod == opt: + result.append(os.path.abspath(dir)) + return result + def FindOptDirectory(opt): # Find the common directory associated with this module # using the include and library directories as a guide @@ -3096,6 +3091,9 @@ def SetupBuildEnvironment(compiler): # If we're cross-compiling, no point in putting our output dirs on the path. if CrossCompiling(): + if GetTarget() == 'emscripten' and not PkgSkip("PYTHON"): + AddToPathEnv("PYTHONPATH", GetOutputDir()) + os.environ["PYTHONHOME"] = os.path.dirname(os.path.dirname(SDK["PYTHON"])) return # Add our output directories to the environment. @@ -3107,6 +3105,7 @@ def SetupBuildEnvironment(compiler): # extension_native_helpers.py currently expects to find libpandaexpress on sys.path. AddToPathEnv("PYTHONPATH", os.path.join(builtdir, "bin")) AddToPathEnv("PATH", os.path.join(builtdir, "plugins")) + os.environ["PYTHONHOME"] = SDK["PYTHON"] # Now for the special (DY)LD_LIBRARY_PATH on Unix-esque systems. if GetHost() != 'windows': @@ -3423,12 +3422,16 @@ def GetExtensionSuffix(): else: dllext = '' + gil_disabled = locations.get_config_var("Py_GIL_DISABLED") + suffix = 't' if gil_disabled and int(gil_disabled) else '' if GetTargetArch() == 'x64': - return dllext + '.cp%d%d-win_amd64.pyd' % (sys.version_info[:2]) + return dllext + '.cp%d%d%s-win_amd64.pyd' % (sys.version_info[0], sys.version_info[1], suffix) else: - return dllext + '.cp%d%d-win32.pyd' % (sys.version_info[:2]) + return dllext + '.cp%d%d%s-win32.pyd' % (sys.version_info[0], sys.version_info[1], suffix) elif target == 'emscripten': - return '.so' + abi = GetPythonABI() + arch = GetTargetArch() + return '.{0}-{1}-emscripten.so'.format(abi, arch) elif CrossCompiling(): return '.{0}.so'.format(GetPythonABI()) else: @@ -3441,7 +3444,14 @@ def GetPythonABI(): if soabi: return soabi - return 'cpython-%d%d' % (sys.version_info[:2]) + soabi = 'cpython-%d%d' % (sys.version_info[:2]) + + if sys.version_info >= (3, 13): + gil_disabled = locations.get_config_var("Py_GIL_DISABLED") + if gil_disabled and int(gil_disabled): + return soabi + 't' + + return soabi def CalcLocation(fn, ipath): if fn.startswith("panda3d/") and fn.endswith(".py"): @@ -3563,7 +3573,7 @@ def GetCurrentPythonVersionInfo(): return return { - "version": SDK["PYTHONVERSION"][6:].rstrip('dmu'), + "version": SDK["PYTHONVERSION"][6:].rstrip('dmut'), "soabi": GetPythonABI(), "ext_suffix": GetExtensionSuffix(), "executable": sys.executable, @@ -3718,7 +3728,7 @@ def TargetAdd(target, dummy=0, opts=[], input=[], dep=[], ipath=None, winrc=None t.inputs.append(fullinput) # Don't re-link a library or binary if just its dependency dlls have been altered. # This should work out fine in most cases, and often reduces recompilation time. - if os.path.splitext(x)[-1] not in SUFFIX_DLL: + if os.path.splitext(x)[-1] not in SUFFIX_DLL or (GetLinkAllStatic() and target.endswith(".exe")): t.deps[fullinput] = 1 (base,suffix) = os.path.splitext(x) if SUFFIX_INC.count(suffix): diff --git a/makepanda/makewheel.py b/makepanda/makewheel.py index 3b2f332260e..f88e1fd7e30 100644 --- a/makepanda/makewheel.py +++ b/makepanda/makewheel.py @@ -19,13 +19,15 @@ def get_abi_tag(): - soabi = get_config_var('SOABI') - if soabi and soabi.startswith('cpython-'): - return 'cp' + soabi.split('-')[1] - elif soabi: - return soabi.replace('.', '_').replace('-', '_') + ver = 'cp%d%d' % sys.version_info[:2] + if hasattr(sys, 'abiflags'): + return ver + sys.abiflags - return 'cp%d%d' % (sys.version_info[:2]) + gil_disabled = get_config_var("Py_GIL_DISABLED") + if gil_disabled and int(gil_disabled): + return ver + 't' + + return ver def is_exe_file(path): @@ -86,7 +88,9 @@ def get_python_ext_module_dir(): # These are not mentioned in manylinux1 spec but should nonetheless always # be excluded. "linux-vdso.so.1", "linux-gate.so.1", "ld-linux.so.2", "libdrm.so.2", + "ld-linux-x86-64.so.2", "ld-linux-aarch64.so.1", "libEGL.so.1", "libOpenGL.so.0", "libGLX.so.0", "libGLdispatch.so.0", + "libGLESv2.so.2", ] # Binaries to never scan for dependencies on non-Windows systems. @@ -94,6 +98,17 @@ def get_python_ext_module_dir(): "panda3d_tools/pstats", ] +# Tools to exclude from the wheel. +EXCLUDE_BINARIES = [ + 'eggcacher', + 'packpanda', + 'interrogate', + 'interrogate_module', + 'test_interrogate', + 'parse_file', + 'run_tests', +] + WHEEL_DATA = """Wheel-Version: 1.0 Generator: makepanda Root-Is-Purelib: false @@ -105,7 +120,7 @@ def get_python_ext_module_dir(): METADATA = { "license": GetMetadataValue('license'), "name": GetMetadataValue('name'), - "metadata_version": "2.0", + "metadata_version": "2.1", "generator": "makepanda", "summary": GetMetadataValue('description'), "extensions": { @@ -487,7 +502,8 @@ def write_file(self, target_path, source_path): self.consider_add_dependency(target_dep, dep_path) continue - elif dep.startswith('/Library/Frameworks/Python.framework/'): + elif dep.startswith('/Library/Frameworks/Python.framework/') or \ + dep.startswith('/Library/Frameworks/PythonT.framework/'): # Add this dependency if it's in the Python directory. target_dep = os.path.dirname(target_path) + '/' + os.path.basename(dep) target_dep = self.consider_add_dependency(target_dep, dep, loader_path) @@ -629,10 +645,20 @@ def makewheel(version, output_dir, platform=None): if platform is None: # Determine the platform from the build. platform_dat = os.path.join(output_dir, 'tmp', 'platform.dat') + cmake_cache = os.path.join(output_dir, 'CMakeCache.txt') if os.path.isfile(platform_dat): + # This is written by makepanda. platform = open(platform_dat, 'r').read().strip() + elif os.path.isfile(cmake_cache): + # This variable is written to the CMake cache by Package.cmake. + for line in open(cmake_cache, 'r').readlines(): + if line.startswith('PYTHON_PLATFORM_TAG:STRING='): + platform = line[27:].strip() + break + if not platform: + raise Exception("Could not find PYTHON_PLATFORM_TAG in CMakeCache.txt, specify --platform manually.") else: - print("Could not find platform.dat in build directory") + print("Could not find platform.dat or CMakeCache.txt in build directory") platform = get_platform() if platform.startswith("linux-") and os.path.isdir("/opt/python"): # Is this manylinux? @@ -653,6 +679,7 @@ def makewheel(version, output_dir, platform=None): or platform.startswith('win_') \ or platform.startswith('cygwin_') is_macosx = platform.startswith('macosx_') + is_android = platform.startswith('android_') # Global filepaths panda3d_dir = join(output_dir, "panda3d") @@ -712,12 +739,20 @@ def makewheel(version, output_dir, platform=None): whl.ignore_deps.update(MANYLINUX_LIBS) # Add libpython for deployment. + suffix = '' + gil_disabled = get_config_var("Py_GIL_DISABLED") + if gil_disabled and int(gil_disabled): + suffix = 't' + if is_windows: - pylib_name = 'python{0}{1}.dll'.format(*sys.version_info) + pylib_name = 'python{0}{1}{2}.dll'.format(sys.version_info[0], sys.version_info[1], suffix) pylib_path = os.path.join(get_config_var('BINDIR'), pylib_name) elif is_macosx: - pylib_name = 'libpython{0}.{1}.dylib'.format(*sys.version_info) + pylib_name = 'libpython{0}.{1}{2}.dylib'.format(sys.version_info[0], sys.version_info[1], suffix) pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name) + elif is_android and CrossCompiling(): + pylib_name = 'libpython{0}.{1}{2}.so'.format(sys.version_info[0], sys.version_info[1], suffix) + pylib_path = os.path.join(GetThirdpartyDir(), 'python', 'lib', pylib_name) else: pylib_name = get_config_var('LDLIBRARY') pylib_arch = get_config_var('MULTIARCH') @@ -856,7 +891,7 @@ def makewheel(version, output_dir, platform=None): tools_init = '' for file in sorted(os.listdir(bin_dir)): basename = os.path.splitext(file)[0] - if basename in ('eggcacher', 'packpanda'): + if basename in EXCLUDE_BINARIES: continue source_path = os.path.join(bin_dir, file) diff --git a/makepanda/test_wheel.py b/makepanda/test_wheel.py index cfe270099ed..2de54e059d1 100755 --- a/makepanda/test_wheel.py +++ b/makepanda/test_wheel.py @@ -14,7 +14,7 @@ from optparse import OptionParser -def test_wheel(wheel, verbose=False): +def test_wheel(wheel, verbose=False, ignores=[]): envdir = tempfile.mkdtemp(prefix="venv-") print("Setting up virtual environment in {0}".format(envdir)) sys.stdout.flush() @@ -61,6 +61,9 @@ def test_wheel(wheel, verbose=False): test_cmd = [python, "-m", "pytest", "tests"] if verbose: test_cmd.append("--verbose") + for ignore in ignores: + test_cmd.append("--ignore") + test_cmd.append(ignore) # Put the location of the python DLL on the path, for deploy-stub test # This is needed because venv does not install a copy of the python DLL @@ -87,6 +90,7 @@ def test_wheel(wheel, verbose=False): if __name__ == "__main__": parser = OptionParser(usage="%prog [options] file...") parser.add_option('', '--verbose', dest = 'verbose', help = 'Enable verbose output', action = 'store_true', default = False) + parser.add_option('', '--ignore', dest = 'ignores', help = 'Ignores given test directory (may be repeated)', action = 'append', default = []) (options, args) = parser.parse_args() if not args: @@ -94,4 +98,4 @@ def test_wheel(wheel, verbose=False): sys.exit(1) for arg in args: - test_wheel(arg, verbose=options.verbose) + test_wheel(arg, verbose=options.verbose, ignores=options.ignores) diff --git a/mypy.ini b/mypy.ini index 85a2d940319..696e4894b0e 100644 --- a/mypy.ini +++ b/mypy.ini @@ -11,3 +11,6 @@ ignore_missing_imports = True [mypy-Pmw.*] ignore_missing_imports = True + +[mypy-imp] +ignore_missing_imports = True diff --git a/panda/CMakeLists.txt b/panda/CMakeLists.txt index cb33932d9cb..e118a8a5b98 100644 --- a/panda/CMakeLists.txt +++ b/panda/CMakeLists.txt @@ -107,7 +107,7 @@ if(HAVE_FREETYPE) endif() if(INTERROGATE_PYTHON_INTERFACE) - add_python_module(panda3d.core ${CORE_MODULE_COMPONENTS} LINK panda) + add_python_module(panda3d.core ${CORE_MODULE_COMPONENTS} LINK panda INIT pyenv_init) # Generate our __init__.py if(WIN32) diff --git a/panda/src/android/android_main.cxx b/panda/src/android/android_main.cxx index 13895d99f60..55355533c3a 100644 --- a/panda/src/android/android_main.cxx +++ b/panda/src/android/android_main.cxx @@ -75,6 +75,7 @@ void android_main(struct android_app* app) { << "New native activity started on " << *current_thread << "\n"; // Were we given an optional location to write the stdout/stderr streams? + bool owns_stdout = false; methodID = env->GetMethodID(activity_class, "getIntentOutputUri", "()Ljava/lang/String;"); jstring joutput_uri = (jstring) env->CallObjectMethod(activity->clazz, methodID); if (joutput_uri != nullptr) { @@ -92,6 +93,7 @@ void android_main(struct android_app* app) { dup2(fd, 1); dup2(fd, 2); + owns_stdout = true; } else { android_cat.error() << "Failed to open output path " << path << "\n"; @@ -109,6 +111,7 @@ void android_main(struct android_app* app) { << spec.get_server_and_port() << "\n"; dup2(fd, 1); dup2(fd, 2); + owns_stdout = true; } else { android_cat.error() << "Failed to open output socket " @@ -267,11 +270,10 @@ void android_main(struct android_app* app) { // We still need to keep an event loop going until Android gives us leave // to end the process. - int looper_id; - int events; - struct android_poll_source *source; - while ((looper_id = ALooper_pollAll(-1, nullptr, &events, (void**)&source)) >= 0) { - // Process this event, but intercept application command events. + while (!app->destroyRequested) { + int looper_id; + struct android_poll_source *source; + auto result = ALooper_pollOnce(-1, &looper_id, nullptr, (void **)&source); if (looper_id == LOOPER_ID_MAIN) { int8_t cmd = android_app_read_cmd(app); android_app_pre_exec_cmd(app, cmd); @@ -300,8 +302,10 @@ void android_main(struct android_app* app) { env->ReleaseStringUTFChars(filename, filename_str); } - close(1); - close(2); + if (owns_stdout) { + close(1); + close(2); + } // Detach the thread before exiting. activity->vm->DetachCurrentThread(); diff --git a/panda/src/android/pview_manifest.xml b/panda/src/android/pview_manifest.xml index b462e4018a6..e68dce55849 100644 --- a/panda/src/android/pview_manifest.xml +++ b/panda/src/android/pview_manifest.xml @@ -8,7 +8,7 @@ - + diff --git a/panda/src/androiddisplay/androidGraphicsWindow.cxx b/panda/src/androiddisplay/androidGraphicsWindow.cxx index b3a8ae425d3..1cc59d82987 100644 --- a/panda/src/androiddisplay/androidGraphicsWindow.cxx +++ b/panda/src/androiddisplay/androidGraphicsWindow.cxx @@ -181,16 +181,14 @@ process_events() { GraphicsWindow::process_events(); // Read all pending events. - int looper_id; - int events; - struct android_poll_source* source; - - // Loop until all events are read. - while ((looper_id = ALooper_pollAll(0, nullptr, &events, (void**)&source)) >= 0) { - // Process this event. - if (source != nullptr) { - source->process(_app, source); - } + struct android_poll_source *source; + + auto result = ALooper_pollOnce(0, nullptr, nullptr, (void **)&source); + nassertv(result != ALOOPER_POLL_ERROR); + + // Process this event. + if (source != nullptr) { + source->process(_app, source); } } @@ -437,14 +435,15 @@ ns_handle_command(int32_t command) { case APP_CMD_WINDOW_RESIZED: properties.set_size(ANativeWindow_getWidth(_app->window), ANativeWindow_getHeight(_app->window)); + system_changed_properties(properties); break; case APP_CMD_WINDOW_REDRAW_NEEDED: break; case APP_CMD_CONTENT_RECT_CHANGED: - properties.set_origin(_app->contentRect.left, _app->contentRect.top); + /*properties.set_origin(_app->contentRect.left, _app->contentRect.top); properties.set_size(_app->contentRect.right - _app->contentRect.left, _app->contentRect.bottom - _app->contentRect.top); - system_changed_properties(properties); + system_changed_properties(properties);*/ break; case APP_CMD_GAINED_FOCUS: properties.set_foreground(true); diff --git a/panda/src/audio/config_audio.cxx b/panda/src/audio/config_audio.cxx index d483b40d75d..de128896e60 100644 --- a/panda/src/audio/config_audio.cxx +++ b/panda/src/audio/config_audio.cxx @@ -75,6 +75,13 @@ ConfigVariableInt audio_preload_threshold "practical to stream multiple sound-files from disk at the same " "time - the hard drive seek time makes it stutter.")); +ConfigVariableBool audio_want_hrtf +("audio-want-hrtf", true, + PRC_DESC("This determines whether OpenAL-Soft should activate HRTF in " + "certain hardware configurations. Set it to true to cause " + "OpenAL to automatically apply HRTF processing to all output " + "audio when headphones are used for playback.")); + // Unknown ConfigVariableInt audio_min_hw_channels diff --git a/panda/src/audio/config_audio.h b/panda/src/audio/config_audio.h index deac9704be4..4e5c428e928 100644 --- a/panda/src/audio/config_audio.h +++ b/panda/src/audio/config_audio.h @@ -67,6 +67,7 @@ extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_distance_factor; extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_drop_off_factor; extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_buffering_seconds; extern EXPCL_PANDA_AUDIO ConfigVariableInt audio_preload_threshold; +extern EXPCL_PANDA_AUDIO ConfigVariableBool audio_want_hrtf; #ifdef NOTIFY_DEBUG //[ // Non-release build: diff --git a/panda/src/audiotraits/openalAudioManager.cxx b/panda/src/audiotraits/openalAudioManager.cxx index 0e6e06d16ac..5df2d0d8809 100644 --- a/panda/src/audiotraits/openalAudioManager.cxx +++ b/panda/src/audiotraits/openalAudioManager.cxx @@ -155,7 +155,22 @@ OpenALAudioManager() { if (_device != nullptr) { // We managed to get a device open. alcGetError(_device); // clear errors - _context = alcCreateContext(_device, nullptr); + + ALCboolean is_hrtf_present = alcIsExtensionPresent(_device, "ALC_SOFT_HRTF"); + + ALCint attrs[3] = {0}; + +#ifndef HAVE_OPENAL_FRAMEWORK + if (is_hrtf_present) { + attrs[0] = ALC_HRTF_SOFT; + attrs[1] = audio_want_hrtf.get_value() ? ALC_TRUE : ALC_FALSE; + attrs[2] = 0; // end of list + } else { + attrs[0] = 0; // end of list + } +#endif // HAVE_OPENAL_FRAMEWORK + + _context = alcCreateContext(_device, attrs); alc_audio_errcheck("alcCreateContext(_device, NULL)", _device); if (_context != nullptr) { _openal_active = true; diff --git a/panda/src/audiotraits/openalAudioManager.h b/panda/src/audiotraits/openalAudioManager.h index 3970c506277..56b01afc6c0 100644 --- a/panda/src/audiotraits/openalAudioManager.h +++ b/panda/src/audiotraits/openalAudioManager.h @@ -29,6 +29,7 @@ #else #include #include + #include #endif class OpenALAudioSound; diff --git a/panda/src/audiotraits/openalAudioSound.h b/panda/src/audiotraits/openalAudioSound.h index cc643ac20c6..6dc30a936c5 100644 --- a/panda/src/audiotraits/openalAudioSound.h +++ b/panda/src/audiotraits/openalAudioSound.h @@ -27,6 +27,7 @@ #else #include #include + #include #endif class EXPCL_OPENAL_AUDIO OpenALAudioSound final : public AudioSound { diff --git a/panda/src/bullet/bulletDebugNode.cxx b/panda/src/bullet/bulletDebugNode.cxx index 7bc26ae1c19..b3a54071462 100644 --- a/panda/src/bullet/bulletDebugNode.cxx +++ b/panda/src/bullet/bulletDebugNode.cxx @@ -248,16 +248,8 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { // Record them without any state or transform. trav->_geoms_pcollector.add_level(2); - { - CullableObject *object = - new CullableObject(std::move(debug_lines), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()); - trav->get_cull_handler()->record_object(object, trav); - } - { - CullableObject *object = - new CullableObject(std::move(debug_triangles), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()); - trav->get_cull_handler()->record_object(object, trav); - } + trav->get_cull_handler()->record_object(CullableObject(std::move(debug_lines), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()), trav); + trav->get_cull_handler()->record_object(CullableObject(std::move(debug_triangles), RenderState::make_empty(), trav->get_scene()->get_cs_world_transform()), trav); } /** diff --git a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm index 3734f37af87..5ab3d64341b 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm @@ -177,7 +177,7 @@ // Get processor information const NXArchInfo *ainfo = NXGetLocalArchInfo(); - _display_information->_cpu_brand_string = strdup(ainfo->description); + _display_information->_cpu_brand_string.assign(ainfo->description); // Get version of Mac OS X SInt32 major, minor, bugfix; diff --git a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm index 3aae8aee634..01c7ab8f63f 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsWindow.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsWindow.mm @@ -32,7 +32,6 @@ #import "cocoaPandaAppDelegate.h" #import -#import #import #import #import @@ -47,6 +46,12 @@ #define NSAppKitVersionNumber10_14 1671 #endif +#if __MAC_OS_X_VERSION_MAX_ALLOWED < 1070 +enum { + NSFullScreenWindowMask = 1 << 14 +}; +#endif + /** * */ @@ -177,7 +182,6 @@ process_events() { GraphicsWindow::process_events(); - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSEvent *event = nil; while (true) { @@ -212,8 +216,6 @@ [_window update]; } - [pool release]; - if (_context_needs_update && _gsg != nullptr) { update_context(); } @@ -728,13 +730,12 @@ // here. if (!properties.has_undecorated() && !_properties.get_undecorated() && [_window respondsToSelector:@selector(setStyleMask:)]) { - if (properties.get_fixed_size()) { - [_window setStyleMask:NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask ]; - } else { - [_window setStyleMask:NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSResizableWindowMask ]; + NSUInteger style = ([_window styleMask] & NSFullScreenWindowMask); + style |= NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; + if (!properties.get_fixed_size()) { + style |= NSResizableWindowMask; } + [_window setStyleMask:style]; [_window makeFirstResponder:_view]; // Resize event fired by makeFirstResponder has an invalid backing scale factor // The actual size must be reset afterward @@ -749,16 +750,14 @@ _properties.set_undecorated(properties.get_undecorated()); if (!_properties.get_fullscreen()) { - if (properties.get_undecorated()) { - [_window setStyleMask: NSBorderlessWindowMask]; - } else if (_properties.get_fixed_size()) { - // Fixed size windows should not show the resize button. - [_window setStyleMask: NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask ]; - } else { - [_window setStyleMask: NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSResizableWindowMask ]; + NSUInteger style = ([_window styleMask] & NSFullScreenWindowMask); + if (!properties.get_undecorated()) { + style |= NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; + if (!properties.get_fixed_size()) { + style |= NSResizableWindowMask; + } } + [_window setStyleMask:style]; [_window makeFirstResponder:_view]; // Resize event fired by makeFirstResponder has an invalid backing scale factor // The actual size must be reset afterward @@ -1176,10 +1175,16 @@ } if (_window != nil) { + // Exit macOS' own fullscreen mode, since our own fullscreen mode + // doesn't work properly with it. + if ([_window styleMask] & NSFullScreenWindowMask) { + [_window toggleFullScreen:nil]; + } + // For some reason, setting the style mask makes it give up its // first-responder status. if ([_window respondsToSelector:@selector(setStyleMask:)]) { - [_window setStyleMask:NSBorderlessWindowMask]; + [_window setStyleMask:([_window styleMask] & NSFullScreenWindowMask)]; } [_window makeFirstResponder:_view]; [_window setLevel:CGShieldingWindowLevel()]; diff --git a/panda/src/cocoadisplay/cocoaPandaApp.mm b/panda/src/cocoadisplay/cocoaPandaApp.mm index 83f0b8ef42d..d256102a2c8 100644 --- a/panda/src/cocoadisplay/cocoaPandaApp.mm +++ b/panda/src/cocoadisplay/cocoaPandaApp.mm @@ -16,11 +16,11 @@ @implementation CocoaPandaApp - (void) sendEvent: (NSEvent *) event { - // This is a hack that allows us to receive cmd-key-up events correctly. - // Also prevent it from eating the inserthelp key. - if (([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) - ||([event type] == NSKeyDown && [event keyCode] == 0x72)) { - + // This is a hack that allows us to receive cmd-key-up events correctly, as + // well as key-up events during a full-screen transition. + // Also prevent it from eating the insert/help key. + if ([event type] == NSKeyUp || + ([event type] == NSKeyDown && [event keyCode] == 0x72)) { [[self keyWindow] sendEvent: event]; } else { [super sendEvent: event]; diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.mm b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.mm index 3632becb0ba..95e4e805a36 100644 --- a/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.mm +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsBuffer.mm @@ -98,7 +98,8 @@ // If the old gsg has the wrong pixel format, create a new one that shares // with the old gsg. DCAST_INTO_R(cocoagsg, _gsg, false); - if (!cocoagsg->get_fb_properties().subsumes(_fb_properties)) { + if (cocoagsg->get_engine() != _engine || + !cocoagsg->get_fb_properties().subsumes(_fb_properties)) { cocoagsg = new CocoaGLGraphicsStateGuardian(_engine, _pipe, cocoagsg); cocoagsg->choose_pixel_format(_fb_properties, cocoa_pipe->get_display_id(), false); _gsg = cocoagsg; diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.mm b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.mm index 7ad1317b0b4..4864ae2f8b8 100644 --- a/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.mm +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsPipe.mm @@ -125,12 +125,12 @@ precertify = true; } } - if (host != nullptr) { + if (host != nullptr && host->get_engine() == engine) { return new GLGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host); } else { return new CocoaGLGraphicsBuffer(engine, this, name, fb_prop, win_prop, - flags, gsg, host); + flags, gsg, nullptr); } } diff --git a/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.mm b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.mm index 33a97a90f92..71a3f87ad36 100644 --- a/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.mm +++ b/panda/src/cocoagldisplay/cocoaGLGraphicsWindow.mm @@ -200,7 +200,8 @@ // If the old gsg has the wrong pixel format, create a new one that shares // with the old gsg. DCAST_INTO_R(cocoagsg, _gsg, false); - if (!cocoagsg->get_fb_properties().subsumes(_fb_properties)) { + if (cocoagsg->get_engine() != _engine || + !cocoagsg->get_fb_properties().subsumes(_fb_properties)) { cocoagsg = new CocoaGLGraphicsStateGuardian(_engine, _pipe, cocoagsg); cocoagsg->choose_pixel_format(_fb_properties, _display, false); _gsg = cocoagsg; diff --git a/panda/src/collide/CMakeLists.txt b/panda/src/collide/CMakeLists.txt index 296a40eeed5..8dad7fe29a9 100644 --- a/panda/src/collide/CMakeLists.txt +++ b/panda/src/collide/CMakeLists.txt @@ -74,6 +74,8 @@ set(P3COLLIDE_IGATEEXT collisionHandlerPhysical_ext.h collisionHandlerQueue_ext.cxx collisionHandlerQueue_ext.h + collisionNode_ext.cxx + collisionNode_ext.h collisionPolygon_ext.cxx collisionPolygon_ext.h collisionTraverser_ext.cxx diff --git a/panda/src/collide/collisionBox.I b/panda/src/collide/collisionBox.I index 86473473cfe..385152c2a1a 100644 --- a/panda/src/collide/collisionBox.I +++ b/panda/src/collide/collisionBox.I @@ -21,11 +21,9 @@ CollisionBox(const LPoint3 ¢er, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { _min = LPoint3(_center.get_x() - x, _center.get_y() - y, _center.get_z() - z); _max = LPoint3(_center.get_x() + x, _center.get_y() + y, _center.get_z() + z); - for(int v = 0; v < 8; v++) - _vertex[v] = get_point_aabb(v); - for(int p = 0; p < 6; p++) + for (int p = 0; p < 6; ++p) { _planes[p] = set_plane(p); - setup_box(); + } } /** @@ -33,14 +31,11 @@ CollisionBox(const LPoint3 ¢er, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) */ INLINE CollisionBox:: CollisionBox(const LPoint3 &min, const LPoint3 &max) : - _min(min), _max(max) + _center((min + max) / 2), _min(min), _max(max) { - _center = (_min + _max) / 2; - for(int v = 0; v < 8; v++) - _vertex[v] = get_point_aabb(v); - for(int p = 0; p < 6; p++) + for (int p = 0; p < 6; ++p) { _planes[p] = set_plane(p); - setup_box(); + } } /** @@ -60,11 +55,9 @@ CollisionBox(const CollisionBox ©) : _min(copy._min), _max(copy._max) { - for(int v = 0; v < 8; v++) - _vertex[v] = copy._vertex[v]; - for(int p = 0; p < 6; p++) + for (int p = 0; p < 6; ++p) { _planes[p] = copy._planes[p]; - setup_box(); + } } /** @@ -139,8 +132,7 @@ get_num_points() const { */ INLINE LPoint3 CollisionBox:: get_point(int n) const { - nassertr(n >= 0 && n < 8, LPoint3::zero()); - return _vertex[n]; + return get_point_aabb(n); } /** @@ -175,6 +167,8 @@ get_plane(int n) const { /** * Creates the nth face of the rectangular solid. + * + * @deprecated Same as get_plane(). */ INLINE LPlane CollisionBox:: set_plane(int n) const { @@ -183,91 +177,3 @@ set_plane(int n) const { get_point(plane_def[n][1]), get_point(plane_def[n][2])); } - - -/** - * Returns true if the 2-d v1 is to the right of v2. - */ -INLINE bool CollisionBox:: -is_right(const LVector2 &v1, const LVector2 &v2) { - return (v1[0] * v2[1] - v1[1] * v2[0]) > 1.0e-6f; -} - -/** - * Returns the linear distance of p to the line defined by f and f+v, where v - * is a normalized vector. The result is negative if p is left of the line, - * positive if it is right of the line. - */ -INLINE PN_stdfloat CollisionBox:: -dist_to_line(const LPoint2 &p, - const LPoint2 &f, const LVector2 &v) { - LVector2 v1 = (p - f); - return (v1[0] * v[1] - v1[1] * v[0]); -} - -/** - * Assuming the indicated point in 3-d space lies within the polygon's plane, - * returns the corresponding point in the polygon's 2-d definition space. - */ -INLINE LPoint2 CollisionBox:: -to_2d(const LVecBase3 &point3d, int plane) const { - LPoint3 point = LPoint3(point3d) * _to_2d_mat[plane]; - return LPoint2(point[0], point[2]); -} - -/** - * Fills the indicated matrix with the appropriate rotation transform to move - * points from the 2-d plane into the 3-d (X, 0, Z) plane. - */ -INLINE void CollisionBox:: -calc_to_3d_mat(LMatrix4 &to_3d_mat,int plane) const { - // We have to be explicit about the coordinate system--we specifically mean - // CS_zup_right, because that points the forward vector down the Y axis and - // moves the coords in (X, 0, Z). We want this effect regardless of the - // user's coordinate system of choice. - - // The up vector, on the other hand, is completely arbitrary. - - look_at(to_3d_mat, -get_plane(plane).get_normal(), - LVector3(0.0f, 0.0f, 1.0f), CS_zup_right); - to_3d_mat.set_row(3, get_plane(plane).get_point()); -} - -/** - * Extrude the indicated point in the polygon's 2-d definition space back into - * 3-d coordinates. - */ -INLINE LPoint3 CollisionBox:: -to_3d(const LVecBase2 &point2d, const LMatrix4 &to_3d_mat) { - return LPoint3(point2d[0], 0.0f, point2d[1]) * to_3d_mat; -} - -/** - * - */ -INLINE CollisionBox::PointDef:: -PointDef(const LPoint2 &p, const LVector2 &v) : _p(p), _v(v) { -} - -/** - * - */ -INLINE CollisionBox::PointDef:: -PointDef(PN_stdfloat x, PN_stdfloat y) : _p(x, y), _v(0.0f, 0.0f) { -} - -/** - * - */ -INLINE CollisionBox::PointDef:: -PointDef(const CollisionBox::PointDef ©) : _p(copy._p), _v(copy._v) { -} - -/** - * - */ -INLINE void CollisionBox::PointDef:: -operator = (const CollisionBox::PointDef ©) { - _p = copy._p; - _v = copy._v; -} diff --git a/panda/src/collide/collisionBox.cxx b/panda/src/collide/collisionBox.cxx index f4224f2d147..5058dfaf37f 100644 --- a/panda/src/collide/collisionBox.cxx +++ b/panda/src/collide/collisionBox.cxx @@ -55,50 +55,107 @@ const int CollisionBox::plane_def[6][4] = { }; /** - * + * Helper function to calculate the intersection between a line segment and a + * sphere. t is filled with the first position along the line segment where + * the intersection hits. */ -CollisionSolid *CollisionBox:: -make_copy() { - return new CollisionBox(*this); +static bool +intersect_segment_sphere(double &t, + const LPoint3 &from, const LVector3 &delta, + const LPoint3 ¢er, double radius_sq) { + double A2 = dot(delta, delta) * 2; + + LVector3 fc = from - center; + double fc_d2 = dot(fc, fc); + double C = fc_d2 - radius_sq; + + if (UNLIKELY(A2 == 0.0)) { + // Degenerate case where delta is zero. This is effectively a test + // against a point (or sphere, for nonzero inflate_radius). + t = 0.0; + return C < 0.0; + } + + double B = 2.0f * dot(delta, fc); + double radical = B*B - 2.0*A2*C; + + if (radical < 0.0) { + // No real roots: no intersection with the line. + return false; + } + + t = (-B - csqrt(radical)) / A2; + return true; } /** - * Compute parameters for each of the box's sides + * Helper function to calculate the intersection between a line segment and a + * capsule. t is filled with the first position along the line segment where + * the intersection hits. + * + * Code derived from a book by Christer Ericson. */ -void CollisionBox:: -setup_box() { - assert(sizeof(_points) / sizeof(_points[0]) == 6); - assert(sizeof(_points[0]) / sizeof(_points[0][0]) == 4); - for (int plane = 0; plane < 6; plane++) { - setup_points(plane); +static bool +intersect_segment_capsule(double &t, + const LPoint3 &from_a, const LVector3 &delta_a, + const LPoint3 &from_b, const LPoint3 &to_b, + double radius_sq) { + LVector3 m = from_a - from_b; + LVector3 delta_b = to_b - from_b; + PN_stdfloat md = m.dot(delta_b); + PN_stdfloat nd = delta_a.dot(delta_b); + PN_stdfloat dd = delta_b.dot(delta_b); + if (md < 0 && md + nd < 0) { + return intersect_segment_sphere(t, from_a, delta_a, from_b, radius_sq); + } + if (md > dd && md + nd > dd) { + return intersect_segment_sphere(t, from_a, delta_a, to_b, radius_sq); + } + PN_stdfloat nn = delta_a.dot(delta_a); + PN_stdfloat mn = m.dot(delta_a); + PN_stdfloat a = dd * nn - nd * nd; + PN_stdfloat k = m.dot(m) - radius_sq; + PN_stdfloat c = dd * k - md * md; + if (IS_NEARLY_ZERO(a)) { + // Segments run parallel + if (c > 0.0f) { + return false; + } + if (md < 0.0f) { + return intersect_segment_sphere(t, from_a, delta_a, from_b, radius_sq); + } + else if (md > dd) { + return intersect_segment_sphere(t, from_a, delta_a, to_b, radius_sq); + } + else { + t = 0.0; + } + return true; + } + PN_stdfloat b = dd * mn - nd * md; + PN_stdfloat discr = b * b - a * c; + if (discr < 0.0f) { + return false; + } + t = (-b - csqrt(discr)) / a; + if (t < 0.0 || t > 1.0) { + return false; + } + if (md + t * nd < 0) { + return intersect_segment_sphere(t, from_a, delta_a, from_b, radius_sq); + } + else if (md + t * nd > dd) { + return intersect_segment_sphere(t, from_a, delta_a, to_b, radius_sq); } + return true; } /** - * Computes the plane and 2d projection of points that make up this side. + * */ -void CollisionBox:: -setup_points(int plane) { - PointDef *points = _points[plane]; - - // Construct a matrix that rotates the points from the (X,0,Z) plane into - // the 3-d plane. - LMatrix4 to_3d_mat; - calc_to_3d_mat(to_3d_mat, plane); - - // And the inverse matrix rotates points from 3-d space into the 2-d plane. - _to_2d_mat[plane].invert_from(to_3d_mat); - - // Now project all of the points onto the 2-d plane. - for (size_t i = 0; i < 4; ++i) { - LPoint3 point = get_point(plane_def[plane][i]) * _to_2d_mat[plane]; - points[i] = PointDef(point[0], point[2]); - } - - for (size_t i = 0; i < 4; i++) { - points[i]._v = points[(i + 1) % 4]._p - points[i]._p; - points[i]._v.normalize(); - } +CollisionSolid *CollisionBox:: +make_copy() { + return new CollisionBox(*this); } /** @@ -117,13 +174,9 @@ xform(const LMatrix4 &mat) { _min = _min * mat; _max = _max * mat; _center = _center * mat; - for(int v = 0; v < 8; v++) { - _vertex[v] = _vertex[v] * mat; - } for(int p = 0; p < 6 ; p++) { _planes[p] = set_plane(p); } - setup_box(); mark_viz_stale(); mark_internal_bounds_stale(); } @@ -169,9 +222,10 @@ output(std::ostream &out) const { */ PT(BoundingVolume) CollisionBox:: compute_internal_bounds() const { - PN_stdfloat x = _vertex[0].get_x() - _center.get_x(); - PN_stdfloat y = _vertex[0].get_y() - _center.get_y(); - PN_stdfloat z = _vertex[0].get_z() - _center.get_z(); + LPoint3 vertex = get_point_aabb(0); + PN_stdfloat x = vertex.get_x() - _center.get_x(); + PN_stdfloat y = vertex.get_y() - _center.get_y(); + PN_stdfloat z = vertex.get_z() - _center.get_z(); PN_stdfloat radius = sqrt(x * x + y * y + z * z); return new BoundingSphere(_center, radius); } @@ -190,168 +244,45 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { const LMatrix4 &wrt_mat = wrt_space->get_mat(); - LPoint3 orig_center = sphere->get_center() * wrt_mat; - LPoint3 from_center = orig_center; - bool moved_from_center = false; - PN_stdfloat t = 1.0f; - LPoint3 contact_point(from_center); - PN_stdfloat actual_t = 1.0f; - - LVector3 from_radius_v = - LVector3(sphere->get_radius(), 0.0f, 0.0f) * wrt_mat; - PN_stdfloat from_radius_2 = from_radius_v.length_squared(); - PN_stdfloat from_radius = csqrt(from_radius_2); - - int ip; - PN_stdfloat max_dist = 0.0; - PN_stdfloat dist = 0.0; - bool intersect; - LPlane plane; - LVector3 normal; - bool fully_inside = true; - - for(ip = 0, intersect = false; ip < 6 && !intersect; ip++) { - plane = get_plane(ip); - - if (wrt_prev_space != wrt_space) { - // If we have a delta between the previous position and the current - // position, we use that to determine some more properties of the - // collision. - LPoint3 b = from_center; - LPoint3 a = sphere->get_center() * wrt_prev_space->get_mat(); - LVector3 delta = b - a; - - // First, there is no collision if the "from" object is definitely - // moving in the same direction as the plane's normal. - PN_stdfloat dot = delta.dot(plane.get_normal()); - if (dot > 0.1f) { - fully_inside = false; - continue; // no intersection - } + LPoint3 center = wrt_mat.xform_point(sphere->get_center()); + PN_stdfloat radius_sq = wrt_mat.xform_vec(LVector3(0, 0, sphere->get_radius())).length_squared(); - if (IS_NEARLY_ZERO(dot)) { - // If we're moving parallel to the plane, the sphere is tested at its - // final point. Leave it as it is. - - } else { -/* - * Otherwise, we're moving into the plane; the sphere is tested at the point - * along its path that is closest to intersecting the plane. This may be the - * actual intersection point, or it may be the starting point or the final - * point. dot is equal to the (negative) magnitude of 'delta' along the - * direction of the plane normal t = ratio of (distance from start pos to - * plane) to (distance from start pos to end pos), along axis of plane normal - */ - PN_stdfloat dist_to_p = plane.dist_to_plane(a); - t = (dist_to_p / -dot); - - // also compute the actual contact point and time of contact for - // handlers that need it - actual_t = ((dist_to_p - from_radius) / -dot); - actual_t = min((PN_stdfloat)1.0, max((PN_stdfloat)0.0, actual_t)); - contact_point = a + (actual_t * delta); - - if (t >= 1.0f) { - // Leave it where it is. - - } else if (t < 0.0f) { - from_center = a; - moved_from_center = true; - } else { - from_center = a + t * delta; - moved_from_center = true; - } - } - } + bool had_prev = false; + LPoint3 prev_center = center; + double t = 0; - normal = (has_effective_normal() && sphere->get_respect_effective_normal()) ? get_effective_normal() : plane.get_normal(); - -#ifndef NDEBUG - /*if (!IS_THRESHOLD_EQUAL(normal.length_squared(), 1.0f, 0.001), NULL) { - std::cout - << "polygon within " << entry.get_into_node_path() - << " has normal " << normal << " of length " << normal.length() - << "\n"; - normal.normalize(); - }*/ -#endif - - // The nearest point within the plane to our center is the intersection of - // the line (center, center - normal) with the plane. - - if (!plane.intersects_line(dist, from_center, -(plane.get_normal()))) { - // No intersection with plane? This means the plane's effective normal - // was within the plane itself. A useless polygon. - fully_inside = false; - continue; - } + if (wrt_space != wrt_prev_space) { + prev_center = wrt_prev_space->get_mat().xform_point(sphere->get_center()); + } + LPoint3 contact_center = prev_center; - if (dist > from_radius) { - // Fully outside this plane, there can not be an intersection. + // First, just test the starting point of the sphere. + LVector3 vec = (prev_center - _min).fmin(0) + (prev_center - _max).fmax(0); + PN_stdfloat vec_lsq = vec.length_squared(); + if (vec_lsq > radius_sq) { + if (wrt_space == wrt_prev_space) { return nullptr; } - if (dist < -from_radius) { - // Fully inside this plane. - continue; - } - fully_inside = false; - - LPoint2 p = to_2d(from_center - dist * plane.get_normal(), ip); - PN_stdfloat edge_dist = 0.0f; - - const ClipPlaneAttrib *cpa = entry.get_into_clip_planes(); - if (cpa != nullptr) { - // We have a clip plane; apply it. - Points new_points; - if (apply_clip_plane(new_points, cpa, entry.get_into_node_path().get_net_transform(),ip)) { - // All points are behind the clip plane; just do the default test. - edge_dist = dist_to_polygon(p, _points[ip], 4); - } else if (new_points.empty()) { - // The polygon is completely clipped. - continue; - } else { - // Test against the clipped polygon. - edge_dist = dist_to_polygon(p, new_points.data(), new_points.size()); - } - } else { - // No clip plane is in effect. Do the default test. - edge_dist = dist_to_polygon(p, _points[ip], 4); - } - - max_dist = from_radius; - // Now we have edge_dist, which is the distance from the sphere center to - // the nearest edge of the polygon, within the polygon's plane. - // edge_dist<0 means the point is within the polygon. - if(edge_dist < 0) { - intersect = true; - continue; - } - - if((edge_dist > 0) && - ((edge_dist * edge_dist + dist * dist) > from_radius_2)) { - // No intersection; the circle is outside the polygon. - continue; + // We must effectively do a capsule-into-box test. + LVector3 delta = center - prev_center; + if (!intersects_capsule(t, prev_center, delta, radius_sq)) { + return nullptr; } + contact_center = prev_center + delta * t; - // The sphere appears to intersect the polygon. If the edge is less than - // from_radius away, the sphere may be resting on an edge of the polygon. - // Determine how far the center of the sphere must remain from the plane, - // based on its distance from the nearest edge. - - if (edge_dist >= 0.0f) { - PN_stdfloat max_dist_2 = max(from_radius_2 - edge_dist * edge_dist, (PN_stdfloat)0.0); - max_dist = csqrt(max_dist_2); - } + // This is used to calculate the surface normal, which must always be + // opposed to the movement direction! + vec = (contact_center - _min).fmin(0) + (contact_center - _max).fmax(0); + if ((vec[0] > 0) == (delta[0] > 0)) vec[0] = 0; + if ((vec[1] > 0) == (delta[1] > 0)) vec[1] = 0; + if ((vec[2] > 0) == (delta[2] > 0)) vec[2] = 0; - if (dist > max_dist) { - // There's no intersection: the sphere is hanging off the edge. - continue; - } - intersect = true; + had_prev = true; } - if (!fully_inside && !intersect) { - return nullptr; + else if (vec_lsq == 0.0f) { + // It's completely inside. + vec = prev_center - _center; } if (collide_cat.is_debug()) { @@ -362,26 +293,44 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { PT(CollisionEntry) new_entry = new CollisionEntry(entry); - PN_stdfloat into_depth = max_dist - dist; - if (moved_from_center) { - // We have to base the depth of intersection on the sphere's final resting - // point, not the point from which we tested the intersection. - PN_stdfloat orig_dist; - plane.intersects_line(orig_dist, orig_center, -normal); - into_depth = max_dist - orig_dist; + int axis; + if (abs(vec[0]) > abs(vec[1])) { + if (abs(vec[0]) > abs(vec[2])) { + axis = 0; + } else { + axis = 2; + } + } else { + if (abs(vec[1]) > abs(vec[2])) { + axis = 1; + } else { + axis = 2; + } } - // Clamp the surface point to the box bounds. - LPoint3 surface = from_center - normal * dist; - surface = surface.fmax(_min); - surface = surface.fmin(_max); + LPoint3 surface_point = contact_center.fmax(_min).fmin(_max); + surface_point[axis] = vec[axis] > 0 ? _max[axis] : _min[axis]; + + LVector3 normal(0, 0, 0); + normal[axis] = (vec[axis] > 0) * 2 - 1; - new_entry->set_surface_normal(normal); - new_entry->set_surface_point(surface); - new_entry->set_interior_point(surface - normal * into_depth); - new_entry->set_contact_pos(contact_point); - new_entry->set_contact_normal(plane.get_normal()); - new_entry->set_t(actual_t); + LPoint3 interior_point = surface_point; + if (had_prev) { + interior_point += (center - contact_center); + } else { + LVector3 other = surface_point - contact_center; + other[axis] = 0.0f; + interior_point[axis] = center[axis] - std::copysign(std::max((PN_stdfloat)0, csqrt(radius_sq - other.length_squared())), vec[axis]); + } + + new_entry->set_interior_point(interior_point); + new_entry->set_surface_point(surface_point); + new_entry->set_surface_normal( + (has_effective_normal() && sphere->get_respect_effective_normal()) + ? get_effective_normal() : normal); + new_entry->set_contact_pos(contact_center); + new_entry->set_contact_normal(normal); + new_entry->set_t(t); return new_entry; } @@ -1088,327 +1037,61 @@ intersects_line(double &t1, double &t2, } /** - * Clips the polygon by all of the clip planes named in the clip plane - * attribute and fills new_points up with the resulting points. - * - * The return value is true if the set of points is unmodified (all points are - * behind all the clip planes), or false otherwise. + * Determine the first point of intersection of the given capsule with the box. */ bool CollisionBox:: -apply_clip_plane(CollisionBox::Points &new_points, - const ClipPlaneAttrib *cpa, - const TransformState *net_transform, int plane_no) const { - bool all_in = true; - - int num_planes = cpa->get_num_on_planes(); - bool first_plane = true; - - for (int i = 0; i < num_planes; i++) { - NodePath plane_path = cpa->get_on_plane(i); - PlaneNode *plane_node = DCAST(PlaneNode, plane_path.node()); - if ((plane_node->get_clip_effect() & PlaneNode::CE_collision) != 0) { - CPT(TransformState) new_transform = - net_transform->invert_compose(plane_path.get_net_transform()); - - LPlane plane = plane_node->get_plane() * new_transform->get_mat(); - if (first_plane) { - first_plane = false; - if (!clip_polygon(new_points, _points[plane_no], 4, plane, plane_no)) { - all_in = false; - } - } else { - Points last_points; - last_points.swap(new_points); - if (!clip_polygon(new_points, last_points.data(), last_points.size(), plane, plane_no)) { - all_in = false; - } - } - } - } - - if (!all_in) { - compute_vectors(new_points); - } - - return all_in; -} -/** - * Clips the source_points of the polygon by the indicated clipping plane, and - * modifies new_points to reflect the new set of clipped points (but does not - * compute the vectors in new_points). - * - * The return value is true if the set of points is unmodified (all points are - * behind the clip plane), or false otherwise. - */ -bool CollisionBox:: -clip_polygon(CollisionBox::Points &new_points, - const PointDef *source_points, size_t num_source_points, - const LPlane &plane, int plane_no) const { - new_points.clear(); - if (num_source_points == 0) { - return true; - } - - LPoint3 from3d; - LVector3 delta3d; - if (!plane.intersects_plane(from3d, delta3d, get_plane(plane_no))) { - // The clipping plane is parallel to the polygon. The polygon is either - // all in or all out. - if (plane.dist_to_plane(get_plane(plane_no).get_point()) < 0.0) { - // A point within the polygon is behind the clipping plane: the polygon - // is all in. - new_points.insert(new_points.end(), source_points, source_points + num_source_points); - return true; - } +intersects_capsule(double &t, const LPoint3 &from, const LVector3 &delta, + PN_stdfloat radius_sq) const { + // First, we check whether the line segment intersects with the box + // expanded by the sphere's radius. + double t2; + if (!intersects_line(t, t2, from, delta, csqrt(radius_sq)) || + t > 1.0 || t2 < 0.0) { return false; } - // Project the line of intersection into the 2-d plane. Now we have a 2-d - // clipping line. - LPoint2 from2d = to_2d(from3d,plane_no); - LVector2 delta2d = to_2d(delta3d,plane_no); - - PN_stdfloat a = -delta2d[1]; - PN_stdfloat b = delta2d[0]; - PN_stdfloat c = from2d[0] * delta2d[1] - from2d[1] * delta2d[0]; - - // Now walk through the points. Any point on the left of our line gets - // removed, and the line segment clipped at the point of intersection. - - // We might increase the number of vertices by as many as 1, if the plane - // clips off exactly one corner. (We might also decrease the number of - // vertices, or keep them the same number.) - new_points.reserve(num_source_points + 1); - - LPoint2 last_point = source_points[num_source_points - 1]._p; - bool last_is_in = !is_right(last_point - from2d, delta2d); - bool all_in = last_is_in; - for (size_t pi = 0; pi < num_source_points; ++pi) { - const LPoint2 &this_point = source_points[pi]._p; - bool this_is_in = !is_right(this_point - from2d, delta2d); - - // There appears to be a compiler bug in gcc 4.0: we need to extract this - // comparison outside of the if statement. - bool crossed_over = (this_is_in != last_is_in); - if (crossed_over) { - // We have just crossed over the clipping line. Find the point of - // intersection. - LVector2 d = this_point - last_point; - PN_stdfloat denom = (a * d[0] + b * d[1]); - if (denom != 0.0) { - PN_stdfloat t = -(a * last_point[0] + b * last_point[1] + c) / denom; - LPoint2 p = last_point + t * d; - - new_points.push_back(PointDef(p[0], p[1])); - last_is_in = this_is_in; - } + LPoint3 intersection = from + delta * t; + + // The following technique is derived from a book by Christer Ericson. + int u = 0, v = 0; + if (intersection[0] < _min[0]) u |= 4; + if (intersection[1] < _min[1]) u |= 2; + if (intersection[2] < _min[2]) u |= 1; + if (intersection[0] > _max[0]) v |= 4; + if (intersection[1] > _max[1]) v |= 2; + if (intersection[2] > _max[2]) v |= 1; + + int m = u | v; + if (m == 7) { + double tmin = DBL_MAX; + LPoint3 vertex = get_point_aabb(v); + if (intersect_segment_capsule(t, from, delta, vertex, + get_point_aabb(v ^ 4), radius_sq)) { + tmin = std::min(t, tmin); } - - if (this_is_in) { - // We are behind the clipping line. Keep the point. - new_points.push_back(PointDef(this_point[0], this_point[1])); - } else { - all_in = false; + if (intersect_segment_capsule(t, from, delta, vertex, + get_point_aabb(v ^ 2), radius_sq)) { + tmin = std::min(t, tmin); } - - last_point = this_point; - } - - return all_in; -} - -/** - * Returns the linear distance from the 2-d point to the nearest part of the - * polygon defined by the points vector. The result is negative if the point - * is within the polygon. - */ -PN_stdfloat CollisionBox:: -dist_to_polygon(const LPoint2 &p, const PointDef *points, size_t num_points) const { - // We know that that the polygon is convex and is defined with the points in - // counterclockwise order. Therefore, we simply compare the signed distance - // to each line segment; we ignore any negative values, and take the minimum - // of all the positive values. - - // If all values are negative, the point is within the polygon; we therefore - // return an arbitrary negative result. - - bool got_dist = false; - PN_stdfloat best_dist = -1.0f; - - for (size_t i = 0; i < num_points - 1; ++i) { - PN_stdfloat d = dist_to_line_segment(p, points[i]._p, points[i + 1]._p, - points[i]._v); - if (d >= 0.0f) { - if (!got_dist || d < best_dist) { - best_dist = d; - got_dist = true; - } + if (intersect_segment_capsule(t, from, delta, vertex, + get_point_aabb(v ^ 1), radius_sq)) { + tmin = std::min(t, tmin); } - } - - PN_stdfloat d = dist_to_line_segment(p, points[num_points - 1]._p, points[0]._p, - points[num_points - 1]._v); - if (d >= 0.0f) { - if (!got_dist || d < best_dist) { - best_dist = d; - //got_dist = true; - } - } - - return best_dist; -} - -/** - * Returns the linear distance of p to the line segment defined by f and t, - * where v = (t - f).normalize(). The result is negative if p is left of the - * line, positive if it is right of the line. If the result is positive, it - * is constrained by endpoints of the line segment (i.e. the result might be - * larger than it would be for a straight distance-to-line test). If the - * result is negative, we don't bother. - */ -PN_stdfloat CollisionBox:: -dist_to_line_segment(const LPoint2 &p, - const LPoint2 &f, const LPoint2 &t, - const LVector2 &v) { - LVector2 v1 = (p - f); - PN_stdfloat d = (v1[0] * v[1] - v1[1] * v[0]); - if (d < 0.0f) { - return d; - } - - // Compute the nearest point on the line. - LPoint2 q = p + LVector2(-v[1], v[0]) * d; - - // Now constrain that point to the line segment. - if (v[0] > 0.0f) { - // X+ - if (v[1] > 0.0f) { - // Y+ - if (v[0] > v[1]) { - // X-dominant. - if (q[0] < f[0]) { - return (p - f).length(); - } if (q[0] > t[0]) { - return (p - t).length(); - } else { - return d; - } - } else { - // Y-dominant. - if (q[1] < f[1]) { - return (p - f).length(); - } if (q[1] > t[1]) { - return (p - t).length(); - } else { - return d; - } - } - } else { - // Y- - if (v[0] > -v[1]) { - // X-dominant. - if (q[0] < f[0]) { - return (p - f).length(); - } if (q[0] > t[0]) { - return (p - t).length(); - } else { - return d; - } - } else { - // Y-dominant. - if (q[1] > f[1]) { - return (p - f).length(); - } if (q[1] < t[1]) { - return (p - t).length(); - } else { - return d; - } - } - } - } else { - // X- - if (v[1] > 0.0f) { - // Y+ - if (-v[0] > v[1]) { - // X-dominant. - if (q[0] > f[0]) { - return (p - f).length(); - } if (q[0] < t[0]) { - return (p - t).length(); - } else { - return d; - } - } else { - // Y-dominant. - if (q[1] < f[1]) { - return (p - f).length(); - } if (q[1] > t[1]) { - return (p - t).length(); - } else { - return d; - } - } - } else { - // Y- - if (-v[0] > -v[1]) { - // X-dominant. - if (q[0] > f[0]) { - return (p - f).length(); - } if (q[0] < t[0]) { - return (p - t).length(); - } else { - return d; - } - } else { - // Y-dominant. - if (q[1] > f[1]) { - return (p - f).length(); - } if (q[1] < t[1]) { - return (p - t).length(); - } else { - return d; - } - } - } - } -} - -/** - * Returns true if the indicated point is within the polygon's 2-d space, - * false otherwise. - */ -bool CollisionBox:: -point_is_inside(const LPoint2 &p, const CollisionBox::Points &points) const { - // We insist that the polygon be convex. This makes things a bit simpler. - // In the case of a convex polygon, defined with points in counterclockwise - // order, a point is interior to the polygon iff the point is not right of - // each of the edges. - for (int i = 0; i < (int)points.size() - 1; i++) { - if (is_right(p - points[i]._p, points[i+1]._p - points[i]._p)) { + if (tmin == DBL_MAX) { return false; } + t = tmin; } - if (is_right(p - points[points.size() - 1]._p, - points[0]._p - points[points.size() - 1]._p)) { - return false; + else if ((m & (m - 1)) != 0) { + // There's just one edge to test. + LPoint3 edge_v1 = get_point_aabb(u ^ 7); + LPoint3 edge_v2 = get_point_aabb(v); + return intersect_segment_capsule(t, from, delta, edge_v1, edge_v2, radius_sq); } return true; } -/** - * Now that the _p members of the given points array have been computed, go - * back and compute all of the _v members. - */ -void CollisionBox:: -compute_vectors(Points &points) { - size_t num_points = points.size(); - for (size_t i = 0; i < num_points; i++) { - points[i]._v = points[(i + 1) % num_points]._p - points[i]._p; - points[i]._v.normalize(); - } -} - /** * Factory method to generate a CollisionBox object */ @@ -1427,28 +1110,42 @@ write_datagram(BamWriter *manager, Datagram &me) { _center.write_datagram(me); _min.write_datagram(me); _max.write_datagram(me); - for(int i=0; i < 8; i++) { - _vertex[i].write_datagram(me); + for (int i = 0; i < 8; ++i) { + get_point_aabb(i).write_datagram(me); } - PN_stdfloat x = _vertex[0].get_x() - _center.get_x(); - PN_stdfloat y = _vertex[0].get_y() - _center.get_y(); - PN_stdfloat z = _vertex[0].get_z() - _center.get_z(); + LPoint3 vertex = get_point_aabb(0); + PN_stdfloat x = vertex.get_x() - _center.get_x(); + PN_stdfloat y = vertex.get_y() - _center.get_y(); + PN_stdfloat z = vertex.get_z() - _center.get_z(); PN_stdfloat radius = sqrt(x * x + y * y + z * z); me.add_stdfloat(radius); me.add_stdfloat(x); me.add_stdfloat(y); me.add_stdfloat(z); - for(int i=0; i < 6; i++) { + for (int i = 0; i < 6; ++i) { _planes[i].write_datagram(me); } - for(int i=0; i < 6; i++) { - _to_2d_mat[i].write_datagram(me); + LMatrix4 to_2d_mat[6]; + for (int i = 0; i < 6; ++i) { + LMatrix4 to_3d_mat; + look_at(to_3d_mat, -get_plane(i).get_normal(), + LVector3(0.0f, 0.0f, 1.0f), CS_zup_right); + to_3d_mat.set_row(3, get_plane(i).get_point()); + + to_2d_mat[i].invert_from(to_3d_mat); + to_2d_mat[i].write_datagram(me); } - for(int i=0; i < 6; i++) { + for (int i = 0; i < 6; ++i) { me.add_uint16(4); + LPoint2 points[4]; + for (size_t j = 0; j < 4; j++) { + points[j] = (get_point(plane_def[i][j]) * to_2d_mat[i]).get_xz(); + } for (size_t j = 0; j < 4; j++) { - _points[i][j]._p.write_datagram(me); - _points[i][j]._v.write_datagram(me); + LPoint2 vec = points[(i + 1) % 4] - points[i]; + vec.normalize(); + points[j].write_datagram(me); + vec.write_datagram(me); } } } @@ -1478,25 +1175,28 @@ fillin(DatagramIterator& scan, BamReader* manager) { _center.read_datagram(scan); _min.read_datagram(scan); _max.read_datagram(scan); - for(int i=0; i < 8; i++) { - _vertex[i].read_datagram(scan); + for (int i = 0; i < 8; ++i) { + LPoint3 vertex; + vertex.read_datagram(scan); } scan.get_stdfloat(); scan.get_stdfloat(); scan.get_stdfloat(); scan.get_stdfloat(); - for(int i=0; i < 6; i++) { + for (int i = 0; i < 6; ++i) { _planes[i].read_datagram(scan); } - for(int i=0; i < 6; i++) { - _to_2d_mat[i].read_datagram(scan); + for (int i = 0; i < 6; ++i) { + LMatrix4 to_2d_mat; + to_2d_mat.read_datagram(scan); } - for(int i=0; i < 6; i++) { + for (int i = 0; i < 6; ++i) { size_t size = scan.get_uint16(); - nassertv(size == 4); - for (size_t j = 0; j < size; j++) { - _points[i][j]._p.read_datagram(scan); - _points[i][j]._v.read_datagram(scan); + for (size_t j = 0; j < size; ++j) { + LPoint2 p; + LVector2 v; + p.read_datagram(scan); + v.read_datagram(scan); } } } diff --git a/panda/src/collide/collisionBox.h b/panda/src/collide/collisionBox.h index 1b2489b9fcb..95588a8acfb 100644 --- a/panda/src/collide/collisionBox.h +++ b/panda/src/collide/collisionBox.h @@ -49,7 +49,6 @@ class EXPCL_PANDA_COLLIDE CollisionBox : public CollisionSolid { virtual void output(std::ostream &out) const; INLINE static void flush_level(); - void setup_box(); PUBLISHED: INLINE int get_num_points() const; @@ -94,12 +93,14 @@ class EXPCL_PANDA_COLLIDE CollisionBox : public CollisionSolid { bool intersects_line(double &t1, double &t2, const LPoint3 &from, const LVector3 &delta, PN_stdfloat inflate_size=0) const; + bool intersects_capsule(double &t, + const LPoint3 &from, const LVector3 &delta, + PN_stdfloat radius_sq) const; private: LPoint3 _center; LPoint3 _min; LPoint3 _max; - LPoint3 _vertex[8]; // Each of the Eight Vertices of the Box LPlane _planes[6]; //Points to each of the six sides of the Box static const int plane_def[6][4]; @@ -107,49 +108,6 @@ class EXPCL_PANDA_COLLIDE CollisionBox : public CollisionSolid { static PStatCollector _volume_pcollector; static PStatCollector _test_pcollector; -private: - INLINE static bool is_right(const LVector2 &v1, const LVector2 &v2); - INLINE static PN_stdfloat dist_to_line(const LPoint2 &p, - const LPoint2 &f, const LVector2 &v); - static PN_stdfloat dist_to_line_segment(const LPoint2 &p, - const LPoint2 &f, const LPoint2 &t, - const LVector2 &v); - -public: - class PointDef { - public: - PointDef() = default; - INLINE PointDef(const LPoint2 &p, const LVector2 &v); - INLINE PointDef(PN_stdfloat x, PN_stdfloat y); - INLINE PointDef(const PointDef ©); - INLINE void operator = (const PointDef ©); - - LPoint2 _p; // the point in 2-d space - LVector2 _v; // the normalized vector to the next point - }; - typedef pvector Points; - - static void compute_vectors(Points &points); - void draw_polygon(GeomNode *viz_geom_node, GeomNode *bounds_viz_geom_node, - const Points &points) const; - - bool point_is_inside(const LPoint2 &p, const Points &points) const; - PN_stdfloat dist_to_polygon(const LPoint2 &p, const PointDef *points, size_t num_points) const; - - void setup_points(int plane); - INLINE LPoint2 to_2d(const LVecBase3 &point3d, int plane) const; - INLINE void calc_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const; - INLINE static LPoint3 to_3d(const LVecBase2 &point2d, const LMatrix4 &to_3d_mat); - bool clip_polygon(Points &new_points, const PointDef *source_points, - size_t num_source_points, const LPlane &plane, - int plane_no) const; - bool apply_clip_plane(Points &new_points, const ClipPlaneAttrib *cpa, - const TransformState *net_transform, int plane_no) const; - -private: - PointDef _points[6][4]; // one set of points for each of the six planes that make up the box - LMatrix4 _to_2d_mat[6]; - public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &me); diff --git a/panda/src/collide/collisionNode.I b/panda/src/collide/collisionNode.I index 51fe8002fbd..f429fccfb1a 100644 --- a/panda/src/collide/collisionNode.I +++ b/panda/src/collide/collisionNode.I @@ -166,3 +166,24 @@ INLINE CollideMask CollisionNode:: get_default_collide_mask() { return default_collision_node_collide_mask; } + +/** + * Returns the custom pointer set via set_owner(). + */ +INLINE void *CollisionNode:: +get_owner() const { + return _owner; +} + +/** + * Sets a custom pointer, together with an optional callback that will be + * called when the node is deleted. + * + * The owner or the callback will not be copied along with the CollisionNode. + */ +INLINE void CollisionNode:: +set_owner(void *owner, OwnerCallback *callback) { + clear_owner(); + _owner = owner; + _owner_callback = callback; +} diff --git a/panda/src/collide/collisionNode.cxx b/panda/src/collide/collisionNode.cxx index 2df893ef18d..60d28960ddb 100644 --- a/panda/src/collide/collisionNode.cxx +++ b/panda/src/collide/collisionNode.cxx @@ -40,7 +40,9 @@ CollisionNode:: CollisionNode(const std::string &name) : PandaNode(name), _from_collide_mask(get_default_collide_mask()), - _collider_sort(0) + _collider_sort(0), + _owner(nullptr), + _owner_callback(nullptr) { set_cull_callback(); set_renderable(); @@ -60,7 +62,9 @@ CollisionNode(const CollisionNode ©) : PandaNode(copy), _from_collide_mask(copy._from_collide_mask), _collider_sort(copy._collider_sort), - _solids(copy._solids) + _solids(copy._solids), + _owner(nullptr), + _owner_callback(nullptr) { } @@ -69,6 +73,10 @@ CollisionNode(const CollisionNode ©) : */ CollisionNode:: ~CollisionNode() { + if (_owner_callback != nullptr) { + _owner_callback(_owner); + _owner_callback = nullptr; + } } /** @@ -251,6 +259,18 @@ set_from_collide_mask(CollideMask mask) { _from_collide_mask = mask; } +/** + * Removes the owner that was previously set using set_owner(). + */ +void CollisionNode:: +clear_owner() { + if (_owner_callback != nullptr) { + _owner_callback(_owner); + } + _owner = nullptr; + _owner_callback = nullptr; +} + /** * Called when needed to recompute the node's _internal_bound object. Nodes * that contain anything of substance should redefine this to do the right diff --git a/panda/src/collide/collisionNode.h b/panda/src/collide/collisionNode.h index fee71fce78c..14941a53369 100644 --- a/panda/src/collide/collisionNode.h +++ b/panda/src/collide/collisionNode.h @@ -77,6 +77,22 @@ class EXPCL_PANDA_COLLIDE CollisionNode : public PandaNode { INLINE static CollideMask get_default_collide_mask(); MAKE_PROPERTY(default_collide_mask, get_default_collide_mask); +public: + typedef void (OwnerCallback)(void *); + + INLINE void *get_owner() const; + +#ifndef CPPPARSER + INLINE void set_owner(void *owner, OwnerCallback *callback = nullptr); + void clear_owner(); +#endif + + EXTENSION(PyObject *get_owner() const); + EXTENSION(void set_owner(PyObject *owner)); + +PUBLISHED: + MAKE_PROPERTY(owner, get_owner, set_owner); + protected: virtual void compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, int &internal_vertices, @@ -94,6 +110,9 @@ class EXPCL_PANDA_COLLIDE CollisionNode : public PandaNode { typedef pvector< COWPT(CollisionSolid) > Solids; Solids _solids; + void *_owner = nullptr; + OwnerCallback *_owner_callback = nullptr; + friend class CollisionTraverser; public: diff --git a/panda/src/collide/collisionNode_ext.cxx b/panda/src/collide/collisionNode_ext.cxx new file mode 100644 index 00000000000..8508cf5206f --- /dev/null +++ b/panda/src/collide/collisionNode_ext.cxx @@ -0,0 +1,62 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file collisionNode_ext.cxx + * @author rdb + * @date 2024-12-12 + */ + +#include "collisionNode_ext.h" + +#ifdef HAVE_PYTHON + +#include "collisionNode.h" + +/** + * Returns the object previously set via set_owner(). If the object has been + * destroyed, returns None. + */ +PyObject *Extension:: +get_owner() const { + PyObject *owner = (PyObject *)_this->get_owner(); + +#if PY_VERSION_HEX >= 0x030D0000 // 3.13 + PyObject *strong_ref; + int result = 0; + if (owner != nullptr) { + result = PyWeakref_GetRef(owner, &strong_ref); + } + if (result > 0) { + return strong_ref; + } + else if (result == 0) { + return Py_NewRef(Py_None); + } + else { + return nullptr; + } +#else + return Py_NewRef(owner != nullptr ? PyWeakref_GetObject(owner) : Py_None); +#endif +} + +/** + * Stores a weak reference to the given object on the CollisionNode, for later + * use in collision events and handlers. + */ +void Extension:: +set_owner(PyObject *owner) { + if (owner != Py_None) { + PyObject *ref = PyWeakref_NewRef(owner, nullptr); + _this->set_owner(ref, [](void *obj) { Py_DECREF((PyObject *)obj); }); + } else { + _this->clear_owner(); + } +} + +#endif diff --git a/panda/src/collide/collisionNode_ext.h b/panda/src/collide/collisionNode_ext.h new file mode 100644 index 00000000000..ea27e1bb7db --- /dev/null +++ b/panda/src/collide/collisionNode_ext.h @@ -0,0 +1,40 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file collisionNode_ext.h + * @author rdb + * @date 2024-12-12 + */ + +#ifndef COLLISIONNODE_EXT_H +#define COLLISIONNODE_EXT_H + +#include "pandabase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "collisionNode.h" +#include "py_panda.h" + +/** + * This class defines the extension methods for CollisionNode, which are called + * instead of any C++ methods with the same prototype. + * + * @since 1.11.0 + */ +template<> +class Extension : public ExtensionBase { +public: + PyObject *get_owner() const; + void set_owner(PyObject *owner); +}; + +#endif // HAVE_PYTHON + +#endif diff --git a/panda/src/collide/collisionPolygon_ext.cxx b/panda/src/collide/collisionPolygon_ext.cxx index 22ada8c3442..3f7d6503aa4 100644 --- a/panda/src/collide/collisionPolygon_ext.cxx +++ b/panda/src/collide/collisionPolygon_ext.cxx @@ -72,6 +72,9 @@ convert_points(pvector &vec, PyObject *points) { return false; } + bool success = true; + + Py_BEGIN_CRITICAL_SECTION(seq); PyObject **items = PySequence_Fast_ITEMS(seq); Py_ssize_t len = PySequence_Fast_GET_SIZE(seq); void *ptr; @@ -90,13 +93,14 @@ convert_points(pvector &vec, PyObject *points) { } else { Dtool_Raise_TypeError("Argument must be of LPoint3 type."); - Py_DECREF(seq); - return false; + success = false; + break; } } + Py_END_CRITICAL_SECTION(); Py_DECREF(seq); - return true; + return success; } #endif diff --git a/panda/src/collide/collisionSphere.cxx b/panda/src/collide/collisionSphere.cxx index b8323faa635..8f9dcb0ccb6 100644 --- a/panda/src/collide/collisionSphere.cxx +++ b/panda/src/collide/collisionSphere.cxx @@ -145,44 +145,48 @@ test_intersection_from_sphere(const CollisionEntry &entry) const { LPoint3 contact_point(into_intersection_point); PN_stdfloat actual_t = 0.0f; - LVector3 vec = from_b - into_center; - PN_stdfloat dist2 = dot(vec, vec); - if (dist2 > (into_radius + from_radius) * (into_radius + from_radius)) { - // No intersection with the current position. Check the delta from the - // previous frame. + LPoint3 from_a = from_b; + if (entry.get_respect_prev_transform()) { CPT(TransformState) wrt_prev_space = entry.get_wrt_prev_space(); - LPoint3 from_a = sphere->get_center() * wrt_prev_space->get_mat(); + if (wrt_prev_space != wrt_space) { + from_a = sphere->get_center() * wrt_prev_space->get_mat(); + } + } - if (!from_a.almost_equal(from_b)) { - LVector3 from_direction = from_b - from_a; - if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) { - // No intersection. - return nullptr; - } + if (from_a.almost_equal(from_b)) { + LVector3 vec = from_b - into_center; + PN_stdfloat dist2 = dot(vec, vec); - if (t2 < 0.0 || t1 > 1.0) { - // Both intersection points are before the start of the segment or - // after the end of the segment. - return nullptr; - } + if (dist2 > (into_radius + from_radius) * (into_radius + from_radius)) { + // No intersection with the current position. + return nullptr; + } + } else { + LVector3 from_direction = from_b - from_a; + if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) { + // No intersection. + return nullptr; + } - // doubles, not floats, to satisfy min and max templates. - actual_t = min(1.0, max(0.0, t1)); - contact_point = from_a + actual_t * (from_b - from_a); - - if (t1 < 0.0) { - // Point a is within the sphere. The first intersection point is - // point a itself. - into_intersection_point = from_a; - } else { - // Point a is outside the sphere, and point b is either inside the - // sphere or beyond it. The first intersection point is at t1. - into_intersection_point = from_a + t1 * from_direction; - } - } else { - // No delta, therefore no intersection. + if (t2 < 0.0 || t1 > 1.0) { + // Both intersection points are before the start of the segment or + // after the end of the segment. return nullptr; } + + // doubles, not floats, to satisfy min and max templates. + actual_t = min(1.0, max(0.0, t1)); + contact_point = from_a + actual_t * (from_b - from_a); + + if (t1 < 0.0) { + // Point a is within the sphere. The first intersection point is + // point a itself. + into_intersection_point = from_a; + } else { + // Point a is outside the sphere, and point b is either inside the + // sphere or beyond it. The first intersection point is at t1. + into_intersection_point = from_a + t1 * from_direction; + } } if (collide_cat.is_debug()) { diff --git a/panda/src/collide/collisionVisualizer.cxx b/panda/src/collide/collisionVisualizer.cxx index d8e70d11df6..29d713badb0 100644 --- a/panda/src/collide/collisionVisualizer.cxx +++ b/panda/src/collide/collisionVisualizer.cxx @@ -207,11 +207,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { PT(Geom) geom = new Geom(point_vdata); geom->add_primitive(points); - CullableObject *object = - new CullableObject(geom, point_state, - xform_data.get_internal_transform(trav)); - - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + geom, point_state, xform_data.get_internal_transform(trav)), trav); } // Draw the normal vector at the surface point. @@ -236,11 +233,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { PT(Geom) geom = new Geom(line_vdata); geom->add_primitive(lines); - CullableObject *object = - new CullableObject(geom, empty_state, - xform_data.get_internal_transform(trav)); - - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + geom, empty_state, xform_data.get_internal_transform(trav)), trav); } } } diff --git a/panda/src/collide/p3collide_ext_composite.cxx b/panda/src/collide/p3collide_ext_composite.cxx index 76e458c0f38..8e9f584c0c9 100644 --- a/panda/src/collide/p3collide_ext_composite.cxx +++ b/panda/src/collide/p3collide_ext_composite.cxx @@ -1,5 +1,6 @@ #include "collisionHandlerEvent_ext.cxx" #include "collisionHandlerPhysical_ext.cxx" #include "collisionHandlerQueue_ext.cxx" +#include "collisionNode_ext.cxx" #include "collisionPolygon_ext.cxx" #include "collisionTraverser_ext.cxx" diff --git a/panda/src/cull/binCullHandler.cxx b/panda/src/cull/binCullHandler.cxx index 53feb15bd42..be944a281df 100644 --- a/panda/src/cull/binCullHandler.cxx +++ b/panda/src/cull/binCullHandler.cxx @@ -19,6 +19,6 @@ * This is called as each Geom is discovered by the CullTraverser. */ void BinCullHandler:: -record_object(CullableObject *object, const CullTraverser *traverser) { - _cull_result->add_object(object, traverser); +record_object(CullableObject &&object, const CullTraverser *traverser) { + _cull_result->add_object(std::move(object), traverser); } diff --git a/panda/src/cull/binCullHandler.h b/panda/src/cull/binCullHandler.h index afe73103ed0..73d88824c39 100644 --- a/panda/src/cull/binCullHandler.h +++ b/panda/src/cull/binCullHandler.h @@ -28,7 +28,7 @@ class EXPCL_PANDA_CULL BinCullHandler : public CullHandler { public: INLINE BinCullHandler(CullResult *cull_result); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); private: diff --git a/panda/src/cull/cullBinBackToFront.cxx b/panda/src/cull/cullBinBackToFront.cxx index 99f006b4058..0254c4dfdd0 100644 --- a/panda/src/cull/cullBinBackToFront.cxx +++ b/panda/src/cull/cullBinBackToFront.cxx @@ -23,18 +23,6 @@ TypeHandle CullBinBackToFront::_type_handle; -/** - * - */ -CullBinBackToFront:: -~CullBinBackToFront() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ @@ -52,7 +40,7 @@ add_object(CullableObject *object, Thread *current_thread) { // Determine the center of the bounding volume. CPT(BoundingVolume) volume = object->_geom->get_bounds(current_thread); if (volume->is_empty()) { - delete object; + // No point in culling objects with no volume. return; } diff --git a/panda/src/cull/cullBinBackToFront.h b/panda/src/cull/cullBinBackToFront.h index cfef2f42676..b950bddc282 100644 --- a/panda/src/cull/cullBinBackToFront.h +++ b/panda/src/cull/cullBinBackToFront.h @@ -33,7 +33,6 @@ class EXPCL_PANDA_CULL CullBinBackToFront : public CullBin { INLINE CullBinBackToFront(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinBackToFront(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinFixed.cxx b/panda/src/cull/cullBinFixed.cxx index 7d4a4150c2a..9d8ff46dcb0 100644 --- a/panda/src/cull/cullBinFixed.cxx +++ b/panda/src/cull/cullBinFixed.cxx @@ -23,18 +23,6 @@ TypeHandle CullBinFixed::_type_handle; -/** - * - */ -CullBinFixed:: -~CullBinFixed() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinFixed.h b/panda/src/cull/cullBinFixed.h index 337283e2b33..fdaece45914 100644 --- a/panda/src/cull/cullBinFixed.h +++ b/panda/src/cull/cullBinFixed.h @@ -35,7 +35,6 @@ class EXPCL_PANDA_CULL CullBinFixed : public CullBin { INLINE CullBinFixed(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinFixed(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinFrontToBack.cxx b/panda/src/cull/cullBinFrontToBack.cxx index 8ddc16745d9..dfc85dd5403 100644 --- a/panda/src/cull/cullBinFrontToBack.cxx +++ b/panda/src/cull/cullBinFrontToBack.cxx @@ -23,18 +23,6 @@ TypeHandle CullBinFrontToBack::_type_handle; -/** - * - */ -CullBinFrontToBack:: -~CullBinFrontToBack() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ @@ -52,7 +40,7 @@ add_object(CullableObject *object, Thread *current_thread) { // Determine the center of the bounding volume. CPT(BoundingVolume) volume = object->_geom->get_bounds(); if (volume->is_empty()) { - delete object; + // No point in culling objects with no volume. return; } diff --git a/panda/src/cull/cullBinFrontToBack.h b/panda/src/cull/cullBinFrontToBack.h index b9ba66c043a..15c1f80ccf4 100644 --- a/panda/src/cull/cullBinFrontToBack.h +++ b/panda/src/cull/cullBinFrontToBack.h @@ -34,7 +34,6 @@ class EXPCL_PANDA_CULL CullBinFrontToBack : public CullBin { INLINE CullBinFrontToBack(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinFrontToBack(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinStateSorted.cxx b/panda/src/cull/cullBinStateSorted.cxx index 55c06075262..3d08802a48f 100644 --- a/panda/src/cull/cullBinStateSorted.cxx +++ b/panda/src/cull/cullBinStateSorted.cxx @@ -22,18 +22,6 @@ TypeHandle CullBinStateSorted::_type_handle; -/** - * - */ -CullBinStateSorted:: -~CullBinStateSorted() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi)._object; - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinStateSorted.h b/panda/src/cull/cullBinStateSorted.h index f97e41fa487..2e6486e3485 100644 --- a/panda/src/cull/cullBinStateSorted.h +++ b/panda/src/cull/cullBinStateSorted.h @@ -37,7 +37,6 @@ class EXPCL_PANDA_CULL CullBinStateSorted : public CullBin { INLINE CullBinStateSorted(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - virtual ~CullBinStateSorted(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/cullBinUnsorted.cxx b/panda/src/cull/cullBinUnsorted.cxx index c633913a03f..768ce35abfd 100644 --- a/panda/src/cull/cullBinUnsorted.cxx +++ b/panda/src/cull/cullBinUnsorted.cxx @@ -19,18 +19,6 @@ TypeHandle CullBinUnsorted::_type_handle; -/** - * - */ -CullBinUnsorted:: -~CullBinUnsorted() { - Objects::iterator oi; - for (oi = _objects.begin(); oi != _objects.end(); ++oi) { - CullableObject *object = (*oi); - delete object; - } -} - /** * Factory constructor for passing to the CullBinManager. */ diff --git a/panda/src/cull/cullBinUnsorted.h b/panda/src/cull/cullBinUnsorted.h index 2dcf60a85ff..bd31ea0a387 100644 --- a/panda/src/cull/cullBinUnsorted.h +++ b/panda/src/cull/cullBinUnsorted.h @@ -29,7 +29,6 @@ class EXPCL_PANDA_CULL CullBinUnsorted : public CullBin { INLINE CullBinUnsorted(const std::string &name, GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); - ~CullBinUnsorted(); static CullBin *make_bin(const std::string &name, GraphicsStateGuardianBase *gsg, diff --git a/panda/src/cull/drawCullHandler.cxx b/panda/src/cull/drawCullHandler.cxx index 78e27a00865..ac7ebf947fd 100644 --- a/panda/src/cull/drawCullHandler.cxx +++ b/panda/src/cull/drawCullHandler.cxx @@ -25,17 +25,14 @@ * This is called as each Geom is discovered by the CullTraverser. */ void DrawCullHandler:: -record_object(CullableObject *object, const CullTraverser *traverser) { +record_object(CullableObject &&object, const CullTraverser *traverser) { // Munge vertices as needed for the GSG's requirements, and the object's // current state. bool force = !_gsg->get_effective_incomplete_render(); Thread *current_thread = traverser->get_current_thread(); - if (object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser, force)) { + if (object.munge_geom(_gsg, _gsg->get_geom_munger(object._state, current_thread), traverser, force)) { // Now we can immediately draw the object. - draw(object, _gsg, force, current_thread); + draw(&object, _gsg, force, current_thread); } - - // Dispense with the object. - delete object; } diff --git a/panda/src/cull/drawCullHandler.h b/panda/src/cull/drawCullHandler.h index 5d8b5d3e411..127f1ee8495 100644 --- a/panda/src/cull/drawCullHandler.h +++ b/panda/src/cull/drawCullHandler.h @@ -31,7 +31,7 @@ class EXPCL_PANDA_CULL DrawCullHandler : public CullHandler { public: INLINE DrawCullHandler(GraphicsStateGuardianBase *gsg); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); private: diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index 84c852d472d..df0e7a7292b 100644 --- a/panda/src/display/displayRegion.cxx +++ b/panda/src/display/displayRegion.cxx @@ -487,7 +487,9 @@ get_screenshot() { if (gsg->get_threading_model().get_draw_stage() != current_thread->get_pipeline_stage()) { // Ask the engine to do on the draw thread. GraphicsEngine *engine = window->get_engine(); - return engine->do_get_screenshot(this, gsg); + return engine->run_on_draw_thread([this] { + return get_screenshot(); + }); } // We are on the draw thread. diff --git a/panda/src/display/frameBufferProperties.cxx b/panda/src/display/frameBufferProperties.cxx index c6e1e9353f0..4f27007cbc8 100644 --- a/panda/src/display/frameBufferProperties.cxx +++ b/panda/src/display/frameBufferProperties.cxx @@ -305,11 +305,12 @@ int FrameBufferProperties:: get_buffer_mask() const { int mask = 0; - if (_property[FBP_back_buffers] > 0) { - mask = RenderBuffer::T_front | RenderBuffer::T_back; - } else { - mask = RenderBuffer::T_front; - } + //XXX rdb: some buffers only have a front buffer, some only a back buffer + //if (_property[FBP_back_buffers] > 0) { + mask = RenderBuffer::T_front | RenderBuffer::T_back; + //} else { + // mask = RenderBuffer::T_front; + //} if (_property[FBP_depth_bits] > 0) { mask |= RenderBuffer::T_depth; } diff --git a/panda/src/display/frameBufferProperties_ext.cxx b/panda/src/display/frameBufferProperties_ext.cxx index 96ed9d3afea..423d66d7489 100644 --- a/panda/src/display/frameBufferProperties_ext.cxx +++ b/panda/src/display/frameBufferProperties_ext.cxx @@ -52,13 +52,14 @@ __setstate__(PyObject *self, PyObject *props) { PyObject *key, *value; Py_ssize_t pos = 0; + Py_BEGIN_CRITICAL_SECTION(props); while (PyDict_Next(props, &pos, &key, &value)) { // Look for a writable property on the type by this name. PyObject *descr = _PyType_Lookup(type, key); if (descr != nullptr && Py_TYPE(descr)->tp_descr_set != nullptr) { if (Py_TYPE(descr)->tp_descr_set(descr, self, value) < 0) { - return; + break; } } else { PyObject *key_repr = PyObject_Repr(key); @@ -67,9 +68,10 @@ __setstate__(PyObject *self, PyObject *props) { PyUnicode_AsUTF8(key_repr) ); Py_DECREF(key_repr); - return; + break; } } + Py_END_CRITICAL_SECTION(); } #endif // HAVE_PYTHON diff --git a/panda/src/display/graphicsEngine.I b/panda/src/display/graphicsEngine.I index d0a4769a214..ca9142a8a81 100644 --- a/panda/src/display/graphicsEngine.I +++ b/panda/src/display/graphicsEngine.I @@ -162,3 +162,62 @@ make_parasite(GraphicsOutput *host, const std::string &name, host->get_gsg(), host); return result; } + +/** + * Version of dispatch_compute that takes a ShaderAttrib instead of a full + * RenderState. + */ +INLINE void GraphicsEngine:: +dispatch_compute(const LVecBase3i &work_groups, const ShaderAttrib *sattr, GraphicsStateGuardian *gsg) { + dispatch_compute(work_groups, RenderState::make(sattr), gsg); +} + +#ifndef CPPPARSER +/** + * Waits for the draw thread to become idle, then runs the given function on it. + */ +template +INLINE auto GraphicsEngine:: +run_on_draw_thread(Callable &&callable) -> decltype(callable()) { + ReMutexHolder holder(_lock); + std::string draw_name = _threading_model.get_draw_name(); + if (draw_name.empty()) { + return std::move(callable)(); + } else { + WindowRenderer *wr = get_window_renderer(draw_name, 0); + RenderThread *thread = (RenderThread *)wr; + return thread->run_on_thread(std::move(callable)); + } +} + +/** + * Waits for this thread to become idle, then runs the given function on it. + */ +template +INLINE auto GraphicsEngine::RenderThread:: +run_on_thread(Callable &&callable) -> + typename std::enable_if::value, decltype(callable())>::type { + + using ReturnType = decltype(callable()); + alignas(ReturnType) unsigned char storage[sizeof(ReturnType)]; + + run_on_thread([] (RenderThread *data) { + new (data->_return_data) ReturnType(std::move(*(Callable *)data->_callback_data)()); + }, &callable, storage); + + return *(ReturnType *)storage; +} + +/** + * Waits for this thread to become idle, then runs the given function on it. + */ +template +INLINE auto GraphicsEngine::RenderThread:: +run_on_thread(Callable &&callable) -> + typename std::enable_if::value, decltype(callable())>::type { + + run_on_thread([] (RenderThread *data) { + std::move(*(Callable *)data->_callback_data)(); + }, &callable, nullptr); +} +#endif // CPPPARSER diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 0a346e8473b..474f8e29347 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -63,6 +63,13 @@ #include #endif +#ifdef __APPLE__ +extern "C" { + void *objc_autoreleasePoolPush(); + void objc_autoreleasePoolPop(void *); +}; +#endif + using std::string; PT(GraphicsEngine) GraphicsEngine::_global_ptr; @@ -145,8 +152,9 @@ INLINE static bool operator < (const CullKey &a, const CullKey &b) { * any Pipeline you choose. */ GraphicsEngine:: -GraphicsEngine(Pipeline *pipeline) : +GraphicsEngine(ClockObject *clock, Pipeline *pipeline) : _pipeline(pipeline), + _clock(clock), _app("app"), _lock("GraphicsEngine::_lock"), _loaded_textures_lock("GraphicsEngine::_loaded_textures_lock") @@ -332,7 +340,7 @@ make_output(GraphicsPipe *pipe, nassertr(pipe != nullptr, nullptr); if (gsg != nullptr) { nassertr(pipe == gsg->get_pipe(), nullptr); - nassertr(this == gsg->get_engine(), nullptr); + //nassertr(this == gsg->get_engine(), nullptr); } // Are we really asking for a callback window? @@ -722,11 +730,9 @@ render_frame() { // been rendered). open_windows(); - ClockObject *global_clock = ClockObject::get_global_clock(); - if (display_cat.is_spam()) { display_cat.spam() - << "render_frame() - frame " << global_clock->get_frame_count() << "\n"; + << "render_frame() - frame " << _clock->get_frame_count() << "\n"; } { @@ -839,8 +845,8 @@ render_frame() { } #endif // THREADED_PIPELINE - global_clock->tick(current_thread); - if (global_clock->check_errors(current_thread)) { + _clock->tick(current_thread); + if (_clock->check_errors(current_thread)) { throw_event("clock_error"); } @@ -1128,47 +1134,30 @@ flip_frame() { */ bool GraphicsEngine:: extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) { - ReMutexHolder holder(_lock); - - string draw_name = gsg->get_threading_model().get_draw_name(); - if (draw_name.empty()) { - // A single-threaded environment. No problem. + return run_on_draw_thread([=] () { return gsg->extract_texture_data(tex); + }); +} - } else { - // A multi-threaded environment. We have to wait until the draw thread - // has finished its current task. - WindowRenderer *wr = get_window_renderer(draw_name, 0); - RenderThread *thread = (RenderThread *)wr; - MutexHolder cv_holder(thread->_cv_mutex); - - while (thread->_thread_state != TS_wait) { - thread->_cv_done.wait(); - } - - // Temporarily set this so that it accesses data from the current thread. - int pipeline_stage = Thread::get_current_pipeline_stage(); - int draw_pipeline_stage = thread->get_pipeline_stage(); - thread->set_pipeline_stage(pipeline_stage); - - // Now that the draw thread is idle, signal it to do the extraction task. - thread->_gsg = gsg; - thread->_texture = tex; - thread->_thread_state = TS_do_extract; - thread->_cv_mutex.release(); - thread->_cv_start.notify(); - thread->_cv_mutex.acquire(); - - // Wait for it to finish the extraction. - while (thread->_thread_state != TS_wait) { - thread->_cv_done.wait(); +/** + * Asks the indicated GraphicsStateGuardian to retrieve the buffer memory + * image of the indicated ShaderBuffer and return it. + * + * This is mainly useful for debugging. It is a very slow call because it + * introduces a pipeline stall both of Panda's pipeline and the graphics + * pipeline. + * + * The return value is empty if some kind of error occurred. + */ +vector_uchar GraphicsEngine:: +extract_shader_buffer_data(ShaderBuffer *buffer, GraphicsStateGuardian *gsg) { + return run_on_draw_thread([=] () { + vector_uchar data; + if (!gsg->extract_shader_buffer_data(buffer, data)) { + data.clear(); } - - thread->set_pipeline_stage(draw_pipeline_stage); - thread->_gsg = nullptr; - thread->_texture = nullptr; - return thread->_result; - } + return data; + }); } /** @@ -1185,57 +1174,20 @@ extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) { * The return value is true if the operation is successful, false otherwise. */ void GraphicsEngine:: -dispatch_compute(const LVecBase3i &work_groups, const ShaderAttrib *sattr, GraphicsStateGuardian *gsg) { +dispatch_compute(const LVecBase3i &work_groups, const RenderState *state, GraphicsStateGuardian *gsg) { + const ShaderAttrib *sattr; + DCAST_INTO_V(sattr, state->get_attrib(ShaderAttrib::get_class_slot())); + const Shader *shader = sattr->get_shader(); nassertv(shader != nullptr); nassertv(gsg != nullptr); - ReMutexHolder holder(_lock); - - CPT(RenderState) state = RenderState::make(sattr); - - string draw_name = gsg->get_threading_model().get_draw_name(); - if (draw_name.empty()) { - // A single-threaded environment. No problem. + run_on_draw_thread([=] () { gsg->push_group_marker(std::string("Compute ") + shader->get_filename(Shader::ST_compute).get_basename()); gsg->set_state_and_transform(state, TransformState::make_identity()); gsg->dispatch_compute(work_groups[0], work_groups[1], work_groups[2]); gsg->pop_group_marker(); - - } else { - // A multi-threaded environment. We have to wait until the draw thread - // has finished its current task. - WindowRenderer *wr = get_window_renderer(draw_name, 0); - RenderThread *thread = (RenderThread *)wr; - MutexHolder cv_holder(thread->_cv_mutex); - - while (thread->_thread_state != TS_wait) { - thread->_cv_done.wait(); - } - - // Temporarily set this so that it accesses data from the current thread. - int pipeline_stage = Thread::get_current_pipeline_stage(); - int draw_pipeline_stage = thread->get_pipeline_stage(); - thread->set_pipeline_stage(pipeline_stage); - - // Now that the draw thread is idle, signal it to do the compute task. - thread->_gsg = gsg; - thread->_state = state.p(); - thread->_work_groups = work_groups; - thread->_thread_state = TS_do_compute; - thread->_cv_mutex.release(); - thread->_cv_start.notify(); - thread->_cv_mutex.acquire(); - - // Wait for it to finish the compute task. - while (thread->_thread_state != TS_wait) { - thread->_cv_done.wait(); - } - - thread->set_pipeline_stage(draw_pipeline_stage); - thread->_gsg = nullptr; - thread->_state = nullptr; - } + }); } /** @@ -1271,43 +1223,6 @@ texture_uploaded(Texture *tex) { // Usually only called by DisplayRegion::do_cull. } -/** - * Called by DisplayRegion::do_get_screenshot - */ -PT(Texture) GraphicsEngine:: -do_get_screenshot(DisplayRegion *region, GraphicsStateGuardian *gsg) { - // A multi-threaded environment. We have to wait until the draw thread - // has finished its current task. - - ReMutexHolder holder(_lock); - - const std::string &draw_name = gsg->get_threading_model().get_draw_name(); - WindowRenderer *wr = get_window_renderer(draw_name, 0); - RenderThread *thread = (RenderThread *)wr; - MutexHolder cv_holder(thread->_cv_mutex); - - while (thread->_thread_state != TS_wait) { - thread->_cv_done.wait(); - } - - // Now that the draw thread is idle, signal it to do the extraction task. - thread->_region = region; - thread->_thread_state = TS_do_screenshot; - thread->_cv_mutex.release(); - thread->_cv_start.notify(); - thread->_cv_mutex.acquire(); - - // Wait for it to finish the extraction. - while (thread->_thread_state != TS_wait) { - thread->_cv_done.wait(); - } - - PT(Texture) tex = std::move(thread->_texture); - thread->_region = nullptr; - thread->_texture = nullptr; - return tex; -} - /** * Fires off a cull traversal using the indicated camera. */ @@ -2585,6 +2500,11 @@ void GraphicsEngine::WindowRenderer:: do_frame(GraphicsEngine *engine, Thread *current_thread) { LightReMutexHolder holder(_wl_lock); +#ifdef __APPLE__ + // Enclose the entire frame in an autorelease pool. + void *pool = objc_autoreleasePoolPush(); +#endif + if (!_cull.empty()) { engine->cull_to_bins(_cull, current_thread); } @@ -2598,6 +2518,10 @@ do_frame(GraphicsEngine *engine, Thread *current_thread) { engine->process_events(_window, current_thread); } +#ifdef __APPLE__ + objc_autoreleasePoolPop(pool); +#endif + // If any GSG's on the list have no more outstanding pointers, clean them // up. (We are in the draw thread for all of these GSG's.) if (any_done_gsgs()) { @@ -2629,10 +2553,18 @@ void GraphicsEngine::WindowRenderer:: do_windows(GraphicsEngine *engine, Thread *current_thread) { LightReMutexHolder holder(_wl_lock); +#ifdef __APPLE__ + void *pool = objc_autoreleasePoolPush(); +#endif + engine->process_events(_window, current_thread); engine->make_contexts(_cdraw, current_thread); engine->make_contexts(_draw, current_thread); + +#ifdef __APPLE__ + objc_autoreleasePoolPop(pool); +#endif } /** @@ -2779,26 +2711,9 @@ thread_main() { do_pending(_engine, current_thread); break; - case TS_do_compute: - nassertd(_gsg != nullptr && _state != nullptr) break; - { - const ShaderAttrib *sattr; - _state->get_attrib(sattr); - _gsg->push_group_marker(std::string("Compute ") + sattr->get_shader()->get_filename(Shader::ST_compute).get_basename()); - _gsg->set_state_and_transform(_state, TransformState::make_identity()); - _gsg->dispatch_compute(_work_groups[0], _work_groups[1], _work_groups[2]); - _gsg->pop_group_marker(); - } - break; - - case TS_do_extract: - nassertd(_gsg != nullptr && _texture != nullptr) break; - _result = _gsg->extract_texture_data(_texture); - break; - - case TS_do_screenshot: - nassertd(_region != nullptr) break; - _texture = _region->get_screenshot(); + case TS_callback: + nassertd(_callback != nullptr) break; + _callback(this); break; case TS_terminate: @@ -2823,3 +2738,39 @@ thread_main() { } } } + +/** + * Waits for this thread to become idle, then runs the given function on it. + */ +void GraphicsEngine::RenderThread:: +run_on_thread(Callback *callback, void *callback_data, void *return_data) { + MutexHolder cv_holder(_cv_mutex); + + while (_thread_state != TS_wait) { + _cv_done.wait(); + } + + // Temporarily set this so that it accesses data from the current thread. + int pipeline_stage = Thread::get_current_pipeline_stage(); + int thread_pipeline_stage = get_pipeline_stage(); + set_pipeline_stage(pipeline_stage); + + // Now that the draw thread is idle, signal it to run the callback. + _callback = callback; + _callback_data = callback_data; + _return_data = return_data; + _thread_state = TS_callback; + _cv_mutex.release(); + _cv_start.notify(); + _cv_mutex.acquire(); + + // Wait for it to finish the job. + while (_thread_state != TS_wait) { + _cv_done.wait(); + } + + set_pipeline_stage(thread_pipeline_stage); + _callback = nullptr; + _callback_data = nullptr; + _return_data = nullptr; +} diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index 0614e47b791..88874f8e509 100644 --- a/panda/src/display/graphicsEngine.h +++ b/panda/src/display/graphicsEngine.h @@ -32,6 +32,10 @@ #include "indirectLess.h" #include "loader.h" #include "referenceCount.h" +#include "renderState.h" +#include "clockObject.h" + +#include class Pipeline; class DisplayRegion; @@ -52,7 +56,8 @@ class Texture; */ class EXPCL_PANDA_DISPLAY GraphicsEngine : public ReferenceCount { PUBLISHED: - explicit GraphicsEngine(Pipeline *pipeline = nullptr); + explicit GraphicsEngine(ClockObject *clock = ClockObject::get_global_clock(), + Pipeline *pipeline = nullptr); BLOCKING ~GraphicsEngine(); void set_threading_model(const GraphicsThreadingModel &threading_model); @@ -110,9 +115,13 @@ class EXPCL_PANDA_DISPLAY GraphicsEngine : public ReferenceCount { BLOCKING void flip_frame(); bool extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg); + vector_uchar extract_shader_buffer_data(ShaderBuffer *buffer, GraphicsStateGuardian *gsg); void dispatch_compute(const LVecBase3i &work_groups, - const ShaderAttrib *sattr, + const RenderState *state, GraphicsStateGuardian *gsg); + INLINE void dispatch_compute(const LVecBase3i &work_groups, + const ShaderAttrib *sattr, + GraphicsStateGuardian *gsg); static GraphicsEngine *get_global_ptr(); @@ -123,15 +132,17 @@ class EXPCL_PANDA_DISPLAY GraphicsEngine : public ReferenceCount { TS_do_flip, TS_do_release, TS_do_windows, - TS_do_compute, - TS_do_extract, - TS_do_screenshot, + TS_callback, TS_terminate, TS_done }; void texture_uploaded(Texture *tex); - PT(Texture) do_get_screenshot(DisplayRegion *region, GraphicsStateGuardian *gsg); + +#ifndef CPPPARSER + template + INLINE auto run_on_draw_thread(Callable &&callable) -> decltype(callable()); +#endif public: static void do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, @@ -298,24 +309,37 @@ class EXPCL_PANDA_DISPLAY GraphicsEngine : public ReferenceCount { RenderThread(const std::string &name, GraphicsEngine *engine); virtual void thread_main(); + typedef void Callback(RenderThread *thread); + void run_on_thread(Callback *callback, + void *callback_data = nullptr, + void *return_data = nullptr); + +#ifndef CPPPARSER + template + INLINE auto run_on_thread(Callable &&callable) -> + typename std::enable_if::value, decltype(callable())>::type; + + template + INLINE auto run_on_thread(Callable &&callable) -> + typename std::enable_if::value, decltype(callable())>::type; +#endif + GraphicsEngine *_engine; Mutex _cv_mutex; ConditionVar _cv_start; ConditionVar _cv_done; ThreadState _thread_state; - // These are stored for extract_texture_data and dispatch_compute. - GraphicsStateGuardian *_gsg; - PT(Texture) _texture; - const RenderState *_state; - DisplayRegion *_region; - LVecBase3i _work_groups; - bool _result; + // Used for TS_callback. + Callback *_callback; + void *_callback_data; + void *_return_data; }; WindowRenderer *get_window_renderer(const std::string &name, int pipeline_stage); Pipeline *_pipeline; + ClockObject *const _clock; Windows _windows; bool _windows_sorted; diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 09dd8c60b4a..b7ff6eb2dba 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -596,7 +596,7 @@ get_supports_tessellation_shaders() const { */ INLINE bool GraphicsStateGuardian:: get_supports_compute_shaders() const { - return _supports_compute_shaders; + return _max_compute_work_group_invocations > 0; } /** @@ -709,6 +709,45 @@ get_supports_dual_source_blending() const { return _supports_dual_source_blending; } +/** + * Returns the maximum number of work groups that can be submitted in a single + * compute dispatch. + * + * If compute shaders are supported, this will be at least 65535x65535x65535. + * Otherwise, it will be zero. + */ +INLINE LVecBase3i GraphicsStateGuardian:: +get_max_compute_work_group_count() const { + return _max_compute_work_group_count; +} + +/** + * Returns the maximum number of invocations in each work group split out + * separately to every x, y, z dimension. This limit applies in addition to + * the overall number of invocations, which is specified by + * get_max_compute_work_group_invocations(). + * + * If compute shaders are supported, this will be at least 128x128x64. + * Otherwise, it will be zero. + */ +INLINE LVecBase3i GraphicsStateGuardian:: +get_max_compute_work_group_size() const { + return _max_compute_work_group_size; +} + +/** + * Returns the maximum number of invocations in each work group as a product + * of the x, y, z dimensions. This limit applies in addition to the + * per-dimension limits specified by get_max_compute_work_group_size(). + * + * If compute shaders are supported, this will be at least 128. Otherwise, it + * will be zero. + */ +INLINE int GraphicsStateGuardian:: +get_max_compute_work_group_invocations() const { + return _max_compute_work_group_invocations; +} + /** * Deprecated. Use get_max_color_targets() instead, which returns the exact * same value. diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index d90cb6ac081..d94c7b59727 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -100,6 +100,7 @@ PStatCollector GraphicsStateGuardian::_draw_primitive_pcollector("Draw:Primitive PStatCollector GraphicsStateGuardian::_draw_set_state_pcollector("Draw:Set State"); PStatCollector GraphicsStateGuardian::_flush_pcollector("Draw:Flush"); PStatCollector GraphicsStateGuardian::_compute_dispatch_pcollector("Draw:Compute dispatch"); +PStatCollector GraphicsStateGuardian::_compute_work_groups_pcollector("Compute work groups"); PStatCollector GraphicsStateGuardian::_wait_occlusion_pcollector("Wait:Occlusion"); PStatCollector GraphicsStateGuardian::_wait_timer_pcollector("Wait:Timer Queries"); @@ -244,10 +245,13 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system, _supports_basic_shaders = false; _supports_geometry_shaders = false; _supports_tessellation_shaders = false; - _supports_compute_shaders = false; _supports_glsl = false; _supports_hlsl = false; + _max_compute_work_group_count = LVecBase3i(0, 0, 0); + _max_compute_work_group_size = LVecBase3i(0, 0, 0); + _max_compute_work_group_invocations = 0; + _supports_stencil = false; _supports_stencil_wrap = false; _supports_two_sided_stencil = false; @@ -572,6 +576,23 @@ update_texture(TextureContext *, bool) { return true; } +/** + * Ensures that the current Texture data is refreshed onto the GSG. This + * means updating the texture properties and/or re-uploading the texture + * image, if necessary. This should only be called within the draw thread. + * + * If force is true, this function will not return until the texture has been + * fully uploaded. If force is false, the function may choose to upload a + * simple version of the texture instead, if the texture is not fully resident + * (and if get_incomplete_render() is true). + */ +bool GraphicsStateGuardian:: +update_texture(TextureContext *tc, bool force, CompletionToken token) { + bool result = update_texture(tc, force); + token.complete(result); + return result; +} + /** * Frees the resources previously allocated via a call to prepare_texture(), * including deleting the TextureContext itself, if it is non-NULL. @@ -745,6 +766,18 @@ release_shader_buffers(const pvector &contexts) { } } +/** + * This method should only be called by the GraphicsEngine. Do not call it + * directly; call GraphicsEngine::extract_texture_data() instead. + * + * This method will be called in the draw thread to download the buffer's + * current contents synchronously. + */ +bool GraphicsStateGuardian:: +extract_shader_buffer_data(ShaderBuffer *buffer, vector_uchar &data) { + return false; +} + /** * Begins a new occlusion query. After this call, you may call * begin_draw_primitives() and draw_triangles()/draw_whatever() repeatedly. @@ -904,8 +937,10 @@ update_shader_matrix_cache(Shader *shader, LVecBase4f *cache, int altered) { /** * The gsg contains a large number of useful matrices: * - * * the world transform, * the modelview matrix, * the cs_transform, * etc, - * etc. + * - the world transform, + * - the modelview matrix, + * - the cs_transform, + * - etc, etc. * * A shader can request any of these values, and furthermore, it can request * that various compositions, inverses, and transposes be performed. The @@ -915,65 +950,181 @@ update_shader_matrix_cache(Shader *shader, LVecBase4f *cache, int altered) { * * Some values, like the following, aren't matrices: * - * * window size * texture coordinates of card center + * - window size + * - texture coordinates of card center * * This routine can fetch these values as well, by shoehorning them into a * matrix. In this way, we avoid the need for a separate routine to fetch * these values. - * - * The "altered" bits indicate what parts of the state_and_transform have - * changed since the last time this particular ShaderMatSpec was evaluated. - * This may allow data to be cached and not reevaluated. - * */ const LVecBase4f *GraphicsStateGuardian:: -fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, int altered) { +fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, LVecBase4f *scratch) { LVecBase3f v; const LVecBase4f *cache0 = cache + spec._cache_offset[0]; const LVecBase4f *cache1 = cache + spec._cache_offset[1]; + LMatrix4f &m = *(LMatrix4f *)scratch; + switch (spec._func) { case Shader::SMF_first: return cache0; case Shader::SMF_compose: - spec._value.multiply(*(LMatrix4f *)cache0, *(LMatrix4f *)cache1); - return (LVecBase4f *)&spec._value; + m.multiply(*(LMatrix4f *)cache0, *(LMatrix4f *)cache1); + return (LVecBase4f *)&m; case Shader::SMF_transform_dlight: - spec._value = *(LMatrix4f *)cache0; + m = *(LMatrix4f *)cache0; v = (*(LMatrix4f *)cache1).xform_vec(cache0[2].get_xyz()); v.normalize(); - spec._value.set_row(2, v); + m.set_row(2, v); v = (*(LMatrix4f *)cache1).xform_vec(cache0[3].get_xyz()); v.normalize(); - spec._value.set_row(3, v); - return (LVecBase4f *)&spec._value; + m.set_row(3, v); + return (LVecBase4f *)&m; case Shader::SMF_transform_plight: { // Careful not to touch the w component, which contains the near value. - spec._value = *(LMatrix4f *)cache0; + m = *(LMatrix4f *)cache0; LPoint3f point = (*(LMatrix4f *)cache1).xform_point(cache0[2].get_xyz()); - spec._value(2, 0) = point[0]; - spec._value(2, 1) = point[1]; - spec._value(2, 2) = point[2]; - return (LVecBase4f *)&spec._value; + m(2, 0) = point[0]; + m(2, 1) = point[1]; + m(2, 2) = point[2]; + return (LVecBase4f *)&m; } case Shader::SMF_transform_slight: - spec._value = *(LMatrix4f *)cache0; - spec._value.set_row(2, (*(LMatrix4f *)cache1).xform_point(cache0[2].get_xyz())); + m = *(LMatrix4f *)cache0; + m.set_row(2, (*(LMatrix4f *)cache1).xform_point(cache0[2].get_xyz())); v = (*(LMatrix4f *)cache1).xform_vec(cache0[3].get_xyz()); v.normalize(); - spec._value.set_row(3, v); - return (LVecBase4f *)&spec._value; + m.set_row(3, v); + return (LVecBase4f *)&m; + + case Shader::SMF_shader_input_ptr: + return (const LVecBase4f *)fetch_ptr_parameter(spec, scratch); } // Should never get here - spec._value = LMatrix4f::ident_mat(); - return (LVecBase4f *)&spec._value; + m = LMatrix4f::ident_mat(); + return (LVecBase4f *)&m; +} + +/** + * Fetches a numeric shader input, doing conversion as necessary using the + * given amount of scratch space. + */ +const void *GraphicsStateGuardian:: +fetch_ptr_parameter(Shader::ShaderMatSpec &spec, LVecBase4f *scratch) { + Shader::ShaderPtrData ptr_data; + if (!_target_shader->get_shader_input_ptr(spec._arg[0], ptr_data)) { + return nullptr; + } + + nassertr(spec._num_components > 0, nullptr); + + int array_size = std::min(spec._array_count, (int)ptr_data._size / spec._num_components); + switch (spec._numeric_type) { + case Shader::SPT_float: + { + float *data = (float *)scratch; + + switch (ptr_data._type) { + case Shader::SPT_int: + // Convert int data to float data. + for (int i = 0; i < (array_size * spec._num_components); ++i) { + data[i] = (float)(((int*)ptr_data._ptr)[i]); + } + return data; + + case Shader::SPT_uint: + // Convert unsigned int data to float data. + for (int i = 0; i < (array_size * spec._num_components); ++i) { + data[i] = (float)(((unsigned int*)ptr_data._ptr)[i]); + } + return data; + + case Shader::SPT_double: + // Downgrade double data to float data. + for (int i = 0; i < (array_size * spec._num_components); ++i) { + data[i] = (float)(((double*)ptr_data._ptr)[i]); + } + return data; + + case Shader::SPT_float: + return (float *)ptr_data._ptr; + + default: +#ifndef NDEBUG + display_cat.error() + << "Invalid ShaderPtrData type " << (int)ptr_data._type + << " for shader input '" << spec._id._name << "'\n"; +#endif + return nullptr; + } + + return data; + } + break; + + case Shader::SPT_int: + if (ptr_data._type != Shader::SPT_int && + ptr_data._type != Shader::SPT_uint) { + display_cat.error() + << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n"; + + // Deactivate it to make sure the user doesn't get flooded with this + // error. + spec._dep = 0; + + } else { + return ptr_data._ptr; + } + break; + + case Shader::SPT_uint: + if (ptr_data._type != Shader::SPT_uint && + ptr_data._type != Shader::SPT_int) { + display_cat.error() + << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n"; + + // Deactivate it to make sure the user doesn't get flooded with this + // error. + spec._dep = 0; + return nullptr; + + } else { + return ptr_data._ptr; + } + break; + + case Shader::SPT_double: + display_cat.error() + << "Passing double-precision shader inputs to shaders is not currently supported\n"; + + // Deactivate it to make sure the user doesn't get flooded with this + // error. + spec._dep = 0; + break; + + case Shader::SPT_bool: + if (ptr_data._type == Shader::SPT_double) { + unsigned int *data = (unsigned int *)scratch; + for (int i = 0; i < (array_size * spec._num_components); ++i) { + data[i] = ((double *)ptr_data._ptr)[i] != 0; + } + return data; + } else { + return (float *)ptr_data._ptr; + } + + case Shader::SPT_unknown: + break; + } + + return nullptr; } /** @@ -1038,32 +1189,23 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS if (target_material->is_off()) { - into[0].set(1, 1, 1, 1); - into[1].set(1, 1, 1, 1); - into[2].set(0, 0, 0, 0); - into[3].set(0, 0, 0, 0); + into[Shader::MA_ambient].set(1, 1, 1, 1); + into[Shader::MA_diffuse].set(1, 1, 1, 1); + into[Shader::MA_emission].set(0, 0, 0, 0); + into[Shader::MA_specular].set(0, 0, 0, 0); + into[Shader::MA_base_color].set(0, 0, 0, 0); + into[Shader::MA_metallic_ior_roughness].set(0, 0, 0, 1); return; } Material *m = target_material->get_material(); LVecBase4 spc = m->get_specular(); spc[3] = m->get_shininess(); - into[0] = LCAST(float, m->get_ambient()); - into[1] = LCAST(float, m->get_diffuse()); - into[2] = LCAST(float, m->get_emission()); - into[3] = LCAST(float, spc); - return; - } - case Shader::SMO_attr_material2: { - const MaterialAttrib *target_material = (const MaterialAttrib *) - _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); - if (target_material->is_off()) { - into[0].set(0, 0, 0, 0); - into[1].set(0, 0, 0, 1); - return; - } - Material *m = target_material->get_material(); - into[0] = LCAST(float, m->get_base_color()); - into[1].set(m->get_metallic(), m->get_refractive_index(), 0, m->get_roughness()); + into[Shader::MA_ambient] = LCAST(float, m->get_ambient()); + into[Shader::MA_diffuse] = LCAST(float, m->get_diffuse()); + into[Shader::MA_emission] = LCAST(float, m->get_emission()); + into[Shader::MA_specular] = LCAST(float, spc); + into[Shader::MA_base_color] = LCAST(float, m->get_base_color()); + into[Shader::MA_metallic_ior_roughness].set(m->get_metallic(), m->get_refractive_index(), 0, m->get_roughness()); return; } case Shader::SMO_attr_color: { @@ -1092,22 +1234,13 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, Fog *fog = target_fog->get_fog(); if (fog == nullptr) { into[0].set(0, 1, 1, 1); + into[1].set(1, 1, 1, 1); return; } PN_stdfloat start, end; fog->get_linear_range(start, end); into[0].set(fog->get_exp_density(), start, end, 1.0f / (end - start)); - return; - } - case Shader::SMO_attr_fogcolor: { - const FogAttrib *target_fog = (const FogAttrib *) - _target_rs->get_attrib_def(FogAttrib::get_class_slot()); - Fog *fog = target_fog->get_fog(); - if (fog == nullptr) { - into[0].set(1, 1, 1, 1); - return; - } - into[0] = LCAST(float, fog->get_color()); + into[1] = LCAST(float, fog->get_color()); return; } case Shader::SMO_alight_x: { @@ -1588,7 +1721,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, fetch_specified_member(np, name->get_basename(), into[0]); return; } - case Shader::SMO_light_source_i_vec_attrib: { + case Shader::SMO_light_source_i: { const LightAttrib *target_light; _target_rs->get_attrib_def(target_light); @@ -1600,17 +1733,17 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, for (i = 0; i < num_lights; ++i) { NodePath light = target_light->get_on_light(i); nassertv(!light.is_empty()); - fetch_specified_member(light, name, into[i]); + fetch_specified_light(light, into); + into += Shader::LA_COUNT; } // Apply the default OpenGL lights otherwise. // Special exception for light 0, which defaults to white. - if (i == 0) { - //FIXME: only the color attribute - into[0].set(1, 1, 1, 1); - ++i; - } for (; i < (size_t)count; ++i) { - fetch_specified_member(NodePath(), name, into[i]); + fetch_specified_light(NodePath(), into); + if (i == 0) { + into[Shader::LA_color].set(1, 1, 1, 1); + } + into += Shader::LA_COUNT; } return; } @@ -1649,7 +1782,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return; } case Shader::SMO_light_source_i_packed: { - // The light matrix contains COLOR, ATTENUATION, POSITION, VIEWVECTOR + // The light matrix contains COLOR, ATTENUATION, VIEWVECTOR, POSITION const LightAttrib *target_light; _target_rs->get_attrib_def(target_light); @@ -1700,7 +1833,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } } - into += i * 4; + into += 4; } // Apply the default OpenGL lights otherwise. // Special exception for light 0, which defaults to white. @@ -1716,7 +1849,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, into[1].set(1, 0, 0, 0); into[2].set(0, 0, 0, 0); into[3].set(0, 0, 0, 0); - into += i * 4; + into += 4; } return; } @@ -2008,6 +2141,111 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LVecBase4f & } } +/** + * Given a NodePath passed into a shader input that is a structure, fetches + * the value for the given member. + */ +void GraphicsStateGuardian:: +fetch_specified_light(const NodePath &np, LVecBase4f *into) { + PandaNode *node = nullptr; + if (!np.is_empty()) { + node = np.node(); + } + + if (node == nullptr) { + into[Shader::LA_color].set(0, 0, 0, 1); + into[Shader::LA_specular].set(0, 0, 0, 1); + into[Shader::LA_ambient].set(0, 0, 0, 1); + into[Shader::LA_diffuse].set(0, 0, 0, 1); + into[Shader::LA_position].set(0, 0, 1, 0); + into[Shader::LA_half_vector].set(0, 0, 1, 0); + into[Shader::LA_spot_direction].set(0, 0, -1, 0); + into[Shader::LA_spot_params].set(-1, 180, 0, 0); + into[Shader::LA_attenuation].set(1, 0, 0, 0); + *(LMatrix4f *)&into[Shader::LA_shadow_view_matrix] = LCAST(float, shadow_bias_mat); + } else { + Light *light = node->as_light(); + nassertv(light != nullptr); + + LVecBase4f color = LCAST(float, light->get_color()); + into[Shader::LA_color] = color; + into[Shader::LA_specular] = LCAST(float, light->get_specular_color()); + + if (node->is_ambient_light()) { + into[Shader::LA_ambient] = color; + into[Shader::LA_diffuse].set(0, 0, 0, 1); + into[Shader::LA_position].set(0, 0, 0, 0); + into[Shader::LA_half_vector].set(0, 0, 0, 0); + into[Shader::LA_spot_direction].set(0, 0, 0, 0); + into[Shader::LA_spot_params].set(-1, 180, 0, 0); + } else { + into[Shader::LA_ambient].set(0, 0, 0, 1); + into[Shader::LA_diffuse] = color; + + CPT(TransformState) net_transform = + np.get_transform(_scene_setup->get_scene_root().get_parent()); + CPT(TransformState) transform = + _scene_setup->get_cs_world_transform()->compose(net_transform); + const LMatrix4 &light_mat = transform->get_mat(); + + LightLensNode *light; + DCAST_INTO_V(light, node); + Lens *lens = light->get_lens(); + nassertv(lens != nullptr); + + if (node->is_of_type(DirectionalLight::get_class_type())) { + DirectionalLight *light; + DCAST_INTO_V(light, node); + + LVector3 dir = -(light->get_direction() * light_mat); + into[Shader::LA_position].set(dir[0], dir[1], dir[2], 0); + + dir.normalize(); + dir += LVector3(0, 0, 1); + dir.normalize(); + into[Shader::LA_half_vector].set(dir[0], dir[1], dir[2], 1); + } + else { + LPoint3 pos = lens->get_nodal_point() * light_mat; + into[Shader::LA_position].set(pos[0], pos[1], pos[2], 1); + + pos.normalize(); + pos += LVector3(0, 0, 1); + pos.normalize(); + into[Shader::LA_half_vector].set(pos[0], pos[1], pos[2], 1); + } + + if (node->is_of_type(Spotlight::get_class_type())) { + float cutoff = lens->get_hfov() * 0.5f; + into[Shader::LA_spot_params].set(ccos(deg_2_rad(cutoff)), cutoff, light->get_exponent(), 0); + } else { + // spotCosCutoff, spotCutoff, spotExponent + into[Shader::LA_spot_params].set(-1, 180, light->get_exponent(), 0); + } + + LVector3 dir = lens->get_view_vector() * light_mat; + into[Shader::LA_spot_direction].set(dir[0], dir[1], dir[2], 0); + + LMatrix4 t = _inv_cs_transform->get_mat() * + _scene_setup->get_camera_transform()->get_mat() * + net_transform->get_inverse()->get_mat() * + LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()); + + if (!node->is_of_type(PointLight::get_class_type())) { + t *= lens->get_projection_mat() * shadow_bias_mat; + } + *(LMatrix4f *)&into[Shader::LA_shadow_view_matrix] = LCAST(float, t); + } + + LVecBase3 atten = light->get_attenuation(); + PN_stdfloat radius = 0; + if (node->is_of_type(SphereLight::get_class_type())) { + radius = ((const SphereLight *)node)->get_radius(); + } + into[Shader::LA_attenuation].set(atten[0], atten[1], atten[2], radius); + } +} + /** * Like fetch_specified_value, but for texture inputs. */ @@ -2543,6 +2781,7 @@ end_frame(Thread *current_thread) { _vertices_tri_pcollector.flush_level(); _vertices_patch_pcollector.flush_level(); _vertices_other_pcollector.flush_level(); + _compute_work_groups_pcollector.flush_level(); _state_pcollector.flush_level(); _texture_state_pcollector.flush_level(); @@ -3191,6 +3430,7 @@ init_frame_pstats() { _vertices_tri_pcollector.clear_level(); _vertices_patch_pcollector.clear_level(); _vertices_other_pcollector.clear_level(); + _compute_work_groups_pcollector.clear_level(); _state_pcollector.clear_level(); _transform_state_pcollector.clear_level(); diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 617174e6676..9cb390f88c7 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -114,6 +114,7 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa GraphicsEngine *get_engine() const; INLINE const GraphicsThreadingModel &get_threading_model() const; MAKE_PROPERTY(pipe, get_pipe); + MAKE_PROPERTY(engine, get_engine); INLINE bool is_hardware() const; virtual INLINE bool prefers_triangle_strips() const; @@ -175,6 +176,12 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa INLINE int get_maximum_simultaneous_render_targets() const; INLINE bool get_supports_dual_source_blending() const; +public: + INLINE LVecBase3i get_max_compute_work_group_count() const; + INLINE LVecBase3i get_max_compute_work_group_size() const; + INLINE int get_max_compute_work_group_invocations() const; + +PUBLISHED: MAKE_PROPERTY(max_vertices_per_array, get_max_vertices_per_array); MAKE_PROPERTY(max_vertices_per_primitive, get_max_vertices_per_primitive); MAKE_PROPERTY(max_texture_stages, get_max_texture_stages); @@ -221,6 +228,9 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa MAKE_PROPERTY(timer_queries_active, get_timer_queries_active); MAKE_PROPERTY(max_color_targets, get_max_color_targets); MAKE_PROPERTY(supports_dual_source_blending, get_supports_dual_source_blending); + MAKE_PROPERTY(max_compute_work_group_count, get_max_compute_work_group_count); + MAKE_PROPERTY(max_compute_work_group_size, get_max_compute_work_group_size); + MAKE_PROPERTY(max_compute_work_group_invocations, get_max_compute_work_group_invocations); INLINE ShaderModel get_shader_model() const; INLINE void set_shader_model(ShaderModel shader_model); @@ -291,6 +301,7 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa public: virtual TextureContext *prepare_texture(Texture *tex); virtual bool update_texture(TextureContext *tc, bool force); + virtual bool update_texture(TextureContext *tc, bool force, CompletionToken token); virtual void release_texture(TextureContext *tc); virtual void release_textures(const pvector &contexts); virtual bool extract_texture_data(Texture *tex); @@ -315,6 +326,7 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data); virtual void release_shader_buffer(BufferContext *ibc); virtual void release_shader_buffers(const pvector &contexts); + virtual bool extract_shader_buffer_data(ShaderBuffer *buffer, vector_uchar &data); virtual void begin_occlusion_query(); virtual PT(OcclusionQueryContext) end_occlusion_query(); @@ -337,11 +349,13 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa virtual void clear(DrawableRegion *clearable); void update_shader_matrix_cache(Shader *shader, LVecBase4f *cache, int altered); - const LVecBase4f *fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, int altered); + const LVecBase4f *fetch_specified_value(Shader::ShaderMatSpec &spec, const LVecBase4f *cache, LVecBase4f *scratch); + const void *fetch_ptr_parameter(Shader::ShaderMatSpec &spec, LVecBase4f *scratch); void fetch_specified_part(Shader::ShaderMatInput input, InternalName *name, LVecBase4f *into, int count = 1); void fetch_specified_member(const NodePath &np, CPT_InternalName member, LVecBase4f &v); + void fetch_specified_light(const NodePath &np, LVecBase4f *into); PT(Texture) fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler, int &view); const Shader::ShaderPtrData *fetch_ptr_parameter(const Shader::ShaderPtrSpec& spec); @@ -615,12 +629,15 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa bool _supports_basic_shaders; bool _supports_geometry_shaders; bool _supports_tessellation_shaders; - bool _supports_compute_shaders; bool _supports_glsl; bool _supports_hlsl; bool _supports_framebuffer_multisample; bool _supports_framebuffer_blit; + LVecBase3i _max_compute_work_group_count; + LVecBase3i _max_compute_work_group_size; + int _max_compute_work_group_invocations; + bool _supports_stencil; bool _supports_stencil_wrap; bool _supports_two_sided_stencil; @@ -689,6 +706,7 @@ class EXPCL_PANDA_DISPLAY GraphicsStateGuardian : public GraphicsStateGuardianBa static PStatCollector _draw_set_state_pcollector; static PStatCollector _flush_pcollector; static PStatCollector _compute_dispatch_pcollector; + static PStatCollector _compute_work_groups_pcollector; static PStatCollector _wait_occlusion_pcollector; static PStatCollector _wait_timer_pcollector; static PStatCollector _timer_queries_pcollector; diff --git a/panda/src/display/windowProperties_ext.cxx b/panda/src/display/windowProperties_ext.cxx index 45b32e822c5..d9975750b71 100644 --- a/panda/src/display/windowProperties_ext.cxx +++ b/panda/src/display/windowProperties_ext.cxx @@ -91,13 +91,14 @@ __setstate__(PyObject *self, PyObject *props) { PyObject *key, *value; Py_ssize_t pos = 0; + Py_BEGIN_CRITICAL_SECTION(props); while (PyDict_Next(props, &pos, &key, &value)) { // Look for a writable property on the type by this name. PyObject *descr = _PyType_Lookup(type, key); if (descr != nullptr && Py_TYPE(descr)->tp_descr_set != nullptr) { if (Py_TYPE(descr)->tp_descr_set(descr, self, value) < 0) { - return; + break; } } else { PyObject *key_repr = PyObject_Repr(key); @@ -106,9 +107,10 @@ __setstate__(PyObject *self, PyObject *props) { PyUnicode_AsUTF8(key_repr) ); Py_DECREF(key_repr); - return; + break; } } + Py_END_CRITICAL_SECTION(); } #endif // HAVE_PYTHON diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index 63120ea290e..ff77e4448c7 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/panda/src/distort/projectionScreen.cxx @@ -451,9 +451,11 @@ recompute_geom_node(const WorkingNodePath &np, LMatrix4 &rel_mat, int num_geoms = node->get_num_geoms(); for (int i = 0; i < num_geoms; i++) { PT(Geom) geom = node->modify_geom(i); - distort_cat.debug() - << " " << *node << " got geom " << geom - << ", cache_ref = " << geom->get_cache_ref_count() << "\n"; + if (distort_cat.is_debug()) { + distort_cat.debug() + << " " << *node << " got geom " << geom + << ", cache_ref = " << geom->get_cache_ref_count() << "\n"; + } geom->test_ref_count_integrity(); recompute_geom(geom, rel_mat); } diff --git a/panda/src/downloadertools/CMakeLists.txt b/panda/src/downloadertools/CMakeLists.txt index 47abcb727fc..cfe6e979009 100644 --- a/panda/src/downloadertools/CMakeLists.txt +++ b/panda/src/downloadertools/CMakeLists.txt @@ -1,6 +1,4 @@ -if(NOT BUILD_PANDATOOL) - # It's safe to say, if the user doesn't want pandatool, they don't want these - # tools either. +if(NOT BUILD_TOOLS) return() endif() diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 90bd610455a..e4ba7819d7a 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -5261,7 +5261,7 @@ FrameBufferProperties DXGraphicsStateGuardian9:: calc_fb_properties(DWORD cformat, DWORD dformat, DWORD multisampletype, DWORD multisamplequality) { FrameBufferProperties props; - int index=0; + int index=0, isfloat=0; int r=0, g=0, b=0, a=0; switch (cformat) { case D3DFMT_R8G8B8: r=8; g=8; b=8; a=0; break; @@ -5275,10 +5275,19 @@ calc_fb_properties(DWORD cformat, DWORD dformat, case D3DFMT_A8R3G3B2: r=3; g=3; b=2; a=8; break; case D3DFMT_X4R4G4B4: r=4; g=4; b=4; a=0; break; case D3DFMT_A2B10G10R10: r=10;g=10;b=10;a=2; break; + case D3DFMT_R16F: r=16; isfloat=1; break; + case D3DFMT_G16R16F: r=16; isfloat=1; break; + case D3DFMT_A16B16G16R16F:r=16; g=16; b=16; a=16; isfloat=1; break; + case D3DFMT_R32F: r=32; isfloat=1; break; + case D3DFMT_G32R32F: r=32; isfloat=1; break; + case D3DFMT_A32B32G32R32F:r=32; g=32; b=32; a=32; isfloat=1; break; case D3DFMT_A8P8: index=8; a=8; break; case D3DFMT_P8: index=8; a=0; break; default: break; } + if (isfloat > 0) { + props.set_float_color(true); + } if (index > 0) { props.set_rgb_color(0); props.set_indexed_color(1); diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index 5a3dd6a44d9..da485cd50d5 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -76,6 +76,7 @@ DXShaderContext9(Shader *s, GSG *gsg) : ShaderContext(s) { #endif _mat_part_cache = new LVecBase4f[s->cp_get_mat_cache_size()]; + _mat_scratch_space = new LVecBase4f[_shader->cp_get_mat_scratch_size()]; } /** @@ -96,6 +97,7 @@ DXShaderContext9:: } delete[] _mat_part_cache; + delete[] _mat_scratch_space; } /** @@ -188,48 +190,12 @@ void DXShaderContext9:: issue_parameters(GSG *gsg, int altered) { #ifdef HAVE_CG if (_cg_program) { - - // Iterate through _ptr parameters - for (size_t i = 0; i < _shader->_ptr_spec.size(); ++i) { - const Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i]; - - if (altered & (spec._dep[0] | spec._dep[1])) { - const Shader::ShaderPtrData *ptr_data = gsg->fetch_ptr_parameter(spec); - - if (ptr_data == nullptr) { //the input is not contained in ShaderPtrData - release_resources(); - return; - } - - // Calculate how many elements to transfer; no more than it expects, - // but certainly no more than we have. - int input_size = std::min(abs(spec._dim[0] * spec._dim[1] * spec._dim[2]), (int)ptr_data->_size); - - CGparameter p = _cg_parameter_map[spec._id._seqno]; - switch (ptr_data->_type) { - case Shader::SPT_int: - cgSetParameterValueic(p, input_size, (int *)ptr_data->_ptr); - break; - - case Shader::SPT_double: - cgSetParameterValuedc(p, input_size, (double *)ptr_data->_ptr); - break; - - case Shader::SPT_float: - cgSetParameterValuefc(p, input_size, (float *)ptr_data->_ptr); - break; - - default: - dxgsg9_cat.error() - << spec._id._name << ": unrecognized parameter type\n"; - release_resources(); - return; - } + if (altered & _shader->_mat_deps) { + if (altered & _shader->_mat_cache_deps) { + gsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); } - } - if (altered & _shader->_mat_deps) { - gsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); + LMatrix4f scratch; for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) { if ((altered & spec._dep) == 0) { @@ -241,7 +207,7 @@ issue_parameters(GSG *gsg, int altered) { continue; } - const LVecBase4f *val = gsg->fetch_specified_value(spec, _mat_part_cache, altered); + const LVecBase4f *val = gsg->fetch_specified_value(spec, _mat_part_cache, _mat_scratch_space); if (val) { const float *data = (const float *)val + spec._offset; LVecBase4f v; diff --git a/panda/src/dxgsg9/dxShaderContext9.h b/panda/src/dxgsg9/dxShaderContext9.h index f9179069ab0..afc7e8031fb 100644 --- a/panda/src/dxgsg9/dxShaderContext9.h +++ b/panda/src/dxgsg9/dxShaderContext9.h @@ -88,6 +88,7 @@ class EXPCL_PANDADX DXShaderContext9 : public ShaderContext { #endif LVecBase4f *_mat_part_cache = nullptr; + LVecBase4f *_mat_scratch_space = nullptr; private: void release_resources(void); diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index e8522f41679..34782f1a4e8 100644 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -231,6 +231,8 @@ create_texture(DXScreenData &scrn) { case 1: if (num_alpha_bits > 0) { _d3d_format = D3DFMT_A8; + } else if (tex->get_component_type() == Texture::T_float) { + _d3d_format = D3DFMT_R32F; } else { _d3d_format = D3DFMT_L8; } @@ -242,7 +244,11 @@ create_texture(DXScreenData &scrn) { _d3d_format = D3DFMT_R8G8B8; break; case 4: - _d3d_format = D3DFMT_A8R8G8B8; + if (tex->get_component_type() == Texture::T_float) { + _d3d_format = D3DFMT_A32B32G32R32F; + } else { + _d3d_format = D3DFMT_A8R8G8B8; + } break; } @@ -499,6 +505,13 @@ create_texture(DXScreenData &scrn) { break; } + if (num_color_channels == 1) { + CHECK_FOR_FMT(R32F); + CHECK_FOR_FMT(X8R8G8B8); + CHECK_FOR_FMT(R8G8B8); + break; + } + if (!((num_color_channels == 3) || (num_color_channels == 4))) break; //bail @@ -664,22 +677,7 @@ create_texture(DXScreenData &scrn) { } } case 8: - if (needs_luminance) { - // don't bother handling those other 8bit lum fmts like 4-4, since 16 - // 8-8 is usually supported too - nassertr(num_color_channels == 1, false); - - // look for native lum fmt first - CHECK_FOR_FMT(L8); - CHECK_FOR_FMT(L8); - - CHECK_FOR_FMT(R8G8B8); - CHECK_FOR_FMT(X8R8G8B8); - - CHECK_FOR_FMT(R5G6B5); - CHECK_FOR_FMT(X1R5G5B5); - - } else if (num_alpha_bits == 8) { + if (num_alpha_bits == 8) { // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444. // skip 8bit alpha only (D3DFMT_A8), because I think only voodoo @@ -690,6 +688,21 @@ create_texture(DXScreenData &scrn) { CHECK_FOR_FMT(A8L8); CHECK_FOR_FMT(A8R8G8B8); CHECK_FOR_FMT(A4R4G4B4); + } else { + if (needs_luminance) { + // don't bother handling those other 8bit lum fmts like 4-4, since 16 + // 8-8 is usually supported too + nassertr(num_color_channels == 1, false); + + // look for native lum fmt first + CHECK_FOR_FMT(L8); + } + + CHECK_FOR_FMT(R8G8B8); + CHECK_FOR_FMT(X8R8G8B8); + + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } break; @@ -1563,8 +1576,8 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface, for (DWORD y = 0; y < copy_height; y++) { source_word = ((DWORD*)surface_bytes) + x_window_offset; - memcpy(dest_line, source_word, byte_pitch); - dest_line += byte_pitch; + memcpy(dest_line, source_word, copy_width * 4); + dest_line += copy_width * 4; surface_bytes += byte_pitch; } } else { @@ -1614,8 +1627,8 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface9 *d3d_surface, // 24bpp texture case (numComponents == 3) for (DWORD y = 0; y < copy_height; y++) { source_byte = surface_bytes + x_window_offset * 3 * sizeof(BYTE); - memcpy(dest_byte, source_byte, byte_pitch); - dest_byte += byte_pitch; + memcpy(dest_byte, source_byte, copy_width * 3); + dest_byte += copy_width * 3; surface_bytes += byte_pitch; } } @@ -1808,16 +1821,21 @@ fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_ // Preallocate temporary buffer for conversion BYTE *temp_buffer = nullptr; - if (source_format == D3DFMT_A8 || component_width != 1) { - int num_pixels = width * height; - if (source_format == D3DFMT_A8) { - num_pixels *= 2; + if (source_format == D3DFMT_A8 || (component_width != 1 && _d3d_format != D3DFMT_R32F)) { + size_t num_bytes = width * height; + if (_d3d_format == D3DFMT_A32B32G32R32F && source_format == D3DFMT_A32B32G32R32F) { + num_bytes *= 16; + } + else if (source_format == D3DFMT_A8) { + num_bytes *= 2; source_format = D3DFMT_A8L8; source_row_byte_length *= 2; - } else { - num_pixels *= num_color_channels; } - temp_buffer = new BYTE[num_pixels]; + else { + num_bytes *= num_color_channels; + } + + temp_buffer = new BYTE[num_bytes]; if (!IS_VALID_PTR(temp_buffer)) { dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; @@ -1872,9 +1890,22 @@ fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_ *out_pixels = ((*source_pixels) << 8) | 0xFF; } } - pixels = (BYTE *)temp_buffer; + pixels = temp_buffer; } - else if (component_width != 1) { + else if (_d3d_format == D3DFMT_A32B32G32R32F && source_format == D3DFMT_A32B32G32R32F) { + // Swap red and blue components. + float *out_pixels = (float *)temp_buffer; + const float *source_pixels = (const float *)pixels; + size_t total_components = (size_t)width * (size_t)height * 4; + for (int i = 0; i < total_components; i += 4) { + out_pixels[i] = source_pixels[i + 2]; + out_pixels[i + 1] = source_pixels[i + 1]; + out_pixels[i + 2] = source_pixels[i + 0]; + out_pixels[i + 3] = source_pixels[i + 3]; + } + pixels = temp_buffer; + } + else if (component_width != 1 && _d3d_format != D3DFMT_R32F) { // Convert from 16-bit per channel (or larger) format down to 8-bit per // channel. This throws away precision in the original image, but dx8 // doesn't support high-precision images anyway. @@ -1887,7 +1918,7 @@ fill_d3d_texture_mipmap_pixels(int mip_level, int depth_index, D3DFORMAT source_ temp_buffer[i] = *source_pixels; source_pixels += component_width; } - pixels = (BYTE *)temp_buffer; + pixels = temp_buffer; } IDirect3DSurface9 *mip_surface = nullptr; @@ -2166,6 +2197,11 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) { image_compression = Texture::CM_off; } + if (image.is_null() && tex->has_clear_color()) { + // Make an image, filled with the texture's clear color. + image = get_texture()->make_ram_image(); + } + if (image.is_null()) { // The texture doesn't have an image to load. That's ok; it might be a // texture we've rendered to by frame buffer operations or something. @@ -2189,17 +2225,22 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) { // Preallocate temporary buffer for conversion BYTE *temp_buffer = nullptr; - if (_d3d_format == D3DFMT_A8 || component_width != 1) { - int num_pixels = orig_width * orig_height * orig_depth; - if (_d3d_format == D3DFMT_A8) { - num_pixels *= 2; + if (_d3d_format == D3DFMT_A8 || (component_width != 1 && _d3d_format != D3DFMT_R32F)) { + size_t num_bytes = orig_width * orig_height * orig_depth; + if (_d3d_format == D3DFMT_A32B32G32R32F && source_format == D3DFMT_A32B32G32R32F) { + num_bytes *= 16; + } + else if (_d3d_format == D3DFMT_A8) { + num_bytes *= 2; source_format = D3DFMT_A8L8; source_row_byte_length *= 2; source_page_byte_length *= 2; - } else { - num_pixels *= num_color_channels; } - temp_buffer = new BYTE[num_pixels]; + else { + num_bytes *= num_color_channels; + } + + temp_buffer = new BYTE[num_bytes]; if (!IS_VALID_PTR(temp_buffer)) { dxgsg9_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n"; @@ -2270,9 +2311,22 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) { } } - pixels = (BYTE *)temp_buffer; + pixels = temp_buffer; + } + else if (_d3d_format == D3DFMT_A32B32G32R32F && source_format == D3DFMT_A32B32G32R32F) { + // Swap red and blue components. + float *out_pixels = (float *)temp_buffer; + const float *source_pixels = (const float *)pixels; + size_t total_components = (size_t)orig_width * (size_t)orig_height * (size_t)orig_depth * 4; + for (int i = 0; i < total_components; i += 4) { + out_pixels[i] = source_pixels[i + 2]; + out_pixels[i + 1] = source_pixels[i + 1]; + out_pixels[i + 2] = source_pixels[i + 0]; + out_pixels[i + 3] = source_pixels[i + 3]; + } + pixels = temp_buffer; } - else if (component_width != 1) { + else if (component_width != 1 && _d3d_format != D3DFMT_R32F) { // Convert from 16-bit per channel (or larger) format down to 8-bit per // channel. This throws away precision in the original image, but dx8 // doesn't support high-precision images anyway. @@ -2285,7 +2339,7 @@ fill_d3d_volume_texture_pixels(DXScreenData &scrn) { temp_buffer[i] = *source_pixels; source_pixels += component_width; } - pixels = (BYTE *)temp_buffer; + pixels = temp_buffer; } // filtering may be done here if texture if targetsize != origsize @@ -2410,6 +2464,20 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) { *alphbits = 32; return 128; + case Texture::F_r16: + return 16; + case Texture::F_rg16: + return 16 * 2; + case Texture::F_rgb16: + return 16 * 3; + + case Texture::F_r32: + return 32; + case Texture::F_rg32: + return 32 * 2; + case Texture::F_rgb32: + return 32 * 3; + case Texture::F_srgb: return 24; case Texture::F_srgb_alpha: diff --git a/panda/src/dxgsg9/dxgsg9base.h b/panda/src/dxgsg9/dxgsg9base.h index 1d26d98ec53..6d0939c70ae 100644 --- a/panda/src/dxgsg9/dxgsg9base.h +++ b/panda/src/dxgsg9/dxgsg9base.h @@ -157,8 +157,8 @@ typedef enum { D24S8_FLAG = FLG(20), D32_FLAG = FLG(21), INTZ_FLAG = FLG(22), - W11V11U10_FLAG = FLG(23), - A2W10V10U10_FLAG = FLG(24), + R32F_FLAG = FLG(23), + A32B32G32R32F_FLAG =FLG(24), ATI1_FLAG = FLG(25), ATI2_FLAG = FLG(26), DXT1_FLAG = FLG(27), diff --git a/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx b/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx index c09916fded9..d43febe03eb 100644 --- a/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsBuffer9.cxx @@ -45,9 +45,10 @@ wdxGraphicsBuffer9(GraphicsEngine *engine, GraphicsPipe *pipe, _color_backing_store = nullptr; _depth_backing_store = nullptr; - // is this correct ??? Since the pbuffer never gets flipped, we get - // screenshots from the same buffer we draw into. - _screenshot_buffer_type = _draw_buffer_type; + // Since the pbuffer never gets flipped, we get screenshots from the same + // buffer we draw into, which is the back buffer. + _draw_buffer_type = RenderBuffer::T_back; + _screenshot_buffer_type = RenderBuffer::T_back; _shared_depth_buffer = 0; _debug = 0; @@ -414,7 +415,7 @@ rebuild_bitplanes() { _depth_backing_store->Release(); _depth_backing_store = nullptr; } - if (!_depth_backing_store) { + if (!_depth_backing_store && _saved_depth_buffer != nullptr) { hr = _dxgsg -> _d3d_device -> CreateDepthStencilSurface (bitplane_x, bitplane_y, _saved_depth_desc.Format, _saved_depth_desc.MultiSampleType, _saved_depth_desc.MultiSampleQuality, @@ -758,10 +759,19 @@ open_buffer() { dxgsg9_cat.error ( ) << "GetDesc " << D3DERRORSTRING(hr) FL; return false; } - hr = _saved_depth_buffer -> GetDesc (&_saved_depth_desc); - if (!SUCCEEDED (hr)) { - dxgsg9_cat.error ( ) << "GetDesc " << D3DERRORSTRING(hr) FL; - return false; + if (_saved_depth_buffer) { + hr = _saved_depth_buffer -> GetDesc (&_saved_depth_desc); + if (!SUCCEEDED (hr)) { + dxgsg9_cat.error ( ) << "GetDesc " << D3DERRORSTRING(hr) FL; + return false; + } + } else { + ZeroMemory(&_saved_depth_desc, sizeof(_saved_depth_desc)); + } + if (_fb_properties.get_alpha_bits() > 0 && + _saved_color_desc.Format == D3DFMT_X8R8G8B8) { + // Add alpha if we didn't have it and we do need it. + _saved_color_desc.Format = D3DFMT_A8R8G8B8; } _fb_properties = _dxgsg-> calc_fb_properties(_saved_color_desc.Format, diff --git a/panda/src/dxgsg9/wdxGraphicsPipe9.cxx b/panda/src/dxgsg9/wdxGraphicsPipe9.cxx index 8cb8b9782f7..1e9222a637e 100644 --- a/panda/src/dxgsg9/wdxGraphicsPipe9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsPipe9.cxx @@ -862,8 +862,8 @@ void Init_D3DFORMAT_map() { INSERT_ELEM(D24S8); INSERT_ELEM(D32); INSERT_ELEM(INTZ); -// NOT IN DX9 INSERT_ELEM(W11V11U10); - INSERT_ELEM(A2W10V10U10); + INSERT_ELEM(R32F); + INSERT_ELEM(A32B32G32R32F); INSERT_ELEM(ATI1); INSERT_ELEM(ATI2); INSERT_ELEM(DXT1); @@ -923,7 +923,11 @@ const char *D3DFormatStr(D3DFORMAT fmt) { CASESTR(D3DFMT_VERTEXDATA); CASESTR(D3DFMT_INDEX16); CASESTR(D3DFMT_INDEX32); + CASESTR(D3DFMT_R16F); + CASESTR(D3DFMT_G16R16F); CASESTR(D3DFMT_A16B16G16R16F); + CASESTR(D3DFMT_R32F); + CASESTR(D3DFMT_G32R32F); CASESTR(D3DFMT_A32B32G32R32F); } diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx index b1694b56136..329a5d21b33 100644 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx @@ -243,6 +243,7 @@ close_window() { DXGraphicsStateGuardian9::set_cg_device(nullptr); _dxgsg->release_swap_chain(&_wcontext); + _dxgsg = nullptr; WinGraphicsWindow::close_window(); } @@ -1187,7 +1188,7 @@ reset_device_resize_window(UINT new_xsize, UINT new_ysize) { if (wdxdisplay9_cat.is_debug()) { wdxdisplay9_cat.debug() << "swapchain is " << _wcontext._swap_chain << "\n"; } - _gsg->mark_new(); + _dxgsg->mark_new(); init_resized_window(); return retval; } diff --git a/panda/src/egg/eggNode_ext.cxx b/panda/src/egg/eggNode_ext.cxx index 3056e40d6db..eee75234596 100644 --- a/panda/src/egg/eggNode_ext.cxx +++ b/panda/src/egg/eggNode_ext.cxx @@ -24,13 +24,10 @@ __reduce__() const { extern struct Dtool_PyTypedObject Dtool_EggNode; // Find the parse_egg_node function in this module. - PyObject *sys_modules = PyImport_GetModuleDict(); - nassertr_always(sys_modules != nullptr, nullptr); - PyObject *module_name = PyObject_GetAttrString((PyObject *)&Dtool_EggNode, "__module__"); nassertr_always(module_name != nullptr, nullptr); - PyObject *module = PyDict_GetItem(sys_modules, module_name); + PyObject *module = PyImport_GetModule(module_name); Py_DECREF(module_name); nassertr_always(module != nullptr, nullptr); @@ -40,6 +37,7 @@ __reduce__() const { } else { func = PyObject_GetAttrString(module, "parse_egg_node"); } + Py_DECREF(module); nassertr_always(func != nullptr, nullptr); // Get the egg syntax to pass to the parse_egg_node function. diff --git a/panda/src/egg/parser.cxx.prebuilt b/panda/src/egg/parser.cxx.prebuilt index c926fcbc45d..7a4e38db413 100644 --- a/panda/src/egg/parser.cxx.prebuilt +++ b/panda/src/egg/parser.cxx.prebuilt @@ -253,7 +253,7 @@ eggyywarning(YYLTYPE *loc, EggParserState &state, yyscan_t scanner, const string # endif # endif -#include "parser.yxx.h" +#include "parser.h" /* Symbol kind. */ enum yysymbol_kind_t { diff --git a/panda/src/egldisplay/eglGraphicsBuffer.cxx b/panda/src/egldisplay/eglGraphicsBuffer.cxx index a71f5626113..b4fd714659a 100644 --- a/panda/src/egldisplay/eglGraphicsBuffer.cxx +++ b/panda/src/egldisplay/eglGraphicsBuffer.cxx @@ -190,7 +190,8 @@ open_buffer() { // If the old gsg has the wrong pixel format, create a new one that shares // with the old gsg. DCAST_INTO_R(eglgsg, _gsg, false); - if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) { + if (eglgsg->get_engine() != _engine || + !eglgsg->get_fb_properties().subsumes(_fb_properties)) { eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg); eglgsg->choose_pixel_format(_fb_properties, egl_pipe, false, true, false); _gsg = eglgsg; diff --git a/panda/src/egldisplay/eglGraphicsPipe.cxx b/panda/src/egldisplay/eglGraphicsPipe.cxx index aaa6ae0af7a..ee03a267c01 100644 --- a/panda/src/egldisplay/eglGraphicsPipe.cxx +++ b/panda/src/egldisplay/eglGraphicsPipe.cxx @@ -288,6 +288,9 @@ make_output(const std::string &name, ((flags&BF_require_window)!=0)) { return nullptr; } + if (host->get_engine() != engine) { + return nullptr; + } // Early failure - if we are sure that this buffer WONT meet specs, we can // bail out early. if ((flags & BF_fb_props_optional) == 0) { diff --git a/panda/src/egldisplay/eglGraphicsWindow.cxx b/panda/src/egldisplay/eglGraphicsWindow.cxx index e82ea6862f4..65d8812de9c 100644 --- a/panda/src/egldisplay/eglGraphicsWindow.cxx +++ b/panda/src/egldisplay/eglGraphicsWindow.cxx @@ -223,7 +223,8 @@ open_window() { // If the old gsg has the wrong pixel format, create a new one that shares // with the old gsg. DCAST_INTO_R(eglgsg, _gsg, false); - if (!eglgsg->get_fb_properties().subsumes(_fb_properties)) { + if (eglgsg->get_engine() != _engine || + !eglgsg->get_fb_properties().subsumes(_fb_properties)) { eglgsg = new eglGraphicsStateGuardian(_engine, _pipe, eglgsg); eglgsg->choose_pixel_format(_fb_properties, egl_pipe, true, false, false); _gsg = eglgsg; diff --git a/panda/src/event/asyncFuture.cxx b/panda/src/event/asyncFuture.cxx index d8b8b91d979..a6aa341c07b 100644 --- a/panda/src/event/asyncFuture.cxx +++ b/panda/src/event/asyncFuture.cxx @@ -389,6 +389,17 @@ wake_task(AsyncTask *task) { } } +/** + * Internal callback called when a CompletionToken created from this future + * completes. + */ +void AsyncFuture:: +token_callback(Completable::Data *data, bool success) { + AsyncFuture *future = (AsyncFuture *)data; + future->set_result(EventParameter(success)); + unref_delete(future); +} + /** * @see AsyncFuture::gather */ diff --git a/panda/src/event/asyncFuture.h b/panda/src/event/asyncFuture.h index acb6b1020fb..f9f71472f8d 100644 --- a/panda/src/event/asyncFuture.h +++ b/panda/src/event/asyncFuture.h @@ -20,6 +20,7 @@ #include "eventParameter.h" #include "patomic.h" #include "small_vector.h" +#include "completionToken.h" class AsyncTaskManager; class AsyncTask; @@ -58,7 +59,7 @@ class AsyncTask; * * @since 1.10.0 */ -class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount { +class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount, protected Completable::Data { PUBLISHED: INLINE AsyncFuture(); virtual ~AsyncFuture(); @@ -109,6 +110,8 @@ class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount { private: void wake_task(AsyncTask *task); + static void token_callback(Completable::Data *, bool success); + protected: enum FutureState : patomic_unsigned_lock_free::value_type { // Pending states @@ -136,6 +139,7 @@ class EXPCL_PANDA_EVENT AsyncFuture : public TypedReferenceCount { friend class AsyncGatheringFuture; friend class AsyncTaskChain; + friend class CompletionToken; friend class PythonTask; public: @@ -199,6 +203,33 @@ class EXPCL_PANDA_EVENT AsyncGatheringFuture final : public AsyncFuture { static TypeHandle _type_handle; }; +#ifndef CPPPARSER +// Allow passing a future into a method accepting a CompletionToken. +template<> +INLINE CompletionToken:: +CompletionToken(AsyncFuture *future) { + if (future != nullptr) { + future->ref(); + _callback._data = future; + if (_callback._data->_function == nullptr) { + _callback._data->_function = &AsyncFuture::token_callback; + } + } +} + +template<> +INLINE CompletionToken:: +CompletionToken(PT(AsyncFuture) future) { + if (future != nullptr) { + _callback._data = future; + if (_callback._data->_function == nullptr) { + _callback._data->_function = &AsyncFuture::token_callback; + } + future.cheat() = nullptr; + } +} +#endif + #include "asyncFuture.I" #endif // !ASYNCFUTURE_H diff --git a/panda/src/event/asyncFuture_ext.cxx b/panda/src/event/asyncFuture_ext.cxx index 44163e9be64..5ec7d080cba 100644 --- a/panda/src/event/asyncFuture_ext.cxx +++ b/panda/src/event/asyncFuture_ext.cxx @@ -146,6 +146,8 @@ static PyObject *gen_next_asyncfuture(PyObject *self) { PyObject *result = get_done_result(future); if (result != nullptr) { PyErr_SetObject(PyExc_StopIteration, result); + // PyErr_SetObject increased the reference count, so we no longer need our reference. + Py_DECREF(result); } return nullptr; } @@ -173,7 +175,7 @@ set_result(PyObject *result) { else if (DtoolInstance_Check(result)) { // If this is a Python subclass of a C++ type, fall through to below, since // we don't want to lose that extra information. - if (Py_TYPE(result) == (PyTypeObject *)DtoolInstance_TYPE(result)) { + if (Py_IS_TYPE(result, Dtool_GetPyTypeObject(DtoolInstance_TYPE(result)))) { void *ptr; if ((ptr = DtoolInstance_UPCAST(result, Dtool_TypedWritableReferenceCount))) { _this->set_result((TypedWritableReferenceCount *)ptr); diff --git a/panda/src/event/asyncTaskChain.cxx b/panda/src/event/asyncTaskChain.cxx index a854596898f..9ab2093fa39 100644 --- a/panda/src/event/asyncTaskChain.cxx +++ b/panda/src/event/asyncTaskChain.cxx @@ -1438,6 +1438,9 @@ AsyncTaskChainThread(const string &name, AsyncTaskChain *chain) : void AsyncTaskChain::AsyncTaskChainThread:: thread_main() { #ifdef HAVE_THREADS + // Let PStats know this thread exists. + PStatClient::thread_tick(); + MutexHolder holder(_chain->_manager->_lock); while (_chain->_state != S_shutdown && _chain->_state != S_interrupted) { thread_consider_yield(); diff --git a/panda/src/event/pythonTask.cxx b/panda/src/event/pythonTask.cxx index 02e91850908..d2515a93122 100644 --- a/panda/src/event/pythonTask.cxx +++ b/panda/src/event/pythonTask.cxx @@ -174,9 +174,15 @@ get_args() { PyTuple_SET_ITEM(with_task, i, Py_NewRef(item)); } - this->ref(); - PyObject *self = DTool_CreatePyInstance(this, Dtool_PythonTask, true, false); - PyTuple_SET_ITEM(with_task, num_args, self); + // Check whether we have a Python wrapper. This is not the case if the + // object has been created by C++ and never been exposed to Python code. + if (__self__ == nullptr) { + // A __self__ instance does not exist, let's create one now. + this->ref(); + __self__ = DTool_CreatePyInstance(this, Dtool_PythonTask, true, false); + } + + PyTuple_SET_ITEM(with_task, num_args, Py_NewRef(__self__)); return with_task; } else { @@ -294,13 +300,13 @@ __setattr__(PyObject *self, PyObject *attr, PyObject *v) { if (!PyUnicode_Check(attr)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", - attr->ob_type->tp_name); + Py_TYPE(attr)->tp_name); return -1; } PyObject *descr = _PyType_Lookup(Py_TYPE(self), attr); if (descr != nullptr) { - descrsetfunc f = descr->ob_type->tp_descr_set; + descrsetfunc f = Py_TYPE(descr)->tp_descr_set; if (f != nullptr) { return f(descr, self, v); } @@ -357,11 +363,9 @@ PyObject *PythonTask:: __getattribute__(PyObject *self, PyObject *attr) const { // We consult the instance dict first, since the user may have overridden a // method or something. - PyObject *item = PyDict_GetItem(__dict__, attr); - - if (item != nullptr) { - // PyDict_GetItem returns a borrowed reference. - return Py_NewRef(item); + PyObject *item; + if (PyDict_GetItemRef(__dict__, attr, &item) > 0) { + return item; } return PyObject_GenericGetAttr(self, attr); @@ -465,7 +469,7 @@ cancel() { #endif // Shortcut for unextended AsyncFuture. - if (Py_TYPE(_fut_waiter) == (PyTypeObject *)&Dtool_AsyncFuture) { + if (Py_IS_TYPE(_fut_waiter, Dtool_GetPyTypeObject(&Dtool_AsyncFuture))) { AsyncFuture *fut = (AsyncFuture *)DtoolInstance_VOID_PTR(_fut_waiter); if (!fut->done()) { fut->cancel(); @@ -713,7 +717,7 @@ do_python_task() { _retrieved_exception = false; if (task_cat.is_debug()) { - if (_exception != nullptr && Py_TYPE(_exception) == &PyType_Type) { + if (_exception != nullptr && Py_IS_TYPE(_exception, &PyType_Type)) { task_cat.debug() << *this << " received " << ((PyTypeObject *)_exception)->tp_name << " from coroutine.\n"; } else { @@ -795,6 +799,7 @@ do_python_task() { << *this << " is now polling " << PyUnicode_AsUTF8(str) << ".done()\n"; Py_DECREF(str); } + Py_DECREF(fut_done); _fut_waiter = result; return DS_cont; } @@ -857,7 +862,7 @@ do_python_task() { PyMethodDef *meth = nullptr; if (PyCFunction_Check(result)) { meth = ((PyCFunctionObject *)result)->m_ml; - } else if (Py_TYPE(result) == &PyMethodDescr_Type) { + } else if (Py_IS_TYPE(result, &PyMethodDescr_Type)) { meth = ((PyMethodDescrObject *)result)->d_method; } @@ -1003,11 +1008,16 @@ call_owner_method(const char *method_name) { void PythonTask:: call_function(PyObject *function) { if (function != Py_None) { - this->ref(); - PyObject *self = DTool_CreatePyInstance(this, Dtool_PythonTask, true, false); - PyObject *result = PyObject_CallOneArg(function, self); + // Check whether we have a Python wrapper. This is not the case if the + // object has been created by C++ and never been exposed to Python code. + if (__self__ == nullptr) { + // A __self__ instance does not exist, let's create one now. + this->ref(); + __self__ = DTool_CreatePyInstance(this, Dtool_PythonTask, true, false); + } + + PyObject *result = PyObject_CallOneArg(function, __self__); Py_XDECREF(result); - Py_DECREF(self); } } diff --git a/panda/src/express/CMakeLists.txt b/panda/src/express/CMakeLists.txt index 3ffc45a1e57..8b38007938c 100644 --- a/panda/src/express/CMakeLists.txt +++ b/panda/src/express/CMakeLists.txt @@ -148,7 +148,7 @@ set(P3EXPRESS_IGATEEXT composite_sources(p3express P3EXPRESS_SOURCES) add_component_library(p3express SYMBOL BUILDING_PANDA_EXPRESS ${P3EXPRESS_SOURCES} ${P3EXPRESS_HEADERS}) -target_link_libraries(p3express p3pandabase p3interrogatedb p3prc p3dtool +target_link_libraries(p3express p3pandabase p3dconfig p3prc p3dtool PKG::ZLIB PKG::OPENSSL) target_interrogate(p3express ALL EXTENSIONS ${P3EXPRESS_IGATEEXT}) diff --git a/panda/src/express/datagram_ext.I b/panda/src/express/datagram_ext.I index 70a71a8b44b..494a76188e9 100644 --- a/panda/src/express/datagram_ext.I +++ b/panda/src/express/datagram_ext.I @@ -47,7 +47,7 @@ __reduce__() const { } extern struct Dtool_PyTypedObject Dtool_Datagram; - PyObject *tp = (PyObject *)&Dtool_Datagram._PyType; + PyObject *tp = (PyObject *)Dtool_GetPyTypeObject(&Dtool_Datagram); PyObject *result = PyTuple_New(2); PyTuple_SET_ITEM(result, 0, Py_NewRef(tp)); diff --git a/panda/src/express/memoryUsage.cxx b/panda/src/express/memoryUsage.cxx index bdc785222ad..21161a025b1 100644 --- a/panda/src/express/memoryUsage.cxx +++ b/panda/src/express/memoryUsage.cxx @@ -16,7 +16,6 @@ #include "trueClock.h" #include "typedReferenceCount.h" #include "mutexImpl.h" -#include "interrogate_request.h" #if defined(_MSC_VER) && defined(_DEBUG) #include diff --git a/panda/src/express/pointerToArray_ext.I b/panda/src/express/pointerToArray_ext.I index 3406a67263c..849f993cbad 100644 --- a/panda/src/express/pointerToArray_ext.I +++ b/panda/src/express/pointerToArray_ext.I @@ -96,7 +96,7 @@ __init__(PyObject *self, PyObject *source) { // Now construct the internal list by copying the elements one-at-a-time // from Python. - PyObject *dict = DtoolInstance_TYPE(self)->_PyType.tp_dict; + PyObject *dict = Dtool_GetPyTypeObject(DtoolInstance_TYPE(self))->tp_dict; PyObject *push_back = PyDict_GetItemString(dict, "push_back"); if (push_back == nullptr) { PyErr_BadArgument(); @@ -106,12 +106,13 @@ __init__(PyObject *self, PyObject *source) { // We need to initialize the this pointer before we can call push_back. DtoolInstance_INIT_PTR(self, this->_this); + Py_BEGIN_CRITICAL_SECTION(source); Py_ssize_t size = PySequence_Size(source); this->_this->reserve(size); for (Py_ssize_t i = 0; i < size; ++i) { PyObject *item = PySequence_GetItem(source, i); if (item == nullptr) { - return; + break; } PyObject *result = PyObject_CallFunctionObjArgs(push_back, self, item, nullptr); Py_DECREF(item); @@ -121,10 +122,11 @@ __init__(PyObject *self, PyObject *source) { PyErr_Format(PyExc_TypeError, "Element %zd in sequence passed to PointerToArray " "constructor could not be added", i); - return; + break; } Py_DECREF(result); } + Py_END_CRITICAL_SECTION(); } /** diff --git a/panda/src/express/trueClock.cxx b/panda/src/express/trueClock.cxx index 157bac657ee..986d2f3c64c 100644 --- a/panda/src/express/trueClock.cxx +++ b/panda/src/express/trueClock.cxx @@ -521,6 +521,7 @@ TrueClock() { #include // for perror static long _init_sec; +static time_t _init_sec_monotonic = 0; /** * @@ -553,25 +554,13 @@ get_long_time() { */ double TrueClock:: get_short_raw_time() { - struct timeval tv; - - int result; - -#ifdef GETTIMEOFDAY_ONE_PARAM - result = gettimeofday(&tv); -#else - result = gettimeofday(&tv, nullptr); -#endif - - if (result < 0) { - // Error in gettimeofday(). - return 0.0; +#if defined(CLOCK_MONOTONIC) && !defined(__APPLE__) + struct timespec spec; + if (clock_gettime(CLOCK_MONOTONIC, &spec) == 0) { + return (double)(spec.tv_sec - _init_sec_monotonic) + (double)spec.tv_nsec / 1000000000.0; } - - // We subtract out the time at which the clock was initialized, because we - // don't care about the number of seconds all the way back to 1970, and we - // want to leave the double with as much precision as it can get. - return (double)(tv.tv_sec - _init_sec) + (double)tv.tv_usec / 1000000.0; +#endif + return get_long_time(); } /** @@ -603,6 +592,16 @@ TrueClock() { } else { _init_sec = tv.tv_sec; } + +#if defined(CLOCK_MONOTONIC) && !defined(__APPLE__) + struct timespec spec; + if (clock_gettime(CLOCK_MONOTONIC, &spec) == 0) { + _init_sec_monotonic = spec.tv_sec; + } else { + perror("clock_gettime(CLOCK_MONOTONIC)"); + _init_sec_monotonic = 0; + } +#endif } #endif diff --git a/panda/src/express/virtualFileMountRamdisk.cxx b/panda/src/express/virtualFileMountRamdisk.cxx index feda85d1f65..2d0449d41dd 100644 --- a/panda/src/express/virtualFileMountRamdisk.cxx +++ b/panda/src/express/virtualFileMountRamdisk.cxx @@ -30,6 +30,7 @@ TypeHandle VirtualFileMountRamdisk::Directory::_type_handle; */ VirtualFileMountRamdisk:: VirtualFileMountRamdisk() : _root("") { + _root.local_object(); } /** @@ -477,6 +478,10 @@ PT(VirtualFileMountRamdisk::FileBase) VirtualFileMountRamdisk::Directory:: do_find_file(const string &filename) const { size_t slash = filename.find('/'); if (slash == string::npos) { + if (filename.empty()) { + return (FileBase *)this; + } + // Search for a file within the local directory. FileBase tfile(filename); tfile.local_object(); diff --git a/panda/src/express/virtualFileSystem.cxx b/panda/src/express/virtualFileSystem.cxx index 37c220f4ca3..1f67b98840a 100644 --- a/panda/src/express/virtualFileSystem.cxx +++ b/panda/src/express/virtualFileSystem.cxx @@ -1206,7 +1206,7 @@ scan_mount_points(vector_string &names, const Filename &path) const { mount_point[prefix.length()] == '/') { // This mount point is below the indicated path. Is it only one // directory below? - string basename = mount_point.substr(prefix.length()); + string basename = mount_point.substr(prefix.length() + 1); if (basename.find('/') == string::npos) { // No embedded slashes, so it's only one directory below. names.push_back(basename); diff --git a/panda/src/ffmpeg/ffmpegAudioCursor.cxx b/panda/src/ffmpeg/ffmpegAudioCursor.cxx index 8d2c6d2aec8..69635549a64 100644 --- a/panda/src/ffmpeg/ffmpegAudioCursor.cxx +++ b/panda/src/ffmpeg/ffmpegAudioCursor.cxx @@ -99,7 +99,15 @@ FfmpegAudioCursor(FfmpegAudio *src) : _audio_timebase = av_q2d(stream->time_base); _audio_rate = codecpar->sample_rate; + + // As of libavformat version 60.25.100, the deprecated + // AVCodecParameters.channels has been removed. + // AVCodecParameters.ch_layout is available since version 59.18.101. +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(59, 18, 101) + _audio_channels = codecpar->ch_layout.nb_channels; +#else _audio_channels = codecpar->channels; +#endif /* LIBAVFORMAT_VERSION_INT */ const AVCodec *pAudioCodec = avcodec_find_decoder(codecpar->codec_id); if (pAudioCodec == nullptr) { @@ -138,10 +146,20 @@ FfmpegAudioCursor(FfmpegAudio *src) : } _resample_ctx = swr_alloc(); + + // As of libavformat version 60.25.100, the deprecated + // AVCodecContext.channel_layout has been removed. + // AVCodecContext.ch_layout is available since version 59.18.101. +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(59, 18, 101) + av_opt_set_chlayout(_resample_ctx, "in_chlayout", &_audio_ctx->ch_layout, 0); + av_opt_set_chlayout(_resample_ctx, "out_chlayout", &_audio_ctx->ch_layout, 0); +#else av_opt_set_int(_resample_ctx, "in_channel_count", _audio_channels, 0); av_opt_set_int(_resample_ctx, "out_channel_count", _audio_channels, 0); av_opt_set_int(_resample_ctx, "in_channel_layout", _audio_ctx->channel_layout, 0); av_opt_set_int(_resample_ctx, "out_channel_layout", _audio_ctx->channel_layout, 0); +#endif /* LIBAVFORMAT_VERSION_INT */ + av_opt_set_int(_resample_ctx, "in_sample_rate", _audio_ctx->sample_rate, 0); av_opt_set_int(_resample_ctx, "out_sample_rate", _audio_ctx->sample_rate, 0); av_opt_set_sample_fmt(_resample_ctx, "in_sample_fmt", _audio_ctx->sample_fmt, 0); @@ -155,7 +173,7 @@ FfmpegAudioCursor(FfmpegAudio *src) : #else ffmpeg_cat.error() << "Codec does not use signed 16-bit sample format, but support for libswresample has not been enabled.\n"; -#endif +#endif /* HAVE_SWRESAMPLE */ } _length = (_format_ctx->duration * 1.0) / AV_TIME_BASE; @@ -220,10 +238,10 @@ cleanup() { avcodec_flush_buffers(_audio_ctx); #endif - avcodec_close(_audio_ctx); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) avcodec_free_context(&_audio_ctx); #else + avcodec_close(_audio_ctx); av_free(_audio_ctx); #endif } diff --git a/panda/src/ffmpeg/ffmpegVideoCursor.cxx b/panda/src/ffmpeg/ffmpegVideoCursor.cxx index aa47af9163a..e77b67d7e30 100644 --- a/panda/src/ffmpeg/ffmpegVideoCursor.cxx +++ b/panda/src/ffmpeg/ffmpegVideoCursor.cxx @@ -614,10 +614,10 @@ close_stream() { avcodec_flush_buffers(_video_ctx); #endif - avcodec_close(_video_ctx); #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0) avcodec_free_context(&_video_ctx); #else + avcodec_close(_video_ctx); av_free(_video_ctx); #endif } diff --git a/panda/src/framework/pandaFramework.cxx b/panda/src/framework/pandaFramework.cxx index 6d249cdc565..32de3dda768 100644 --- a/panda/src/framework/pandaFramework.cxx +++ b/panda/src/framework/pandaFramework.cxx @@ -204,6 +204,8 @@ close_framework() { _event_handler.remove_all_hooks(); + _task_mgr.cleanup(); + _is_open = false; _made_default_pipe = false; _default_pipe.clear(); diff --git a/panda/src/gles2gsg/gles2gsg.h b/panda/src/gles2gsg/gles2gsg.h index 967f3417036..48d86955866 100644 --- a/panda/src/gles2gsg/gles2gsg.h +++ b/panda/src/gles2gsg/gles2gsg.h @@ -147,6 +147,11 @@ typedef char GLchar; #define GL_FRAMEBUFFER_BARRIER_BIT 0x400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x800 #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x1000 +#define GL_SHADER_STORAGE_BARRIER_BIT 0x2000 +#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 +#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 +#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 +#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_HALF_FLOAT 0x140B #define GL_COLOR 0x1800 #define GL_DEPTH 0x1801 @@ -181,6 +186,7 @@ typedef char GLchar; #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 @@ -272,6 +278,7 @@ typedef char GLchar; #define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A +#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 @@ -279,6 +286,8 @@ typedef char GLchar; #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_COMPUTE_SHADER 0x91B9 +#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE +#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF #define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 #define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 #define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 diff --git a/panda/src/glstuff/glBufferContext_src.h b/panda/src/glstuff/glBufferContext_src.h index b67a9d214e4..dcc31c09abb 100644 --- a/panda/src/glstuff/glBufferContext_src.h +++ b/panda/src/glstuff/glBufferContext_src.h @@ -32,6 +32,10 @@ class EXPCL_GL CLP(BufferContext) : public BufferContext, public AdaptiveLruPage // This is the GL "name" of the data object. GLuint _index; + // This is set to glgsg->_shader_storage_barrier_counter if a write was + // performed, in which case a barrier is issued before the next use. + int _shader_storage_barrier_counter = -1; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 3f42461c3d3..50e72f86a49 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -330,6 +330,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte } _mat_part_cache = new LVecBase4f[_shader->cp_get_mat_cache_size()]; + _mat_scratch_space = new LVecBase4f[_shader->cp_get_mat_scratch_size()]; _glgsg->report_my_gl_errors(); } @@ -341,6 +342,7 @@ CLP(CgShaderContext):: ~CLP(CgShaderContext)() { // Don't call release_resources; we may not have an active context. delete[] _mat_part_cache; + delete[] _mat_scratch_space; } /** @@ -533,7 +535,7 @@ issue_parameters(int altered) { // modified every frame and when we switch ShaderAttribs. if (altered & (Shader::SSD_shaderinputs | Shader::SSD_frame)) { // Iterate through _ptr parameters - for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) { + /*for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) { Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i]; const Shader::ShaderPtrData *ptr_data =_glgsg->fetch_ptr_parameter(spec); @@ -688,49 +690,100 @@ issue_parameters(int altered) { release_resources(); return; } - } + }*/ } if (altered & _shader->_mat_deps) { - _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); + if (altered & _shader->_mat_cache_deps) { + _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); + } + + LMatrix4f scratch; for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) { if ((altered & spec._dep) == 0) { continue; } - const LVecBase4f *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, altered); + const LVecBase4f *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, _mat_scratch_space); if (!val) continue; const float *data = val->get_data(); data += spec._offset; CGparameter p = _cg_parameter_map[spec._id._seqno]; - switch (spec._piece) { - case Shader::SMP_float: cgGLSetParameter1f(p, data[0]); continue; - case Shader::SMP_vec2: cgGLSetParameter2fv(p, data); continue; - case Shader::SMP_vec3: cgGLSetParameter3fv(p, data); continue; - case Shader::SMP_vec4: cgGLSetParameter4fv(p, data); continue; - case Shader::SMP_vec4_array: cgGLSetParameterArray4f(p, 0, spec._array_count, data); continue; - case Shader::SMP_mat4_whole: cgGLSetMatrixParameterfc(p, data); continue; - case Shader::SMP_mat4_array: cgGLSetMatrixParameterArrayfc(p, 0, spec._array_count, data); continue; - case Shader::SMP_mat4_transpose: cgGLSetMatrixParameterfr(p, data); continue; - case Shader::SMP_mat4_column: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); continue; - case Shader::SMP_mat4_upper3x3: - { - LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); - cgGLSetMatrixParameterfc(p, upper3.get_data()); - continue; + if (spec._numeric_type == Shader::SPT_float) { + switch (spec._piece) { + case Shader::SMP_scalar: cgGLSetParameter1f(p, data[0]); continue; + case Shader::SMP_vec2: cgGLSetParameter2fv(p, data); continue; + case Shader::SMP_vec3: cgGLSetParameter3fv(p, data); continue; + case Shader::SMP_vec4: cgGLSetParameter4fv(p, data); continue; + case Shader::SMP_scalar_array: cgGLSetParameterArray1f(p, 0, spec._array_count, data); continue; + case Shader::SMP_vec2_array: cgGLSetParameterArray2f(p, 0, spec._array_count, data); continue; + case Shader::SMP_vec3_array: cgGLSetParameterArray3f(p, 0, spec._array_count, data); continue; + case Shader::SMP_vec4_array: cgGLSetParameterArray4f(p, 0, spec._array_count, data); continue; + case Shader::SMP_mat3_whole: + case Shader::SMP_mat4_whole: cgGLSetMatrixParameterfc(p, data); continue; + case Shader::SMP_mat3_array: + case Shader::SMP_mat4_array: cgGLSetMatrixParameterArrayfc(p, 0, spec._array_count, data); continue; + case Shader::SMP_mat4_transpose: cgGLSetMatrixParameterfr(p, data); continue; + case Shader::SMP_mat4_column: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); continue; + case Shader::SMP_mat4_upper3x3: + { + LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); + cgGLSetMatrixParameterfc(p, upper3.get_data()); + continue; + } + case Shader::SMP_mat4_transpose3x3: + { + LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); + cgGLSetMatrixParameterfr(p, upper3.get_data()); + continue; + } } - case Shader::SMP_mat4_transpose3x3: - { - LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); - cgGLSetMatrixParameterfr(p, upper3.get_data()); - continue; + } + else if (spec._numeric_type == Shader::SPT_double) { + const double *datad = (const double *)data; + switch (spec._piece) { + case Shader::SMP_scalar: cgGLSetParameter1d(p, datad[0]); continue; + case Shader::SMP_vec2: cgGLSetParameter2dv(p, datad); continue; + case Shader::SMP_vec3: cgGLSetParameter3dv(p, datad); continue; + case Shader::SMP_vec4: cgGLSetParameter4dv(p, datad); continue; + case Shader::SMP_scalar_array: cgGLSetParameterArray1d(p, 0, spec._array_count, datad); continue; + case Shader::SMP_vec2_array: cgGLSetParameterArray2d(p, 0, spec._array_count, datad); continue; + case Shader::SMP_vec3_array: cgGLSetParameterArray3d(p, 0, spec._array_count, datad); continue; + case Shader::SMP_vec4_array: cgGLSetParameterArray4d(p, 0, spec._array_count, datad); continue; + case Shader::SMP_mat3_whole: + case Shader::SMP_mat4_whole: cgGLSetMatrixParameterdc(p, datad); continue; + case Shader::SMP_mat3_array: + case Shader::SMP_mat4_array: cgGLSetMatrixParameterArraydc(p, 0, spec._array_count, datad); continue; + case Shader::SMP_mat4_transpose: cgGLSetMatrixParameterdr(p, datad); continue; + case Shader::SMP_mat4_column: cgGLSetParameter4d(p, datad[0], datad[4], datad[ 8], datad[12]); continue; + case Shader::SMP_mat4_upper3x3: + { + LMatrix3d upper3(datad[0], datad[1], datad[2], datad[4], datad[5], datad[6], datad[8], datad[9], datad[10]); + cgGLSetMatrixParameterdc(p, upper3.get_data()); + continue; + } + case Shader::SMP_mat4_transpose3x3: + { + LMatrix3d upper3(datad[0], datad[1], datad[2], datad[4], datad[5], datad[6], datad[8], datad[9], datad[10]); + cgGLSetMatrixParameterdr(p, upper3.get_data()); + continue; + } + } + } + else if (spec._numeric_type == Shader::SPT_int || spec._numeric_type == Shader::SPT_uint) { + switch (spec._piece) { + case Shader::SMP_scalar_array: + case Shader::SMP_scalar: cgSetParameter1i(p, ((int *)data)[0]); continue; + case Shader::SMP_vec2_array: + case Shader::SMP_vec2: cgSetParameter2iv(p, (int *)data); continue; + case Shader::SMP_vec3_array: + case Shader::SMP_vec3: cgSetParameter3iv(p, (int *)data); continue; + case Shader::SMP_vec4_array: + case Shader::SMP_vec4: cgSetParameter4iv(p, (int *)data); continue; + default: assert(false); } - case Shader::SMP_int: cgSetParameter1i(p, ((const int *)data)[0]); continue; - case Shader::SMP_ivec2: cgSetParameter2iv(p, (const int *)data); continue; - case Shader::SMP_ivec3: cgSetParameter3iv(p, (const int *)data); continue; - case Shader::SMP_ivec4: cgSetParameter4iv(p, (const int *)data); continue; } } } diff --git a/panda/src/glstuff/glCgShaderContext_src.h b/panda/src/glstuff/glCgShaderContext_src.h index 587504bb689..a9b4157c6e0 100644 --- a/panda/src/glstuff/glCgShaderContext_src.h +++ b/panda/src/glstuff/glCgShaderContext_src.h @@ -76,6 +76,7 @@ class EXPCL_GL CLP(CgShaderContext) final : public ShaderContext { long _slider_table_size; LVecBase4f *_mat_part_cache = nullptr; + LVecBase4f *_mat_scratch_space = nullptr; pvector _cg_parameter_map; WCPT(RenderState) _state_rs; diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 0a26277ea92..9a38590b8b7 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -16,6 +16,18 @@ using std::max; using std::min; +/** + * Returns a copy of the FrameBufferProperties, but without back buffers. + * This is used since the GraphicsOutput constructor makes some decisions + * based on whether this is set, so we need to unset it early. + */ +static FrameBufferProperties +without_back_buffers(const FrameBufferProperties &fb_prop) { + FrameBufferProperties copy(fb_prop); + copy.set_back_buffers(0); + return copy; +} + TypeHandle CLP(GraphicsBuffer)::_type_handle; /** @@ -29,7 +41,7 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe, int flags, GraphicsStateGuardian *gsg, GraphicsOutput *host) : - GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host), + GraphicsBuffer(engine, pipe, name, without_back_buffers(fb_prop), win_prop, flags, gsg, host), _requested_multisamples(0), _requested_coverage_samples(0), _rb_context(nullptr), @@ -269,7 +281,7 @@ begin_frame(FrameMode mode, Thread *current_thread) { CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); for (CLP(TextureContext) *gtc : _texture_contexts) { - if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) { + if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT, true)) { glgsg->issue_memory_barrier(GL_FRAMEBUFFER_BARRIER_BIT); // If we've done it for one, we've done it for all. break; @@ -407,6 +419,7 @@ rebuild_bitplanes() { Texture *attach[RTP_COUNT]; memset(attach, 0, sizeof(Texture *) * RTP_COUNT); _texture_contexts.clear(); + _textures.clear(); // Sort the textures list into appropriate slots. { @@ -446,15 +459,17 @@ rebuild_bitplanes() { } // If we can't bind this type of texture, punt it. - if ((tex->get_texture_type() != Texture::TT_2d_texture) && - (tex->get_texture_type() != Texture::TT_3d_texture) && - (tex->get_texture_type() != Texture::TT_2d_texture_array) && - (tex->get_texture_type() != Texture::TT_cube_map)) { + Texture::TextureType texture_type = tex->get_texture_type(); + if (texture_type != Texture::TT_2d_texture && + texture_type != Texture::TT_3d_texture && + texture_type != Texture::TT_2d_texture_array && + texture_type != Texture::TT_cube_map && + texture_type != Texture::TT_cube_map_array) { ((CData *)cdata.p())->_textures[i]._rtm_mode = RTM_copy_texture; continue; } - if (_rb_size_z > 1 && tex->get_texture_type() == Texture::TT_2d_texture) { + if (_rb_size_z > 1 && texture_type == Texture::TT_2d_texture) { // We can't bind a 2D texture to a layered FBO. If the user happened // to request RTM_bind_layered for a 2D texture, that's just silly, // and we can't render to anything but the first layer anyway. @@ -508,6 +523,18 @@ rebuild_bitplanes() { // but it's a waste. Let's not do it unless the user requested stencil. _use_depth_stencil = false; +#ifdef __APPLE__ + } else if (_fb_properties.get_depth_bits() > 0 && _requested_multisamples) { + // Apple's OpenGL driver doesn't like blitting depth-stencil targets. + // See GitHub issue #1719 + _use_depth_stencil = false; + if (_fb_properties.get_depth_bits() < 24) { + // Make sure we do get at least as many depth bits as we would have + // gotten if we did get a depth-stencil buffer. + _fb_properties.set_depth_bits(24); + } +#endif + } else if (_fb_properties.get_depth_bits() > 0) { // Let's use a depth stencil buffer by default, if a depth buffer was // requested. @@ -613,10 +640,23 @@ rebuild_bitplanes() { if (_have_any_color || have_any_depth) { // Clear if the fbo was just created, regardless of the clear settings per - // frame. + // frame. However, we don't do this for textures, which may have useful + // contents that need to be preserved. if (_initial_clear) { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + GLbitfield mask = 0; + if (_rb[RTP_color]) { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + mask |= GL_COLOR_BUFFER_BIT; + } + if (_rb[RTP_depth]) { + mask |= GL_DEPTH_BUFFER_BIT; + } + if (_rb[RTP_depth_stencil]) { + mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + } + if (mask != 0) { + glClear(mask); + } } #ifndef OPENGLES_1 } else if (glgsg->_supports_empty_framebuffer) { @@ -781,6 +821,12 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, _fb_properties.setup_color_texture(tex); } + if (slot == RTP_color && !tex->has_clear_color()) { + tex->set_clear_color(LColor(0, 0, 0, 1)); + } + + _textures.push_back(tex); + TextureContext *tc = tex->prepare_now(glgsg->get_prepared_objects(), glgsg); nassertv(tc != nullptr); CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); @@ -1120,7 +1166,9 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, if (slot == RTP_depth_stencil) { if (GLCAT.is_debug()) { - GLCAT.debug() << "Creating depth stencil renderbuffer.\n"; + GLCAT.debug() + << "Creating depth stencil renderbuffer with format 0x" << std::hex + << gl_format << std::dec << ".\n"; } // Allocate renderbuffer storage for depth stencil. GLint depth_size = 0, stencil_size = 0; @@ -1148,7 +1196,9 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, } else if (slot == RTP_depth) { if (GLCAT.is_debug()) { - GLCAT.debug() << "Creating depth renderbuffer.\n"; + GLCAT.debug() + << "Creating depth renderbuffer with format 0x" << std::hex + << gl_format << std::dec << ".\n"; } // Allocate renderbuffer storage for regular depth. GLint depth_size = 0; @@ -1164,6 +1214,11 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, } else { gl_format = GL_DEPTH_COMPONENT32F_NV; } + if (GLCAT.is_debug()) { + GLCAT.debug() + << "GL_DEPTH_COMPONENT32 not supported, switching to format 0x" + << std::hex << gl_format << std::dec << " instead.\n"; + } glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y); glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &depth_size); @@ -1188,7 +1243,9 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, } else { if (GLCAT.is_debug()) { - GLCAT.debug() << "Creating color renderbuffer.\n"; + GLCAT.debug() + << "Creating color renderbuffer with format 0x" << std::hex + << gl_format << std::dec << ".\n"; } glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y); @@ -1236,12 +1293,33 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, #ifndef OPENGLES_2 if (_use_depth_stencil) { glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]); + GLuint format; +#ifdef OPENGLES_1 + format = GL_DEPTH24_STENCIL8_OES; +#else + if (_fb_properties.get_depth_bits() > 24 || + _fb_properties.get_float_depth()) { + if (!glgsg->_use_remapped_depth_range) { + format = GL_DEPTH32F_STENCIL8; + } else { + format = GL_DEPTH32F_STENCIL8_NV; + } + } else { + format = GL_DEPTH24_STENCIL8; + } +#endif + if (GLCAT.is_debug()) { + GLCAT.debug() + << "Creating depth stencil renderbuffer with format 0x" << std::hex + << format << std::dec << " and " << _requested_multisamples + << " multisamples.\n"; + } if (_requested_coverage_samples) { glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples, - _requested_multisamples, GL_DEPTH_STENCIL_EXT, + _requested_multisamples, format, _rb_size_x, _rb_size_y); } else { - glgsg->_glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT, _requested_multisamples, GL_DEPTH_STENCIL_EXT, + glgsg->_glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT, _requested_multisamples, format, _rb_size_x, _rb_size_y); } #ifndef OPENGLES @@ -1280,6 +1358,22 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, default: break; } +#ifndef OPENGLES + } else if (_fb_properties.get_depth_bits() > 24) { + format = GL_DEPTH_COMPONENT32; + } else if (_fb_properties.get_depth_bits() > 16) { + format = GL_DEPTH_COMPONENT24; + } else if (_fb_properties.get_depth_bits() > 1) { + format = GL_DEPTH_COMPONENT16; + } else { + format = GL_DEPTH_COMPONENT; +#endif + } + if (GLCAT.is_debug()) { + GLCAT.debug() + << "Creating depth renderbuffer with format 0x" << std::hex + << format << std::dec << " and " << _requested_multisamples + << " multisamples.\n"; } if (_requested_coverage_samples) { glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples, @@ -1319,21 +1413,97 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, case RTP_aux_rgba_1: case RTP_aux_rgba_2: case RTP_aux_rgba_3: + gl_format = GL_RGBA; + break; default: - if (_fb_properties.get_srgb_color()) { - gl_format = GL_SRGB8_ALPHA8; - } else if (_fb_properties.get_float_color()) { - if (_fb_properties.get_color_bits() > 16 * 3) { - gl_format = GL_RGBA32F_ARB; + if (_fb_properties.get_alpha_bits() == 0) { + if (_fb_properties.get_srgb_color()) { + gl_format = GL_SRGB8; + } else if (_fb_properties.get_color_bits() > 16 * 3 || + _fb_properties.get_red_bits() > 16 || + _fb_properties.get_green_bits() > 16 || + _fb_properties.get_blue_bits() > 16) { + // 32-bit, which is always floating-point. + if (_fb_properties.get_blue_bits() > 0 || + _fb_properties.get_color_bits() == 1 || + _fb_properties.get_color_bits() > 32 * 2) { + gl_format = GL_RGB32F; + } else if (_fb_properties.get_green_bits() > 0 || + _fb_properties.get_color_bits() > 32) { + gl_format = GL_RG32F; + } else { + gl_format = GL_R32F; + } + } else if (_fb_properties.get_float_color()) { + // 16-bit floating-point. + if (_fb_properties.get_blue_bits() > 10 || + _fb_properties.get_color_bits() == 1 || + _fb_properties.get_color_bits() > 32) { + gl_format = GL_RGB16F; + } else if (_fb_properties.get_blue_bits() > 0) { + if (_fb_properties.get_red_bits() > 11 || + _fb_properties.get_green_bits() > 11) { + gl_format = GL_RGB16F; + } else { + gl_format = GL_R11F_G11F_B10F; + } + } else if (_fb_properties.get_green_bits() > 0 || + _fb_properties.get_color_bits() > 16) { + gl_format = GL_RG16F; + } else { + gl_format = GL_R16F; + } + } else if (_fb_properties.get_color_bits() > 10 * 3 || + _fb_properties.get_red_bits() > 10 || + _fb_properties.get_green_bits() > 10 || + _fb_properties.get_blue_bits() > 10) { + // 16-bit normalized. + if (_fb_properties.get_blue_bits() > 0 || + _fb_properties.get_color_bits() == 1 || + _fb_properties.get_color_bits() > 16 * 2) { + gl_format = GL_RGBA16; + } else if (_fb_properties.get_green_bits() > 0 || + _fb_properties.get_color_bits() > 16) { + gl_format = GL_RG16; + } else { + gl_format = GL_R16; + } + } else if (_fb_properties.get_color_bits() > 8 * 3 || + _fb_properties.get_red_bits() > 8 || + _fb_properties.get_green_bits() > 8 || + _fb_properties.get_blue_bits() > 8) { + gl_format = GL_RGB10_A2; } else { - gl_format = GL_RGBA16F_ARB; + gl_format = GL_RGB; } } else { - gl_format = GL_RGBA; + if (_fb_properties.get_srgb_color()) { + gl_format = GL_SRGB8_ALPHA8; + } else if (_fb_properties.get_float_color()) { + if (_fb_properties.get_color_bits() > 16 * 3) { + gl_format = GL_RGBA32F_ARB; + } else { + gl_format = GL_RGBA16F_ARB; + } + } else { + if (_fb_properties.get_color_bits() > 16 * 3) { + gl_format = GL_RGBA32F_ARB; + } else if (_fb_properties.get_color_bits() > 8 * 3) { + gl_format = GL_RGBA16; + } else { + gl_format = GL_RGBA; + } + } } break; } #endif + if (GLCAT.is_debug()) { + GLCAT.debug() + << "Creating color renderbuffer with format 0x" << std::hex + << gl_format << std::dec << " and " << _requested_multisamples + << " multisamples.\n"; + } glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]); if (_requested_coverage_samples) { glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples, @@ -1393,6 +1563,7 @@ attach_tex(GLenum attachpoint, CLP(TextureContext) *gtc, int view, int layer) { target, index, 0, layer); break; case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachpoint, index, 0, layer); break; @@ -1955,7 +2126,7 @@ resolve_multisamples() { // Issue memory barriers as necessary to make sure that the texture memory // is synchronized before we blit to it. for (CLP(TextureContext) *gtc : _texture_contexts) { - if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) { + if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT, true)) { glgsg->issue_memory_barrier(GL_FRAMEBUFFER_BARRIER_BIT); // If we've done it for one, we've done it for all. break; diff --git a/panda/src/glstuff/glGraphicsBuffer_src.h b/panda/src/glstuff/glGraphicsBuffer_src.h index ab07322293a..f718e134f85 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.h +++ b/panda/src/glstuff/glGraphicsBuffer_src.h @@ -128,6 +128,10 @@ class EXPCL_GL CLP(GraphicsBuffer) : public GraphicsBuffer { typedef pvector TextureContexts; TextureContexts _texture_contexts; + // List of textures we need to keep a reference to. + typedef pvector Textures; + Textures _textures; + // The cube map face we are currently drawing to or have just finished // drawing to, or -1 if we are not drawing to a cube map. int _bound_tex_page; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index c50cfddb4f3..f95dcc74676 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -24,6 +24,7 @@ #include "geomTrifans.h" #include "geomLines.h" #include "geomLinestrips.h" +#include "geomPatches.h" #include "geomPoints.h" #include "geomVertexReader.h" #include "graphicsWindow.h" @@ -67,6 +68,7 @@ #include "shaderGenerator.h" #include "samplerState.h" #include "displayInformation.h" +#include "completionCounter.h" #if defined(HAVE_CG) && !defined(OPENGLES) #include @@ -96,6 +98,10 @@ PStatCollector CLP(GraphicsStateGuardian)::_check_residency_pcollector("*:PStats PStatCollector CLP(GraphicsStateGuardian)::_wait_fence_pcollector("Wait:Fence"); PStatCollector CLP(GraphicsStateGuardian)::_copy_texture_finish_pcollector("Draw:Copy texture:Finish"); +static PStatCollector _create_texture_storage_pcollector("Draw:Transfer data:Texture:Create Storage"); +static PStatCollector _create_map_pbo_pcollector("Draw:Transfer data:Texture:Create/Map PBO"); +static PStatCollector _load_texture_copy_pcollector("Draw:Transfer data:Texture:Copy/Convert"); + #if defined(HAVE_CG) && !defined(OPENGLES) AtomicAdjust::Integer CLP(GraphicsStateGuardian)::_num_gsgs_with_cg_contexts = 0; small_vector CLP(GraphicsStateGuardian)::_destroyed_cg_contexts; @@ -188,16 +194,22 @@ static const string default_vshader = "in vec4 p3d_MultiTexCoord0;\n" "out vec3 texcoord;\n" "out vec4 color;\n" + "uniform mat4 p3d_ModelViewProjectionMatrix;\n" #else "#version 100\n" "precision mediump float;\n" "attribute vec4 p3d_Vertex;\n" "attribute vec4 p3d_Color;\n" "attribute vec4 p3d_MultiTexCoord0;\n" - "varying vec3 texcoord;\n" "varying lowp vec4 color;\n" -#endif + "#ifdef GL_FRAGMENT_PRECISION_HIGH\n" + "varying highp vec3 texcoord;\n" + "uniform highp mat4 p3d_ModelViewProjectionMatrix;\n" + "#else\n" + "varying mediump vec3 texcoord;\n" "uniform mat4 p3d_ModelViewProjectionMatrix;\n" + "#endif\n" +#endif "uniform mat4 p3d_TextureMatrix;\n" "uniform vec4 p3d_ColorScale;\n" "void main(void) {\n" @@ -265,7 +277,11 @@ static const string default_fshader = #else "#version 100\n" "precision mediump float;\n" - "varying vec3 texcoord;\n" + "#ifdef GL_FRAGMENT_PRECISION_HIGH\n" + "varying highp vec3 texcoord;\n" + "#else\n" + "varying mediump vec3 texcoord;\n" + "#endif\n" "varying lowp vec4 color;\n" "uniform lowp sampler2D p3d_Texture0;\n" "uniform lowp vec4 p3d_TexAlphaOnly;\n" @@ -315,6 +331,23 @@ uchar_l_to_rgb(unsigned char *dest, const unsigned char *source, } } +/** + * Recopies the given array of pixels, converting from luminance to RGBA + * arrangement. + */ +static void +uchar_l_to_rgba(unsigned char *dest, const unsigned char *source, + int num_pixels) { + for (int i = 0; i < num_pixels; i++) { + dest[0] = source[0]; + dest[1] = source[0]; + dest[2] = source[0]; + dest[3] = 1; + dest += 4; + source += 1; + } +} + /** * Recopies the given array of pixels, converting from BGRA to RGBA * arrangement. @@ -415,78 +448,182 @@ ushort_la_to_rgba(unsigned short *dest, const unsigned short *source, } /** - * Reverses the order of the components within the image, to convert (for - * instance) GL_BGR to GL_RGB. Returns the byte pointer representing the - * converted image, or the original image if it is unchanged. - * - * new_image must be supplied; it is the PTA_uchar that will be used to hold - * the converted image if required. It will be modified only if the - * conversion is necessary, in which case the data will be stored there, and - * this pointer will be returned. If the conversion is not necessary, this - * pointer will be left unchanged. + * Determines the number of components of the given external format. */ -static const unsigned char * -fix_component_ordering(PTA_uchar &new_image, - const unsigned char *orig_image, size_t orig_image_size, - GLenum external_format, Texture *tex) { - const unsigned char *result = orig_image; +static int +get_external_format_components(GLint external_format) { + switch (external_format) { +#ifndef OPENGLES_1 + case GL_RED: + case GL_RED_INTEGER: + case GL_GREEN: + case GL_BLUE: +#endif + case GL_ALPHA: + case GL_LUMINANCE: +#ifndef OPENGLES + case GL_GREEN_INTEGER: + case GL_BLUE_INTEGER: + case GL_ALPHA_INTEGER: + case GL_STENCIL_INDEX: +#endif + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + return 1; + +#ifndef OPENGLES_1 + case GL_RG: + case GL_RG_INTEGER: +#endif + case GL_LUMINANCE_ALPHA: + return 2; + + case GL_RGB: +#ifndef OPENGLES_1 + case GL_RGB_INTEGER: +#endif +#ifndef OPENGLES + case GL_BGR: + case GL_BGR_INTEGER: +#endif + return 3; + + case GL_RGBA: +#ifndef OPENGLES_1 + case GL_RGBA_INTEGER: +#endif + case GL_BGRA: +#ifndef OPENGLES + case GL_BGRA_INTEGER: +#endif + return 4; + + default: + GLCAT.error() + << "Unknown external format 0x" << std::hex << external_format + << std::dec << "\n"; + return 4; + } +} +/** + * Copies the image with optional conversion. + */ +static void +copy_image(unsigned char *new_image, const unsigned char *orig_image, + size_t orig_image_size, GLint external_format, int num_components, + int component_width) { switch (external_format) { +#ifndef OPENGLES_1 + case GL_RED: + case GL_RED_INTEGER: + case GL_GREEN: + case GL_BLUE: +#endif + case GL_ALPHA: + case GL_LUMINANCE: +#ifndef OPENGLES + case GL_GREEN_INTEGER: + case GL_BLUE_INTEGER: + case GL_ALPHA_INTEGER: + case GL_STENCIL_INDEX: +#endif + case GL_DEPTH_COMPONENT: + case GL_DEPTH_STENCIL: + if (num_components == 1) { + memcpy(new_image, orig_image, orig_image_size); + return; + } + break; + +#ifndef OPENGLES_1 + case GL_RG: + case GL_RG_INTEGER: +#endif + case GL_LUMINANCE_ALPHA: + if (num_components == 2) { + memcpy(new_image, orig_image, orig_image_size); + return; + } + break; + +#ifndef OPENGLES_1 +#ifndef OPENGLES + case GL_BGR: +#endif + case GL_RGB_INTEGER: + if (num_components == 3) { + memcpy(new_image, orig_image, orig_image_size); + return; + } + if (num_components == 1 && component_width == 1) { + uchar_l_to_rgb(new_image, orig_image, orig_image_size); + return; + } + break; +#endif + case GL_RGB: - if (tex->get_num_components() == 1) { - new_image = PTA_uchar::empty_array(orig_image_size * 3); +#ifndef OPENGLES + case GL_BGR_INTEGER: +#endif + // Need to swap order. + if (num_components == 1 && component_width == 1) { uchar_l_to_rgb(new_image, orig_image, orig_image_size); - result = new_image; - break; + return; } - switch (tex->get_component_type()) { - case Texture::T_unsigned_byte: - case Texture::T_byte: - new_image = PTA_uchar::empty_array(orig_image_size); + if (num_components == 3 && component_width == 1) { uchar_bgr_to_rgb(new_image, orig_image, orig_image_size / 3); - result = new_image; - break; - - case Texture::T_unsigned_short: - case Texture::T_short: - new_image = PTA_uchar::empty_array(orig_image_size); - ushort_bgr_to_rgb((unsigned short *)new_image.p(), + return; + } + if (num_components == 3 && component_width == 2) { + ushort_bgr_to_rgb((unsigned short *)new_image, (const unsigned short *)orig_image, orig_image_size / 6); - result = new_image; - break; + return; + } + break; - default: - break; + case GL_BGRA: +#ifndef OPENGLES_1 + case GL_RGBA_INTEGER: +#endif + if (num_components == 4) { + memcpy(new_image, orig_image, orig_image_size); + return; + } + if (num_components == 1 && component_width == 1) { + uchar_l_to_rgba(new_image, orig_image, orig_image_size); + return; + } + if (num_components == 2 && component_width == 1) { + uchar_la_to_rgba(new_image, orig_image, orig_image_size / 2); + return; } break; case GL_RGBA: - if (tex->get_num_components() == 2) { - new_image = PTA_uchar::empty_array(orig_image_size * 2); +#ifndef OPENGLES + case GL_BGRA_INTEGER: +#endif + // Need to swap order. + if (num_components == 1 && component_width == 1) { + uchar_l_to_rgba(new_image, orig_image, orig_image_size); + return; + } + if (num_components == 2 && component_width == 1) { uchar_la_to_rgba(new_image, orig_image, orig_image_size / 2); - result = new_image; - break; + return; } - switch (tex->get_component_type()) { - case Texture::T_unsigned_byte: - case Texture::T_byte: - new_image = PTA_uchar::empty_array(orig_image_size); + if (num_components == 4 && component_width == 1) { uchar_bgra_to_rgba(new_image, orig_image, orig_image_size / 4); - result = new_image; - break; - - case Texture::T_unsigned_short: - case Texture::T_short: - new_image = PTA_uchar::empty_array(orig_image_size); - ushort_bgra_to_rgba((unsigned short *)new_image.p(), + return; + } + if (num_components == 4 && component_width == 2) { + ushort_bgra_to_rgba((unsigned short *)new_image, (const unsigned short *)orig_image, orig_image_size / 8); - result = new_image; - break; - - default: - break; + return; } break; @@ -494,7 +631,33 @@ fix_component_ordering(PTA_uchar &new_image, break; } - return result; + nassert_raise("Failed to convert image."); +} + +/** + * Reverses the order of the components within the image, to convert (for + * instance) GL_BGR to GL_RGB. Returns the byte pointer representing the + * converted image, or the original image if it is unchanged. + * + * new_image must be supplied; it is the PTA_uchar that will be used to hold + * the converted image if required. It will be modified only if the + * conversion is necessary, in which case the data will be stored there, and + * this pointer will be returned. If the conversion is not necessary, this + * pointer will be left unchanged. + */ +static const unsigned char * +fix_component_ordering(PTA_uchar &new_image, + const unsigned char *orig_image, size_t orig_image_size, + GLenum external_format, Texture *tex) { + if (external_format == GL_RGB || external_format == GL_RGBA) { + int num_components = tex->get_num_components(); + int component_width = tex->get_component_width(); + size_t new_image_size = (orig_image_size / num_components) * ((external_format == GL_RGBA) ? 4 : 3); + new_image = PTA_uchar::empty_array(new_image_size); + copy_image(&new_image[0], orig_image, orig_image_size, external_format, num_components, component_width); + return new_image; + } + return orig_image; } // #--- Zhao Nov2011 @@ -513,6 +676,7 @@ int CLP(GraphicsStateGuardian)::get_driver_shader_version_minor() { return _gl_s CLP(GraphicsStateGuardian):: CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) : GraphicsStateGuardian(gl_coordinate_system, engine, pipe), + _job_queue_cvar(_job_queue_mutex), _renderbuffer_residency(get_prepared_objects()->get_name(), "renderbuffer"), _active_ppbuffer_memory_pcollector("Graphics memory:" + get_prepared_objects()->get_name() + ":Active:ppbuffer"), _inactive_ppbuffer_memory_pcollector("Graphics memory:" + get_prepared_objects()->get_name() + ":Inactive:ppbuffer") @@ -556,6 +720,13 @@ CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) : _cg_context = 0; #endif +#ifdef HAVE_THREADS + AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr(); + _async_chain = task_mgr->make_task_chain("gl_texture_transfer", + gl_texture_transfer_num_threads, + gl_texture_transfer_thread_priority); +#endif + #ifdef DO_PSTATS if (gl_finish) { GLCAT.warning() @@ -574,6 +745,15 @@ CLP(GraphicsStateGuardian):: << "GLGraphicsStateGuardian " << this << " destructing\n"; } +#ifdef HAVE_THREADS + // Make sure there are no more async tasks that could reference this GSG. + _async_chain->wait_for_tasks(); +#endif + { + MutexHolder holder(_job_queue_mutex); + _job_queue.clear(); + } + close_gsg(); } @@ -756,6 +936,15 @@ reset() { // Print out a list of all extensions. report_extensions(); +#ifndef OPENGLES_1 + if (_gl_version_major >= 3) { + _glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) + get_extension_func("glGetIntegeri_v"); + } else { + _glGetIntegeri_v = nullptr; + } +#endif + // Check if we are running under a profiling tool such as apitrace. #if !defined(NDEBUG) && !defined(OPENGLES_1) if (has_extension("GL_EXT_debug_marker")) { @@ -1720,6 +1909,24 @@ reset() { } #endif +#ifndef OPENGLES_1 + _glCopyBufferSubData = nullptr; + if (_supports_buffers) { + if (is_at_least_gl_version(3, 1) || + is_at_least_gles_version(3, 0) || + has_extension("GL_ARB_copy_buffer")) { + _glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) + get_extension_func("glCopyBufferSubData"); + } +#ifdef OPENGLES_2 + else if (has_extension("GL_NV_copy_buffer")) { + _glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) + get_extension_func("glCopyBufferSubDataNV"); + } +#endif + } +#endif + #ifdef OPENGLES if (is_at_least_gles_version(3, 0)) { _glMapBufferRange = (PFNGLMAPBUFFERRANGEEXTPROC) @@ -1746,7 +1953,8 @@ reset() { _glMapBufferRange = nullptr; } - if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_buffer_storage")) { + if (_glMapBufferRange != nullptr && + (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_buffer_storage"))) { _glBufferStorage = (PFNGLBUFFERSTORAGEPROC) get_extension_func("glBufferStorage"); @@ -1917,7 +2125,6 @@ reset() { } #endif // HAVE_CG - _supports_compute_shaders = false; #ifndef OPENGLES_1 #ifdef OPENGLES if (is_at_least_gles_version(3, 1)) { @@ -1928,7 +2135,26 @@ reset() { get_extension_func("glDispatchCompute"); if (_glDispatchCompute != nullptr) { - _supports_compute_shaders = true; + glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &_max_compute_work_group_invocations); + + if (_max_compute_work_group_invocations > 0) { + // Initialize to spec-mandated minima + _max_compute_work_group_count.fill(65535); +#ifdef OPENGLES + _max_compute_work_group_size.set(128, 128, 64); +#else + _max_compute_work_group_size.set(1024, 1024, 64); +#endif + + if (_glGetIntegeri_v != nullptr) { + _glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &_max_compute_work_group_count[0]); + _glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &_max_compute_work_group_count[1]); + _glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &_max_compute_work_group_count[2]); + _glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &_max_compute_work_group_size[0]); + _glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &_max_compute_work_group_size[1]); + _glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &_max_compute_work_group_size[2]); + } + } } } #endif // !OPENGLES_1 @@ -2582,7 +2808,10 @@ reset() { #endif #ifndef OPENGLES - if (is_at_least_gl_version(4, 5) || has_extension("GL_ARB_direct_state_access")) { + _glMapNamedBufferRange = nullptr; + + if (gl_support_dsa && + (is_at_least_gl_version(4, 5) || has_extension("GL_ARB_direct_state_access"))) { _glCreateTextures = (PFNGLCREATETEXTURESPROC) get_extension_func("glCreateTextures"); _glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC) @@ -2596,12 +2825,29 @@ reset() { _glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC) get_extension_func("glBindTextureUnit"); + if (_glMapBufferRange != nullptr) { + _glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC) + get_extension_func("glMapNamedBufferRange"); + } + _supports_dsa = true; } else { _supports_dsa = false; } #endif +#ifndef OPENGLES_1 +#ifdef OPENGLES + if (is_at_least_gles_version(3, 0) || has_extension("GL_NV_pixel_buffer_object")) { +#else + if (is_at_least_gl_version(2, 1) || has_extension("GL_ARB_pixel_buffer_object")) { +#endif + _supports_pixel_buffers = true; + } else { + _supports_pixel_buffers = false; + } +#endif + #ifndef OPENGLES_1 // Do we support empty framebuffer objects? #ifdef OPENGLES @@ -3196,7 +3442,7 @@ reset() { _max_image_units = 0; #ifndef OPENGLES_1 #ifdef OPENGLES - if (is_at_least_gles_version(3, 1) && gl_immutable_texture_storage) { + if (is_at_least_gles_version(3, 1)) { #else if (is_at_least_gl_version(4, 2) || has_extension("GL_ARB_shader_image_load_store")) { #endif @@ -4268,6 +4514,8 @@ prepare_lens() { */ bool CLP(GraphicsStateGuardian):: begin_frame(Thread *current_thread) { + process_pending_jobs(false); + if (!GraphicsStateGuardian::begin_frame(current_thread)) { return false; } @@ -4281,9 +4529,11 @@ begin_frame(Thread *current_thread) { _primitive_batches_display_list_pcollector.clear_level(); #endif - if (!_async_ram_copies.empty()) { - finish_async_framebuffer_ram_copies(); +#ifndef OPENGLES_1 + if (!_fences.empty()) { + process_fences(false); } +#endif #if defined(DO_PSTATS) && !defined(OPENGLES) int frame_number = ClockObject::get_global_clock()->get_frame_count(current_thread); @@ -5707,7 +5957,7 @@ draw_patches(const GeomPrimitivePipelineReader *reader, bool force) { } #ifndef OPENGLES - _glPatchParameteri(GL_PATCH_VERTICES, reader->get_object()->get_num_vertices_per_primitive()); + _glPatchParameteri(GL_PATCH_VERTICES, ((const GeomPatches *)reader->get_object())->get_num_vertices_per_primitive()); #ifdef SUPPORT_IMMEDIATE_MODE if (_use_sender) { @@ -6241,28 +6491,32 @@ issue_memory_barrier(GLbitfield barriers) { _glMemoryBarrier(barriers); - // Indicate that barriers no longer need to be issued for the relevant lists - // of textures. + // Increment these counters to indicate that these barriers have been issued. if (barriers & GL_TEXTURE_FETCH_BARRIER_BIT) { - _textures_needing_fetch_barrier.clear(); + ++_texture_fetch_barrier_counter; GLCAT.spam(false) << " texture_fetch"; } if (barriers & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) { - _textures_needing_image_access_barrier.clear(); + ++_shader_image_access_barrier_counter; GLCAT.spam(false) << " shader_image_access"; } if (barriers & GL_TEXTURE_UPDATE_BARRIER_BIT) { - _textures_needing_update_barrier.clear(); + ++_texture_update_barrier_counter; GLCAT.spam(false) << " texture_update"; } if (barriers & GL_FRAMEBUFFER_BARRIER_BIT) { - _textures_needing_framebuffer_barrier.clear(); + ++_framebuffer_barrier_counter; GLCAT.spam(false) << " framebuffer"; } + if (barriers & GL_SHADER_STORAGE_BARRIER_BIT) { + ++_shader_storage_barrier_counter; + GLCAT.spam(false) << " shader_storage"; + } + GLCAT.spam(false) << "\n"; report_my_gl_errors(); @@ -6354,23 +6608,16 @@ prepare_texture(Texture *tex) { * (and if get_incomplete_render() is true). */ bool CLP(GraphicsStateGuardian):: -update_texture(TextureContext *tc, bool force) { +update_texture(TextureContext *tc, bool force, CompletionToken token) { CLP(TextureContext) *gtc; DCAST_INTO_R(gtc, tc, false); - Texture *tex = tc->get_texture(); - GLenum target = get_texture_target(tex->get_texture_type()); - if (gtc->_target != target) { - // The target has changed. That means we have to re-bind a new texture - // object. - gtc->reset_data(target, tex->get_num_views()); - } - if (gtc->was_image_modified() || !gtc->_has_storage) { PStatGPUTimer timer(this, _texture_update_pcollector); // If the texture image was modified, reload the texture. - bool okflag = upload_texture(gtc, force, tex->uses_mipmaps()); + Texture *tex = tc->get_texture(); + bool okflag = upload_texture(gtc, force, tex->uses_mipmaps(), std::move(token)); if (!okflag) { GLCAT.error() << "Could not load " << *tex << "\n"; @@ -6386,6 +6633,7 @@ update_texture(TextureContext *tc, bool force) { } else if (gtc->was_properties_modified()) { PStatGPUTimer timer(this, _texture_update_pcollector); + Texture *tex = tc->get_texture(); // If only the properties have been modified, we don't necessarily need to // reload the texture. @@ -6401,7 +6649,7 @@ update_texture(TextureContext *tc, bool force) { if (needs_reload) { gtc->mark_needs_reload(); - bool okflag = upload_texture(gtc, force, tex->uses_mipmaps()); + bool okflag = upload_texture(gtc, force, tex->uses_mipmaps(), std::move(token)); if (!okflag) { GLCAT.error() << "Could not load " << *tex << "\n"; @@ -6411,7 +6659,20 @@ update_texture(TextureContext *tc, bool force) { else { // The texture didn't need reloading, but mark it fully updated now. gtc->mark_loaded(); + + if (force) { + // This update is still underway. + gtc->wait_pending_uploads(); + } + token.complete(true); + } + } + else { + if (force) { + // This update is still underway. + gtc->wait_pending_uploads(); } + token.complete(true); } gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); @@ -6429,12 +6690,9 @@ void CLP(GraphicsStateGuardian):: release_texture(TextureContext *tc) { CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); -#ifndef OPENGLES_1 - _textures_needing_fetch_barrier.erase(gtc); - _textures_needing_image_access_barrier.erase(gtc); - _textures_needing_update_barrier.erase(gtc); - _textures_needing_framebuffer_barrier.erase(gtc); -#endif + gtc->cancel_pending_uploads(); + gtc->wait_pending_uploads(); + gtc->delete_unused_pbos(); gtc->set_num_views(0); delete gtc; @@ -6457,13 +6715,6 @@ release_textures(const pvector &contexts) { for (TextureContext *tc : contexts) { CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); -#ifndef OPENGLES_1 - _textures_needing_fetch_barrier.erase(gtc); - _textures_needing_image_access_barrier.erase(gtc); - _textures_needing_update_barrier.erase(gtc); - _textures_needing_framebuffer_barrier.erase(gtc); -#endif - num_indices += gtc->_num_views; if (gtc->_buffers != nullptr) { num_buffers += gtc->_num_views; @@ -7351,11 +7602,18 @@ prepare_shader_buffer(ShaderBuffer *data) { // Some drivers require the buffer to be padded to 16 byte boundary. uint64_t num_bytes = (data->get_data_size_bytes() + 15u) & ~15u; if (_supports_buffer_storage) { - _glBufferStorage(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), 0); + GLbitfield flags = 0; + if (data->get_usage_hint() == GeomEnums::UH_client) { + flags |= GL_CLIENT_STORAGE_BIT; + } + _glBufferStorage(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), flags); } else { _glBufferData(GL_SHADER_STORAGE_BUFFER, num_bytes, data->get_initial_data(), get_usage(data->get_usage_hint())); } + // Barrier not needed. + gbc->_shader_storage_barrier_counter = _shader_storage_barrier_counter - 1; + gbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); report_my_gl_errors(); @@ -7368,13 +7626,15 @@ prepare_shader_buffer(ShaderBuffer *data) { /** * Binds the given shader buffer to the given binding slot. */ -void CLP(GraphicsStateGuardian):: +CLP(BufferContext) *CLP(GraphicsStateGuardian):: apply_shader_buffer(GLuint base, ShaderBuffer *buffer) { + CLP(BufferContext) *gbc = nullptr; + GLuint index = 0; if (buffer != nullptr) { BufferContext *bc = buffer->prepare_now(get_prepared_objects(), this); if (bc != nullptr) { - CLP(BufferContext) *gbc = DCAST(CLP(BufferContext), bc); + gbc = DCAST(CLP(BufferContext), bc); index = gbc->_index; gbc->set_active(true); } @@ -7396,6 +7656,8 @@ apply_shader_buffer(GLuint base, ShaderBuffer *buffer) { report_my_gl_errors(); } + + return gbc; } /** @@ -7479,6 +7741,38 @@ release_shader_buffers(const pvector &contexts) { _glDeleteBuffers(num_indices, indices); report_my_gl_errors(); } + +/** + * This method should only be called by the GraphicsEngine. Do not call it + * directly; call GraphicsEngine::extract_texture_data() instead. + * + * This method will be called in the draw thread to download the buffer's + * current contents synchronously. + */ +bool CLP(GraphicsStateGuardian):: +extract_shader_buffer_data(ShaderBuffer *buffer, vector_uchar &data) { + BufferContext *bc = buffer->prepare_now(get_prepared_objects(), this); + if (bc == nullptr || !bc->is_of_type(CLP(BufferContext)::get_class_type())) { + return false; + } + CLP(BufferContext) *gbc = DCAST(CLP(BufferContext), bc); + + data.resize(buffer->get_data_size_bytes()); + + if (_glMemoryBarrier != nullptr) { + _glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); + } + + _glBindBuffer(GL_SHADER_STORAGE_BUFFER, gbc->_index); + + _glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, data.size(), &data[0]); + + _glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + _current_sbuffer_index = 0; + report_my_gl_errors(); + + return true; +} #endif #ifndef OPENGLES @@ -7622,9 +7916,18 @@ void CLP(GraphicsStateGuardian):: dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) { maybe_gl_finish(); - PStatGPUTimer timer(this, _compute_dispatch_pcollector); - nassertv(_supports_compute_shaders); + nassertv(get_supports_compute_shaders()); nassertv(_current_shader_context != nullptr); + CLP(ShaderContext) *gsc; + DCAST_INTO_V(gsc, _current_shader_context); + +#ifdef DO_PSTATS + _compute_work_groups_pcollector.add_level(num_groups_x * num_groups_y * num_groups_z); + PStatGPUTimer timer(this, gsc->_compute_dispatch_pcollector); +#endif + + gsc->issue_memory_barriers(); + _glDispatchCompute(num_groups_x, num_groups_y, num_groups_z); maybe_gl_finish(); @@ -7697,6 +8000,11 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z, return false; } + } else if (tex->get_texture_type() == Texture::TT_cube_map_array) { + if (!_supports_cube_map_array) { + return false; + } + } else { GLCAT.error() << "Don't know how to copy framebuffer to texture " << *tex << "\n"; @@ -7740,6 +8048,8 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z, nassertr(tc != nullptr, false); CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); + gtc->cancel_pending_uploads(); + GLenum target = get_texture_target(tex->get_texture_type()); if (gtc->_target != target) { gtc->reset_data(target, view + 1); @@ -7819,8 +8129,8 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z, } #ifndef OPENGLES_1 - if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) { - // Make sure that any incoherent writes to this texture have been synced. + if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT, true)) { + // Make sure that any reads and writes to this texture have been synced. issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT); } #endif @@ -8210,13 +8520,50 @@ framebuffer_copy_to_ram(Texture *tex, int view, int z, _glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT); } #endif - GLsync fence = _glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - _async_ram_copies.push_back({request, pbo, fence, external_format, - view, mapped_ptr, image_size}); - } else -#endif - if (external_format == GL_RGBA || external_format == GL_RGB) { - // We may have to reverse the byte ordering of the image if GL didn't do it + + insert_fence([ + this, request = PT(ScreenshotRequest)(request), + mapped_ptr, size = image_size, + pbo, view, external_format + ] (bool success) { + + void *ptr = mapped_ptr; + if (ptr == nullptr) { + ptr = map_read_buffer(GL_PIXEL_PACK_BUFFER, pbo, size); + } + + // Do the memcpy in the background, since it can be slow. + auto func = [=](AsyncTask *task) { + const unsigned char *result = (unsigned char *)ptr; + PTA_uchar new_image; + if (external_format == GL_RGBA || external_format == GL_RGB) { + // We may have to reverse the byte ordering of the image if GL didn't do + // it for us. + result = fix_component_ordering(new_image, result, size, + external_format, request->get_result()); + } + request->set_view_data(view, result); + + // Finishing can take a long time, release the client buffer first so it + // can be reused for the next screenshot. + this->release_client_buffer(pbo, ptr, size); + request->finish(); + return AsyncTask::DS_done; + }; +#ifdef HAVE_THREADS + // We assign a sort value based on the originating frame number, so that + // earlier frames will be processed before subsequent frames, but we don't + // make it unique for every frame, which would kill concurrency. + int frame_number = request->get_frame_number(); + _async_chain->add(std::move(func), "screenshot", frame_number >> 3, -(frame_number & ((1 << 3) - 1))); +#else + func(nullptr); +#endif + }); + } else +#endif + if (external_format == GL_RGBA || external_format == GL_RGB) { + // We may have to reverse the byte ordering of the image if GL didn't do it // for us. PTA_uchar new_image; const unsigned char *result = @@ -8237,104 +8584,6 @@ framebuffer_copy_to_ram(Texture *tex, int view, int z, return true; } -/** - * Finishes all asynchronous framebuffer-copy-to-ram operations. - */ -void CLP(GraphicsStateGuardian):: -finish_async_framebuffer_ram_copies(bool force) { -#ifndef OPENGLES_1 - if (_async_ram_copies.empty()) { - return; - } - - //XXX having a fixed number of threads is not a great idea. We ought to have - // a common thread pool that is sized based on the available number of CPUs. -#ifdef HAVE_THREADS - AsyncTaskManager *task_mgr = AsyncTaskManager::get_global_ptr(); - static AsyncTaskChain *chain = task_mgr->make_task_chain("texture_download", 2, TP_low); -#endif - - PStatTimer timer(_copy_texture_finish_pcollector); - - if (force) { - // Just wait for the last fence, the rest must be complete too then. - PStatTimer timer(_wait_fence_pcollector); - GLsync fence = _async_ram_copies.back()._fence; - _glClientWaitSync(fence, 0, (GLuint64)-1); - } - - while (!_async_ram_copies.empty()) { - AsyncRamCopy © = _async_ram_copies.front(); - if (!force) { - GLenum result = _glClientWaitSync(copy._fence, 0, 0); - if (result != GL_ALREADY_SIGNALED && result != GL_CONDITION_SATISFIED) { - // Not yet done. The rest must not yet be done then, either. - break; - } - } - _glDeleteSync(copy._fence); - - GLuint pbo = copy._pbo; - int view = copy._view; - PT(ScreenshotRequest) request = std::move(copy._request); - GLuint external_format = copy._external_format; - void *mapped_ptr = copy._mapped_pointer; - size_t size = copy._size; - - if (mapped_ptr == nullptr) { - _glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); -#ifdef OPENGLES - // There is neither glMapBuffer nor persistent mapping in OpenGL ES - mapped_ptr = _glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, size, GL_MAP_READ_BIT); -#else - // If we get here in desktop GL, we must not have persistent mapping - nassertv(!_supports_buffer_storage); - mapped_ptr = _glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); -#endif - } - - // Do the memcpy in the background, since it can be slow. - auto func = [=](AsyncTask *task) { - const unsigned char *result = (unsigned char *)mapped_ptr; - PTA_uchar new_image; - if (external_format == GL_RGBA || external_format == GL_RGB) { - // We may have to reverse the byte ordering of the image if GL didn't do - // it for us. - result = fix_component_ordering(new_image, result, size, - external_format, request->get_result()); - } - request->set_view_data(view, result); - - // Finishing can take a long time, release the client buffer first so it - // can be reused for the next screenshot. - this->release_client_buffer(pbo, mapped_ptr, size); - request->finish(); - return AsyncTask::DS_done; - }; -#ifdef HAVE_THREADS - // We assign a sort value based on the originating frame number, so that - // earlier frames will be processed before subsequent frames, but we don't - // make it unique for every frame, which would kill concurrency. - int frame_number = request->get_frame_number(); - chain->add(std::move(func), "screenshot", frame_number >> 3, -(frame_number & ((1 << 3) - 1))); -#else - func(nullptr); -#endif - - _async_ram_copies.pop_front(); - - // If there is 1 remaining, save it for next frame. This helps prevent an - // inconsistent frame rate when the number of fetched frames alternates - // between 0 and 2, which can settle into a stable feedback loop. - if (!force && _async_ram_copies.size() == 1) { - break; - } - } - - _glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); -#endif -} - #ifdef SUPPORT_FIXED_FUNCTION /** * @@ -13805,12 +14054,15 @@ apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc * image. */ bool CLP(GraphicsStateGuardian):: -upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { +upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps, + CompletionToken token) { PStatGPUTimer timer(this, _load_texture_pcollector); Texture *tex = gtc->get_texture(); - if (_effective_incomplete_render && !force) { + //FIXME: upload simple texture for async uploaded thing + bool async_upload = true; + if (_effective_incomplete_render && !force && !async_upload) { bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image(); if (!has_image && tex->might_have_ram_image() && tex->has_simple_ram_image() && @@ -14094,6 +14346,8 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { int num_views = tex->get_num_views(); if (needs_reload) { + gtc->cancel_pending_uploads(); + if (gtc->_immutable) { GLCAT.info() << "Attempt to modify texture with immutable storage, recreating texture.\n"; @@ -14107,8 +14361,8 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { #ifndef OPENGLES_1 if (needs_reload || !image.is_null()) { - // Make sure that any incoherent writes to this texture have been synced. - if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) { + // Make sure that any reads and writes to this texture have been synced. + if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT, true)) { issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT); } } @@ -14125,46 +14379,73 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { nassertr(gtc->_buffers != nullptr, false); } - bool extract_success = false; - if (tex->get_post_load_store_cache()) { - extract_success = true; + bool compressed = image_compression != Texture::CM_off; + if (compressed && !_supports_compressed_texture) { + return false; } + // Does this texture require asynchronous uploads? +#if defined(HAVE_THREADS) && !defined(OPENGLES_1) + int async_buffers = _supports_pixel_buffers ? tex->get_num_async_transfer_buffers() : 0; + if (async_buffers != 0) { + // Prefer immutable storage, if supported. + if (needs_reload && _supports_tex_storage) { + gtc->_immutable = true; + } + } + else if (async_buffers == 0 && gtc->_num_pbos > 0) { + gtc->delete_unused_pbos(); + } +#else + int async_buffers = 0; +#endif + + // Keep track of which views are uploaded. + CompletionCounter counter; bool success = true; + for (int view = 0; view < num_views; ++view) { - if (upload_texture_image(gtc, view, needs_reload || view >= old_num_views, - mipmap_bias, num_levels, - internal_format, external_format, - component_type, image_compression)) { + if (upload_texture_view(gtc, view, needs_reload || view >= old_num_views, + mipmap_bias, num_levels, + internal_format, external_format, + component_type, compressed, async_buffers, + counter.make_token())) { + // We always create storage right away even if we do the upload of the + // actual data asynchronously. gtc->_has_storage = true; gtc->_internal_format = internal_format; gtc->_width = width; gtc->_height = height; gtc->_depth = depth; gtc->_num_levels = num_levels; - - if (extract_success) { - // The next call assumes the texture is still bound. - if (!do_extract_texture_data(gtc, view)) { - extract_success = false; - } - } } else { success = false; } } - report_my_gl_errors(); + if (!success) { + report_my_gl_errors(); + return false; + } + + gtc->_uploads_pending++; + + std::move(counter).then([=, token = std::move(token)] (bool success) mutable { + --gtc->_uploads_pending; + if (!success) { + token.complete(false); + return; + } - if (success) { if (needs_reload) { gtc->update_data_size_bytes(get_texture_memory_size(gtc)); } - nassertr(gtc->_has_storage, false); + nassertv(gtc->_has_storage); - if (extract_success) { + Texture *tex = gtc->get_texture(); + if (tex->get_post_load_store_cache()) { tex->set_post_load_store_cache(false); // OK, get the RAM image, and save it in a BamCache record. if (tex->has_ram_image()) { @@ -14178,14 +14459,20 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { } GraphicsEngine *engine = get_engine(); - nassertr(engine != nullptr, false); + nassertv(engine != nullptr); engine->texture_uploaded(tex); - gtc->mark_loaded(); - return true; - } + token.complete(true); + }); - return false; + // Update the modified counters now, even if we've only spawned an async + // upload, because we've already set things in motion to update the texture + // to this version. Otherwise, future calls to update_texture will continue + // to try to update the image over and over again. + gtc->mark_loaded(); + + report_my_gl_errors(); + return true; } /** @@ -14193,17 +14480,13 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { * texture memory. */ bool CLP(GraphicsStateGuardian):: -upload_texture_image(CLP(TextureContext) *gtc, int view, bool needs_reload, - int mipmap_bias, int num_levels, GLint internal_format, - GLint external_format, GLenum component_type, - Texture::CompressionMode image_compression) { +upload_texture_view(CLP(TextureContext) *gtc, int view, bool needs_reload, + int mipmap_bias, int num_levels, GLint internal_format, + GLint external_format, GLenum component_type, + bool compressed, int async_buffers, CompletionToken token) { // Make sure the error stack is cleared out before we begin. clear_my_gl_errors(); - if (image_compression != Texture::CM_off && !_supports_compressed_texture) { - return false; - } - GLenum target = gtc->_target; if (target == GL_NONE) { // Unsupported target (e.g. 3-d texturing on GL 1.1). @@ -14240,9 +14523,14 @@ upload_texture_image(CLP(TextureContext) *gtc, int view, bool needs_reload, int width = tex->get_expected_mipmap_x_size(mipmap_bias); int height = tex->get_expected_mipmap_y_size(mipmap_bias); int depth = tex->get_expected_mipmap_z_size(mipmap_bias); + int num_components = tex->get_num_components(); + int expected_num_components = compressed ? num_components : get_external_format_components(external_format); + int component_width = tex->get_component_width(); + GLenum usage = GL_STATIC_DRAW; #ifndef OPENGLES_1 if (target == GL_TEXTURE_BUFFER) { + usage = get_usage(tex->get_usage_hint()); GLuint buffer = gtc->get_view_buffer(view); nassertr(buffer != 0, false); _glBindBuffer(GL_TEXTURE_BUFFER, buffer); @@ -14310,6 +14598,7 @@ upload_texture_image(CLP(TextureContext) *gtc, int view, bool needs_reload, // but we are not allowed to change the texture size or number of mipmap // levels after this point. if (gtc->_immutable) { + PStatTimer timer(_create_texture_storage_pcollector); if (GLCAT.is_debug()) { GLCAT.debug() << "allocating storage for texture " << tex->get_name() << ", " @@ -14344,15 +14633,89 @@ upload_texture_image(CLP(TextureContext) *gtc, int view, bool needs_reload, // How many mipmap levels do we have available to upload? int num_ram_mipmap_levels = 0; + GLuint pbo = 0; + size_t pbo_size = 0; + void *mapped_ptr = nullptr; if (!image.is_null()) { num_ram_mipmap_levels = std::min(num_levels, tex->get_num_ram_mipmap_images() - mipmap_bias); + + // Create a PBO that can hold all the mipmap levels. +#if defined(HAVE_THREADS) && !defined(OPENGLES_1) + if (async_buffers != 0) { + pbo_size = 0; + for (int n = mipmap_bias; n < num_ram_mipmap_levels + mipmap_bias; ++n) { + size_t view_size = tex->get_ram_mipmap_view_size(n); + if (!compressed) { + view_size = expected_num_components * (view_size / num_components); + } + pbo_size += view_size; + } + + bool create_storage = false; + if (pbo_size != gtc->_pbo_size) { + // No PBOs yet, or they aren't of the right size. + if (_supports_buffer_storage) { + // If using buffer storage, need to deallocate all of them. + gtc->delete_unused_pbos(); + } + gtc->_pbo_size = pbo_size; + create_storage = true; + } + else if (async_buffers > 0) { + // Wait for a PBO to become available if we're at our limit. + gtc->wait_for_unused_pbo(async_buffers); + } + + PStatTimer timer(_create_map_pbo_pcollector); + if (gtc->_unused_pbos.empty()) { + _glGenBuffers(1, &pbo); + gtc->_num_pbos++; + create_storage = true; + } else { + // Map an existing PBO. + pbo = gtc->_unused_pbos.back(); + gtc->_unused_pbos.pop_back(); + } + + mapped_ptr = map_write_discard_buffer(GL_PIXEL_UNPACK_BUFFER, pbo, + pbo_size, create_storage); + if (mapped_ptr == nullptr) { + report_my_gl_errors(); + GLCAT.warning() + << "Failed to map pixel unpack buffer.\n"; + gtc->_unused_pbos.push_back(pbo); + } + } +#endif } - if (!needs_reload) { - // Try to subload the image over the existing GL Texture object, possibly - // saving on texture memory fragmentation. + if (needs_reload && num_ram_mipmap_levels == 0 && + external_format == GL_DEPTH_STENCIL && get_supports_depth_stencil()) { +#ifdef OPENGLES + component_type = GL_UNSIGNED_INT_24_8_OES; +#else + component_type = GL_UNSIGNED_INT_24_8_EXT; +#endif + } - if (GLCAT.is_debug()) { + int upload_count = ++gtc->_uploads_started; + + if (GLCAT.is_debug()) { + if (needs_reload) { + // Load the image up from scratch, creating a new GL Texture object. + GLCAT.debug() + << "loading new texture object for " << tex->get_name() << " view " + << view << ", " << width << " x " << height << " x " << depth + << ", mipmaps " << num_ram_mipmap_levels << " / " << num_levels; + + if (num_ram_mipmap_levels == 0 && tex->has_clear_color()) { + GLCAT.debug(false) + << ", clearing to " << tex->get_clear_color(); + } + } + else { + // Try to subload the image over the existing GL Texture object, possibly + // saving on texture memory fragmentation. SparseArray pages = gtc->get_view_modified_pages(view, 0); if (num_ram_mipmap_levels == 0) { if (tex->has_clear_color()) { @@ -14360,457 +14723,631 @@ upload_texture_image(CLP(TextureContext) *gtc, int view, bool needs_reload, << "clearing texture " << tex->get_name() << " view " << view << ", " << width << " x " << height << " x " << depth << ", pages " << pages << ", mipmaps " << num_levels << ", clear_color = " - << tex->get_clear_color() << "\n"; + << tex->get_clear_color(); } else { GLCAT.debug() << "not loading NULL image for texture " << tex->get_name() << " view " << view << ", " << width << " x " << height << " x " << depth - << ", pages " << pages << ", mipmaps = " << num_levels << "\n"; + << ", pages " << pages << ", mipmaps = " << num_levels; } } else { GLCAT.debug() << "updating image data of texture " << tex->get_name() << " view " << view << ", " << width << " x " << height << " x " << depth << ", pages " << pages << ", mipmaps " << num_ram_mipmap_levels - << " / " << num_levels << "\n"; - } - } - - for (int n = mipmap_bias; n < num_levels + mipmap_bias; ++n) { - SparseArray pages = gtc->get_view_modified_pages(view, n); - - // we grab the mipmap pointer first, if it is NULL we grab the normal - // mipmap image pointer which is a PTA_uchar - const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n); - CPTA_uchar ptimage; - if (image_ptr == nullptr) { - ptimage = tex->get_ram_mipmap_image(n); - if (ptimage.is_null()) { - if (n - mipmap_bias < num_ram_mipmap_levels) { - // We were told we'd have this many RAM mipmap images, but we - // don't. Raise a warning. - GLCAT.warning() - << "No mipmap level " << n << " defined for " << tex->get_name() - << "\n"; - break; - } + << " / " << num_levels; + } + } + if (mapped_ptr != nullptr) { + GLCAT.debug(false) << " (async #" << upload_count << " via buffer " << pbo << ")\n"; + } else { + GLCAT.debug(false) << " (#" << upload_count << ")\n"; + } + } - if (tex->has_clear_color()) { - // The texture has a clear color, so we should fill this mipmap - // level to a solid color. -#ifndef OPENGLES - if (target != GL_TEXTURE_BUFFER) { - if (_supports_clear_texture) { - // We can do that with the convenient glClearTexImage - // function. - vector_uchar clear_data = tex->get_clear_data(); + // Keeps track of any async jobs we've spawned. +#if defined(HAVE_THREADS) && !defined(OPENGLES_1) + CompletionCounter counter; + struct AsyncLevel { + int width, height, depth; + size_t page_size; + uintptr_t pbo_offset; + SparseArray pages; + }; + AsyncLevel *async_levels = nullptr; + size_t num_async_levels = 0; + uintptr_t pbo_offset = 0u; +#endif + bool success = true; - if (pages.has_all_of(0, depth)) { - _glClearTexImage(index, n - mipmap_bias, external_format, - component_type, (void *)&clear_data[0]); - } - else for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { - int begin = pages.get_subrange_begin(sri); - int num_pages = pages.get_subrange_end(sri) - begin; - _glClearTexSubImage(index, n - mipmap_bias, 0, 0, begin, - width, height, num_pages, external_format, - component_type, (void *)&clear_data[0]); - } - continue; + for (int n = mipmap_bias; n < num_levels + mipmap_bias; ++n) { + SparseArray pages = gtc->get_view_modified_pages(view, n); + int level = n - mipmap_bias; + + int width = tex->get_expected_mipmap_x_size(n); + int height = tex->get_expected_mipmap_y_size(n); + + // we grab the mipmap pointer first, if it is NULL we grab the normal + // mipmap image pointer which is a PTA_uchar + const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n); + CPTA_uchar ptimage; + if (image_ptr == nullptr) { + ptimage = tex->get_ram_mipmap_image(n); + image_ptr = ptimage; + } + if (image_ptr == nullptr) { + if (level < num_ram_mipmap_levels) { + // We were told we'd have this many RAM mipmap images, but we + // don't. Raise a warning. + GLCAT.warning() + << "No mipmap level " << n << " defined for " << tex->get_name() + << "\n"; + + if (needs_reload && _supports_texture_max_level) { + // Tell the GL we have no more mipmaps for it to use. + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, level - 1); + } + break; + } + + if (tex->has_clear_color()) { + // The texture has a clear color, so we should fill this mipmap + // level to a solid color. +#ifndef OPENGLES + if (target != GL_TEXTURE_BUFFER) { + if (_supports_clear_texture && !compressed) { + // If we don't have storage, we create it with a NULL image first. + if (!needs_reload || + upload_texture_level(true, false, target, level, + width, height, depth, internal_format, + external_format, component_type, + nullptr, 0, pages, usage)) { + vector_uchar clear_data = tex->get_clear_data(); + + if (needs_reload || pages.has_all_of(0, depth)) { + _glClearTexImage(index, level, external_format, + component_type, (void *)&clear_data[0]); } - } else { - if (_supports_clear_buffer) { - // For buffer textures we need to clear the underlying - // storage. - vector_uchar clear_data = tex->get_clear_data(); - - _glClearBufferData(GL_TEXTURE_BUFFER, internal_format, external_format, - component_type, (const void *)&clear_data[0]); - continue; + else for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { + int begin = pages.get_subrange_begin(sri); + int num_pages = pages.get_subrange_end(sri) - begin; + _glClearTexSubImage(index, level, 0, 0, begin, + width, height, num_pages, external_format, + component_type, (void *)&clear_data[0]); } + continue; } -#endif // OPENGLES - // Ask the Texture class to create the mipmap level in RAM. It'll - // fill it in with the correct clear color, which we can then - // upload. - ptimage = tex->make_ram_mipmap_image(n); + } + } else { + if (_supports_clear_buffer) { + // For buffer textures we need to clear the underlying + // storage. + if (needs_reload) { + _glBufferData(GL_TEXTURE_BUFFER, tex->get_expected_ram_mipmap_view_size(n), nullptr, usage); + } + vector_uchar clear_data = tex->get_clear_data(); - } else { - // No clear color and no more images. - break; + _glClearBufferData(GL_TEXTURE_BUFFER, internal_format, external_format, + component_type, (const void *)&clear_data[0]); + continue; } } +#endif // OPENGLES + // Ask the Texture class to create the mipmap level in RAM. It'll + // fill it in with the correct clear color, which we can then + // upload. + ptimage = tex->make_ram_mipmap_image(n); image_ptr = ptimage; } - - PTA_uchar bgr_image; - size_t page_size = tex->get_ram_mipmap_page_size(n); - if (image_ptr != nullptr) { - const unsigned char *orig_image_ptr = image_ptr; - size_t view_size = tex->get_ram_mipmap_view_size(n); - image_ptr += view_size * view; - nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); - - if (image_compression == Texture::CM_off) { - // If the GL doesn't claim to support BGR, we may have to reverse - // the component ordering of the image. - image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size, - external_format, tex); - } + else if (!needs_reload) { + // No clear color and no more images, and no storage to create. + break; } - - int width = tex->get_expected_mipmap_x_size(n); - int height = tex->get_expected_mipmap_y_size(n); - -#ifdef DO_PSTATS - _data_transferred_pcollector.add_level(page_size * pages.get_num_on_bits()); -#endif - switch (target) { -#ifndef OPENGLES_1 - case GL_TEXTURE_3D: - if (_supports_3d_texture) { - for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { - int begin = pages.get_subrange_begin(sri); - int num_pages = pages.get_subrange_end(sri) - begin; - const unsigned char *page_ptr = image_ptr + page_size * begin; - - if (image_compression == Texture::CM_off) { - _glTexSubImage3D(target, n - mipmap_bias, - 0, 0, begin, width, height, num_pages, - external_format, component_type, page_ptr); - } else { - _glCompressedTexSubImage3D(target, n - mipmap_bias, - 0, 0, begin, width, height, num_pages, - external_format, - page_size * num_pages, page_ptr); - } - } - } else { - report_my_gl_errors(); - return false; + else if (compressed) { + // We can't upload a NULL compressed texture. + if (_supports_texture_max_level) { + // Tell the GL we have no more mipmaps for it to use. + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, level - 1); } break; -#endif // OPENGLES_1 + } + } -#ifndef OPENGLES - case GL_TEXTURE_1D: - if (image_compression == Texture::CM_off) { - glTexSubImage1D(target, n - mipmap_bias, 0, width, - external_format, component_type, image_ptr); - } else { - _glCompressedTexSubImage1D(target, n - mipmap_bias, 0, width, - external_format, page_size, image_ptr); + // Select the correct view. + size_t orig_view_size = 0; + size_t orig_page_size = 0; + size_t page_size = 0; + if (image_ptr != nullptr) { + orig_view_size = tex->get_ram_mipmap_view_size(n); + if (view > 0) { + const unsigned char *orig_image_ptr = image_ptr; + image_ptr += orig_view_size * view; + nassertd(image_ptr >= orig_image_ptr && image_ptr + orig_view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n)) { + success = false; + break; } - break; -#endif // OPENGLES + } + orig_page_size = tex->get_ram_mipmap_page_size(n); + page_size = orig_page_size; + if (!compressed) { + // May need to convert. + page_size = get_external_format_components(external_format) * (page_size / num_components); + } + } #ifndef OPENGLES_1 - case GL_TEXTURE_2D_ARRAY: - case GL_TEXTURE_CUBE_MAP_ARRAY: - if (_supports_2d_texture_array) { - for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { - int begin = pages.get_subrange_begin(sri); - int num_pages = pages.get_subrange_end(sri) - begin; - const unsigned char *page_ptr = image_ptr + page_size * begin; - - if (image_compression == Texture::CM_off) { - _glTexSubImage3D(target, n - mipmap_bias, - 0, 0, begin, width, height, num_pages, - external_format, component_type, page_ptr); - } else { - _glCompressedTexSubImage3D(target, n - mipmap_bias, - 0, 0, begin, width, height, num_pages, - external_format, - page_size * num_pages, page_ptr); - } + else if (target == GL_TEXTURE_BUFFER) { + // page_size for buffer texture indicates the size even for a null image. + page_size = tex->get_expected_ram_mipmap_view_size(n); + } +#endif + + // Don't need to update the padded area at the bottom. + int sub_height = height; + if (n == 0 && (target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP)) { + sub_height -= tex->get_pad_y_size(); + } + +#if defined(HAVE_THREADS) && !defined(OPENGLES_1) + if (mapped_ptr != nullptr) { + // Let's make sure we have texture storage (normally this is handled by + // the glTexStorage2D calls above, if immutable texture storage is + // supported and enabled), it makes other things easier down the line. + if (needs_reload) { + PStatTimer timer(_create_texture_storage_pcollector); + if (!upload_texture_level(true, compressed, target, level, + width, height, depth, internal_format, + external_format, component_type, + nullptr, page_size, pages, usage)) { + if (level == 0) { + // If level 0 failed to create, this texture is useless. + success = false; } - } else { - report_my_gl_errors(); - return false; + else if (_supports_texture_max_level) { + // Apparently, this is all it's going to get. + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, level - 1); + } + break; } - break; -#endif // OPENGLES_1 + } -#ifndef OPENGLES_1 - case GL_TEXTURE_BUFFER: - if (_supports_buffer_texture) { - _glBufferSubData(GL_TEXTURE_BUFFER, 0, page_size, image_ptr); - } else { - report_my_gl_errors(); - return false; - } - break; -#endif // OPENGLES + // Spawn a task to do the upload asynchronously into the PBO. + if (image_ptr != nullptr) { + void *mapped_level_ptr = (char *)mapped_ptr + pbo_offset; - case GL_TEXTURE_CUBE_MAP: - if (_supports_cube_map) { - // This is the only texture type that must be specified using separate - // per-page calls. - if (n == 0) { - height = tex->get_y_size() - tex->get_pad_y_size(); + if (ptimage) { + ptimage.node_ref(); + } + _async_chain->add([=, ptimage = std::move(ptimage), token = counter.make_token()](AsyncTask *task) mutable { + { + PStatTimer timer(_load_texture_copy_pcollector); + copy_image((unsigned char *)mapped_level_ptr, image_ptr, orig_view_size, + external_format, num_components, component_width); } - for (int z = 0; z < 6; ++z) { - if (pages.get_bit(z)) { - GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; - const unsigned char *page_ptr = image_ptr + page_size * z; - - if (image_compression == Texture::CM_off) { - glTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height, - external_format, component_type, page_ptr); - } else { - _glCompressedTexSubImage2D(page_target, n - mipmap_bias, - 0, 0, width, height, - external_format, page_size, page_ptr); - } - } + if (ptimage) { + ptimage.node_unref(); } - } else { - report_my_gl_errors(); - return false; + + token.complete(true); + return AsyncTask::DS_done; + }, "copy:" + tex->get_name()); + + if (async_levels == nullptr) { + async_levels = new AsyncLevel[num_levels + 1]; } + async_levels[num_async_levels++] = {width, sub_height, depth, page_size, pbo_offset, std::move(pages)}; + pbo_offset += page_size * depth; + continue; + } + } +#endif + if (image_ptr != nullptr) { + if (page_size != orig_page_size || external_format == GL_RGBA || external_format == GL_RGB) { + // If the GL doesn't claim to support BGR, we may have to reverse + // the component ordering of the image. + PStatTimer timer(_load_texture_copy_pcollector); + PTA_uchar new_image = PTA_uchar::empty_array(page_size * depth); + copy_image(&new_image[0], image_ptr, orig_view_size, + external_format, num_components, component_width); + + ptimage = std::move(new_image); + image_ptr = ptimage; + } + } + + // Try updating the existing storage (sub-loading) first. + if (!needs_reload) { + if (!upload_texture_level(false, compressed, target, level, + width, sub_height, depth, internal_format, + external_format, component_type, + image_ptr, page_size, pages, usage)) { break; + } - default: - if (image_compression == Texture::CM_off) { - if (n == 0) { - // It's unfortunate that we can't adjust the width, too, but - // TexSubImage2D doesn't accept a row-stride parameter. - height = tex->get_y_size() - tex->get_pad_y_size(); - } - glTexSubImage2D(target, n - mipmap_bias, 0, 0, width, height, - external_format, component_type, image_ptr); - } else { - _glCompressedTexSubImage2D(target, n - mipmap_bias, 0, 0, width, height, - external_format, page_size, image_ptr); + // Did that fail? If it did, we'll immediately try again, this time + // loading the texture from scratch. + GLenum error_code = gl_get_error(); + if (error_code != GL_NO_ERROR) { + if (GLCAT.is_warning()) { + GLCAT.warning() + << "GL texture subload failed for " << tex->get_name() + << " level " << level << ": " << get_error_string(error_code) << "\n"; } - break; + needs_reload = true; } } - // Did that fail? If it did, we'll immediately try again, this time - // loading the texture from scratch. - GLenum error_code = gl_get_error(); - if (error_code != GL_NO_ERROR) { - if (GLCAT.is_debug()) { - GLCAT.debug() - << "GL texture subload failed for " << tex->get_name() - << " : " << get_error_string(error_code) << "\n"; + if (needs_reload) { + if (!upload_texture_level(true, compressed, target, level, + width, height, depth, internal_format, + external_format, component_type, + image_ptr, page_size, pages, usage)) { + + if (_supports_texture_max_level) { + // Apparently, this is all it's going to get. + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, level); + } + if (level == 0) { + success = false; + } + break; } - needs_reload = true; } } + // Purely synchronous path, we can finish up the creation now. + // Report the error message explicitly if the GL texture creation failed. if (needs_reload) { - // Load the image up from scratch, creating a new GL Texture object. - if (GLCAT.is_debug()) { - GLCAT.debug() - << "loading new texture object for " << tex->get_name() << " view " - << view << ", " << width << " x " << height << " x " << depth - << ", mipmaps " << num_ram_mipmap_levels << " / " << num_levels << "\n"; + GLenum error_code = gl_get_error(); + if (error_code != GL_NO_ERROR) { + GLCAT.error() + << "GL texture creation failed for " << tex->get_name() + << " : " << get_error_string(error_code) << "\n"; + + gtc->_has_storage = false; + success = false; } + } - // If there is immutable storage, this is impossible to do, and we should - // not have gotten here at all. - nassertr(!gtc->_immutable, false); +#if defined(HAVE_THREADS) && !defined(OPENGLES_1) + if (async_levels != nullptr) { + // Schedule a follow-up task to finish the upload, which needs to happen + // with bound context, so we use a special mini job queue for that. - if (num_ram_mipmap_levels == 0) { - if (GLCAT.is_debug()) { - GLCAT.debug() - << " (initializing NULL image)\n"; - } + // Storing 0 as last item saves some closure space. + async_levels[num_async_levels] = {0}; - if ((external_format == GL_DEPTH_STENCIL) && get_supports_depth_stencil()) { -#ifdef OPENGLES - component_type = GL_UNSIGNED_INT_24_8_OES; -#else - component_type = GL_UNSIGNED_INT_24_8_EXT; -#endif - } - } - - for (int n = mipmap_bias; n < num_levels + mipmap_bias; ++n) { - const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n); - CPTA_uchar ptimage; - if (image_ptr == nullptr) { - ptimage = tex->get_ram_mipmap_image(n); - if (ptimage.is_null()) { - if (n - mipmap_bias < num_ram_mipmap_levels) { - // We were told we'd have this many RAM mipmap images, but we - // don't. Raise a warning. - GLCAT.warning() - << "No mipmap level " << n << " defined for " << tex->get_name() - << "\n"; - if (_supports_texture_max_level) { - // Tell the GL we have no more mipmaps for it to use. - glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias); + std::move(counter).then([ + this, token = std::move(token), + async_levels, gtc, view, pbo, pbo_size, upload_count, + external_format, component_type, compressed + ] (bool success) mutable { + call_later([=, token = std::move(token)] () mutable { + _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); + _glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + + if (gtc->_uploads_finished - upload_count >= 0) { + // Updates arrived out of order, so we skip this one, since a newer + // update was already finished. + GLCAT.info() + << "Discarding async update #" << upload_count << " to texture " + << gtc->get_texture()->get_name() << "\n"; + success = false; + } + else if (view >= gtc->_num_views) { + // If we uploaded a view that is no longer needed, we silently + // consider it a success, even if the task failed. + success = true; + } + else if (!apply_texture(gtc, view)) { + success = false; + } + else if (success) { + PStatTimer timer(_load_texture_pcollector); + + if (gtc->_target == GL_TEXTURE_BUFFER) { + // We can use a trick for buffer textures: just swap the "PBO" with + // the existing texture storage. The existing storage becomes the + // new PBO. Note also that buffer textures have no mipmaps. + _glTexBuffer(GL_TEXTURE_BUFFER, gtc->_internal_format, pbo); + std::swap(pbo, gtc->_buffers[view]); + } + else { + for (int level = 0; async_levels[level].width != 0; ++level) { + AsyncLevel &data = async_levels[level]; + if (!upload_texture_level(false, compressed, gtc->_target, level, + data.width, data.height, data.depth, + gtc->_internal_format, external_format, + component_type, (unsigned char *)data.pbo_offset, + data.page_size, data.pages, GL_STATIC_DRAW)) { + if (_supports_texture_max_level && !gtc->_generate_mipmaps) { + // Apparently, this is all it's going to get. + glTexParameteri(gtc->_target, GL_TEXTURE_MAX_LEVEL, level - 1); + } + success = false; + break; + } } - break; } - if (tex->has_clear_color()) { - // Ask the Texture class to create the mipmap level in RAM. It'll - // fill it in with the correct clear color, which we can then - // upload. - ptimage = tex->make_ram_mipmap_image(n); + if (success) { + gtc->_uploads_finished = upload_count; } - else if (image_compression != Texture::CM_off) { - // We can't upload a NULL compressed texture. - if (_supports_texture_max_level) { - // Tell the GL we have no more mipmaps for it to use. - glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias); + + if (gtc->_generate_mipmaps && _glGenerateMipmap != nullptr) { + // We uploaded an image; we may need to generate mipmaps. + if (GLCAT.is_debug()) { + GLCAT.debug() + << "generating mipmaps for texture " << gtc->get_texture()->get_name() + << " view " << view << ", " << async_levels[0].width << " x " + << async_levels[0].height << " x " << async_levels[0].depth + << ", mipmaps = " << gtc->_num_levels + << " (async update #" << upload_count << ")\n"; + } + _glGenerateMipmap(gtc->_target); + } + + if (success && gtc->get_texture()->get_post_load_store_cache()) { + if (!do_extract_texture_data(gtc, view)) { + success = false; } - break; } } - image_ptr = ptimage; + _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + // This goes back into the pool. + gtc->return_pbo(pbo, pbo_size); + + token.complete(success); + + delete[] async_levels; + }); + }); + } else +#endif + { + // This ensures any pending async op will not overwrite what we just did. + gtc->_uploads_finished = upload_count; + + if (pbo != 0) { + // For whatever reason, we haven't used the PBO, so return it. + gtc->return_pbo(pbo, pbo_size); + } + + if (gtc->_generate_mipmaps && _glGenerateMipmap != nullptr && !image.is_null()) { + // We uploaded an image; we may need to generate mipmaps. + if (GLCAT.is_debug()) { + GLCAT.debug() + << "generating mipmaps for texture " << gtc->get_texture()->get_name() << " view " + << view << ", " << width << " x " << height << " x " << depth + << ", mipmaps = " << num_levels << "\n"; } + _glGenerateMipmap(gtc->_target); + } - PTA_uchar bgr_image; - size_t view_size = tex->get_ram_mipmap_view_size(n); - if (image_ptr != nullptr) { - const unsigned char *orig_image_ptr = image_ptr; - image_ptr += view_size * view; - nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false); - - if (image_compression == Texture::CM_off) { - // If the GL doesn't claim to support BGR, we may have to reverse - // the component ordering of the image. - image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size, - external_format, tex); - } + if (gtc->get_texture()->get_post_load_store_cache()) { + if (!do_extract_texture_data(gtc, view)) { + success = false; } + } - int width = tex->get_expected_mipmap_x_size(n); - int height = tex->get_expected_mipmap_y_size(n); -#ifndef OPENGLES_1 - int depth = tex->get_expected_mipmap_z_size(n); -#endif + token.complete(success); + } -#ifdef DO_PSTATS - _data_transferred_pcollector.add_level(view_size); -#endif - switch (target) { -#ifndef OPENGLES // 1-d textures not supported by OpenGL ES. Fall through. - case GL_TEXTURE_1D: - if (image_compression == Texture::CM_off) { - glTexImage1D(target, n - mipmap_bias, internal_format, - width, 0, external_format, component_type, image_ptr); - } else { - _glCompressedTexImage1D(target, n - mipmap_bias, external_format, - width, 0, view_size, image_ptr); - } - break; -#endif // OPENGLES // OpenGL ES will fall through. + report_my_gl_errors(); -#ifndef OPENGLES_1 - case GL_TEXTURE_3D: - if (_supports_3d_texture) { - if (image_compression == Texture::CM_off) { - _glTexImage3D(target, n - mipmap_bias, internal_format, - width, height, depth, 0, - external_format, component_type, image_ptr); - } else { - _glCompressedTexImage3D(target, n - mipmap_bias, external_format, - width, height, depth, 0, view_size, image_ptr); - } - } else { - report_my_gl_errors(); - return false; - } - break; -#endif // OPENGLES_1 + return success; +} +/** + * Performs the actual OpenGL call to update the texture data for the given + * mipmap level (be sure to subtract the mipmap_bias before passing it in). + * + * If full_reload is true, recreates the texture storage, otherwise subloads + * into the existing texture storage. A texture storage with undefined + * contents can be created by setting image_ptr to nullptr, in which case + * compressed must be false. + * + * Returns true if this texture format was supported, false otherwise. + */ +bool CLP(GraphicsStateGuardian):: +upload_texture_level(bool full_reload, bool compressed, GLenum target, + int level, int width, int height, int depth, + GLint internal_format, GLint external_format, + GLenum component_type, const unsigned char *image_ptr, + size_t page_size, SparseArray pages, + GLenum usage_hint) { + + switch (target) { #ifndef OPENGLES_1 - case GL_TEXTURE_2D_ARRAY: - case GL_TEXTURE_CUBE_MAP_ARRAY: - if (_supports_2d_texture_array) { - if (image_compression == Texture::CM_off) { - _glTexImage3D(target, n - mipmap_bias, internal_format, - width, height, depth, 0, - external_format, component_type, image_ptr); - } else { - _glCompressedTexImage3D(target, n - mipmap_bias, external_format, - width, height, depth, 0, view_size, image_ptr); - } - } else { - report_my_gl_errors(); - return false; - } - break; + case GL_TEXTURE_3D: + if (!_supports_3d_texture) { + return false; + } - case GL_TEXTURE_BUFFER: - if (_supports_buffer_texture) { - _glBufferData(GL_TEXTURE_BUFFER, view_size, image_ptr, - get_usage(tex->get_usage_hint())); + if (full_reload) { + if (!compressed) { + _glTexImage3D(target, level, internal_format, + width, height, depth, 0, + external_format, component_type, image_ptr); + } else { + _glCompressedTexImage3D(target, level, external_format, + width, height, depth, 0, page_size * depth, image_ptr); + } + } else { + for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { + int begin = pages.get_subrange_begin(sri); + int num_pages = pages.get_subrange_end(sri) - begin; + const unsigned char *page_ptr = image_ptr + page_size * begin; + + if (!compressed) { + _glTexSubImage3D(target, level, + 0, 0, begin, width, height, num_pages, + external_format, component_type, page_ptr); } else { - report_my_gl_errors(); - return false; + _glCompressedTexSubImage3D(target, level, + 0, 0, begin, width, height, num_pages, + external_format, + page_size * num_pages, page_ptr); } - break; + } + } + break; #endif // OPENGLES_1 - case GL_TEXTURE_CUBE_MAP: - if (_supports_cube_map) { - // This is the only texture type that must be specified using separate - // per-page calls. - size_t page_size = tex->get_ram_mipmap_page_size(n); - for (int z = 0; z < 6; ++z) { - GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; - const unsigned char *page_ptr = - (image_ptr != nullptr) ? image_ptr + page_size * z : nullptr; - - if (image_compression == Texture::CM_off) { - glTexImage2D(page_target, n - mipmap_bias, internal_format, - width, height, 0, +#ifndef OPENGLES_1 + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: + if (!_supports_2d_texture_array) { + return false; + } + + if (full_reload) { + if (!compressed) { + _glTexImage3D(target, level, internal_format, width, height, depth, 0, + external_format, component_type, image_ptr); + } else { + _glCompressedTexImage3D(target, level, external_format, + width, height, depth, 0, + page_size * depth, image_ptr); + } + } else { + for (size_t sri = 0; sri < pages.get_num_subranges(); ++sri) { + int begin = pages.get_subrange_begin(sri); + int num_pages = pages.get_subrange_end(sri) - begin; + const unsigned char *page_ptr = image_ptr + page_size * begin; + + if (!compressed) { + _glTexSubImage3D(target, level, + 0, 0, begin, width, height, num_pages, external_format, component_type, page_ptr); - } else { - _glCompressedTexImage2D(page_target, n - mipmap_bias, external_format, - width, height, 0, page_size, page_ptr); - } - } } else { - report_my_gl_errors(); - return false; + _glCompressedTexSubImage3D(target, level, + 0, 0, begin, width, height, num_pages, + external_format, + page_size * num_pages, page_ptr); } - break; + } + } + break; +#endif // !OPENGLES_1 - default: - if (image_compression == Texture::CM_off) { - glTexImage2D(target, n - mipmap_bias, internal_format, - width, height, 0, - external_format, component_type, image_ptr); +#ifndef OPENGLES_1 + case GL_TEXTURE_BUFFER: + if (!_supports_buffer_texture) { + return false; + } + + if (full_reload) { + _glBufferData(GL_TEXTURE_BUFFER, page_size, image_ptr, usage_hint); + } else { + _glBufferSubData(GL_TEXTURE_BUFFER, 0, page_size, image_ptr); + } + break; +#endif // !OPENGLES_1 + + case GL_TEXTURE_CUBE_MAP: + if (!_supports_cube_map) { + return false; + } + + // This is the only texture type that must be specified using separate + // per-page calls. + if (full_reload) { + for (int z = 0; z < 6; ++z) { + GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; + const unsigned char *page_ptr = + (image_ptr != nullptr) ? image_ptr + page_size * z : nullptr; + + if (!compressed) { + glTexImage2D(page_target, level, internal_format, width, height, 0, + external_format, component_type, page_ptr); } else { - _glCompressedTexImage2D(target, n - mipmap_bias, external_format, - width, height, 0, view_size, image_ptr); + _glCompressedTexImage2D(page_target, level, external_format, + width, height, 0, page_size, page_ptr); + } + } + } else { + for (int z = 0; z < 6; ++z) { + if (pages.get_bit(z)) { + GLenum page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; + const unsigned char *page_ptr = image_ptr + page_size * z; + + if (!compressed) { + glTexSubImage2D(page_target, level, 0, 0, width, height, + external_format, component_type, page_ptr); + } else { + _glCompressedTexSubImage2D(page_target, level, + 0, 0, width, height, + external_format, page_size, page_ptr); + } } } } + break; - // Report the error message explicitly if the GL texture creation failed. - GLenum error_code = gl_get_error(); - if (error_code != GL_NO_ERROR) { - GLCAT.error() - << "GL texture creation failed for " << tex->get_name() - << " : " << get_error_string(error_code) << "\n"; +#ifndef OPENGLES + case GL_TEXTURE_1D: + if (full_reload) { + if (!compressed) { + glTexImage1D(target, level, internal_format, + width, 0, external_format, component_type, image_ptr); + } else { + _glCompressedTexImage1D(target, level, external_format, + width, 0, page_size, image_ptr); + } + } else { + if (!compressed) { + glTexSubImage1D(target, level, 0, width, + external_format, component_type, image_ptr); + } else { + _glCompressedTexSubImage1D(target, level, 0, width, + external_format, page_size, image_ptr); + } + } + break; +#endif // !OPENGLES - gtc->_has_storage = false; - return false; + default: + if (full_reload) { + if (!compressed) { + glTexImage2D(target, level, internal_format, width, height, 0, + external_format, component_type, image_ptr); + } else { + _glCompressedTexImage2D(target, level, external_format, + width, height, 0, page_size, image_ptr); + } + } else { + if (!compressed) { + glTexSubImage2D(target, level, 0, 0, width, height, + external_format, component_type, image_ptr); + } else { + _glCompressedTexSubImage2D(target, level, 0, 0, width, height, + external_format, page_size, image_ptr); + } } + break; + } + +#ifdef DO_PSTATS + if (full_reload) { + _data_transferred_pcollector.add_level(page_size * depth); + } else { + _data_transferred_pcollector.add_level(pages.get_num_on_bits() * depth); } +#endif - if (gtc->_generate_mipmaps && _glGenerateMipmap != nullptr && !image.is_null()) { - // We uploaded an image; we may need to generate mipmaps. + // Did that fail? If it did, we'll immediately try again, this time + // loading the texture from scratch. + /*GLenum error_code = gl_get_error(); + if (error_code != GL_NO_ERROR) { if (GLCAT.is_debug()) { GLCAT.debug() - << "generating mipmaps for texture " << tex->get_name() << " view " - << view << ", " << width << " x " << height << " x " << depth - << ", mipmaps = " << num_levels << "\n"; + << "GL texture subload failed for " << tex->get_name() + << " : " << get_error_string(error_code) << "\n"; } - _glGenerateMipmap(target); - } - - report_my_gl_errors(); - + full_reload = true; + }*/ return true; } @@ -15054,6 +15591,7 @@ get_texture_memory_size(CLP(TextureContext) *gtc) { void CLP(GraphicsStateGuardian):: check_nonresident_texture(BufferContextChain &chain) { #if defined(SUPPORT_FIXED_FUNCTION) && !defined(OPENGLES) // Residency queries not supported by OpenGL ES. + LightMutexHolder holder(chain._lock); size_t num_textures = chain.get_count(); if (num_textures == 0) { return; @@ -15105,7 +15643,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc, int view) { #ifndef OPENGLES_1 // Make sure any incoherent writes to the texture have been synced. - if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) { + if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT, false)) { issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT); } #endif @@ -16108,3 +16646,160 @@ do_issue_scissor() { } } } + +#ifndef OPENGLES_1 +/** + * Maps a buffer for reading. May be temporarily bound to the given target. + */ +void *CLP(GraphicsStateGuardian):: +map_read_buffer(GLenum target, GLuint buffer, size_t size) { + nassertr(buffer != 0, nullptr); + +#ifndef OPENGLES + if (_glMapNamedBufferRange != nullptr) { + return _glMapNamedBufferRange(buffer, 0, size, GL_MAP_READ_BIT); + } +#endif + + void *mapped_ptr = nullptr; + + _glBindBuffer(target, buffer); +#ifdef OPENGLES + // There is neither glMapBuffer nor persistent mapping in OpenGL ES + mapped_ptr = _glMapBufferRange(target, 0, size, GL_MAP_READ_BIT); +#else + // If we get here in desktop GL, we must not have persistent mapping + mapped_ptr = _glMapBuffer(target, GL_READ_ONLY); +#endif + + _glBindBuffer(target, 0); + return mapped_ptr; +} + +/** + * Maps a buffer as write-only, discarding the previous contents. If + * create_storage is true, allocates new storage for the buffer. May use the + * given target to temporarily bind the buffer, if DSA is not supported. + */ +void *CLP(GraphicsStateGuardian):: +map_write_discard_buffer(GLenum target, GLuint buffer, size_t size, + bool create_storage) { + nassertr(buffer != 0, nullptr); + +#ifndef OPENGLES + if (!create_storage && _glMapNamedBufferRange != nullptr) { + return _glMapNamedBufferRange(buffer, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + } +#endif + + _glBindBuffer(target, buffer); + + void *mapped_ptr; + if (_glMapBufferRange != nullptr) { + if (create_storage) { + if (_supports_buffer_storage) { + _glBufferStorage(target, size, nullptr, GL_MAP_WRITE_BIT); + } else { + _glBufferData(target, size, nullptr, GL_STATIC_DRAW); + } + } + mapped_ptr = _glMapBufferRange(target, 0, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + } else { +#ifdef OPENGLES + mapped_ptr = nullptr; +#else + // Explicitly orphan the buffer before mapping. + _glBufferData(target, size, nullptr, GL_STATIC_DRAW); + mapped_ptr = _glMapBuffer(target, GL_WRITE_ONLY); +#endif + } + + _glBindBuffer(target, 0); + return mapped_ptr; +} +#endif // !OPENGLES_1 + +#ifndef OPENGLES_1 +/** + * Inserts a fence into the command stream. + */ +void CLP(GraphicsStateGuardian):: +insert_fence(CompletionToken &&callback) { + GLsync fence = _glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + _fences.push_back({fence, std::move(callback)}); +} + +/** + * Checks which fences are finished and processes those. + */ +void CLP(GraphicsStateGuardian):: +process_fences(bool force) { + if (_fences.empty()) { + return; + } + + PStatTimer timer(_copy_texture_finish_pcollector); + + if (force) { + // Just wait for the last fence, the rest must be complete too then. + PStatTimer timer(_wait_fence_pcollector); + GLsync fence = _fences.back()._object; + _glClientWaitSync(fence, 0, (GLuint64)-1); + } + + while (!_fences.empty()) { + Fence &fence = _fences.front(); + if (!force) { + GLenum result = _glClientWaitSync(fence._object, 0, 0); + if (result != GL_ALREADY_SIGNALED && result != GL_CONDITION_SATISFIED) { + // Not yet done. The rest must not yet be done then, either. + break; + } + } + _glDeleteSync(fence._object); + + std::move(fence._token).complete(true); + _fences.pop_front(); + + // If there is 1 remaining, save it for next frame. This helps prevent an + // inconsistent frame rate when the number of fetched frames alternates + // between 0 and 2, which can settle into a stable feedback loop. + if (!force && _fences.size() == 1) { + break; + } + } +} +#endif // !OPENGLES_1 + +/** + * Adds a job to the queue to be processed later while the context is bound, + * useful for calling from other threads. + */ +void CLP(GraphicsStateGuardian):: +call_later(Completable &&job) { + MutexHolder holder(_job_queue_mutex); + _job_queue.push_back(std::move(job)); + _job_queue_cvar.notify(); +} + +/** + * Processes any pending jobs from the queue. If wait is true, waits for at + * least one job if the queue is empty. + * + * May only be called on the draw thread. + */ +void CLP(GraphicsStateGuardian):: +process_pending_jobs(bool wait) { + JobQueue jobs; + { + MutexHolder holder(_job_queue_mutex); + if (wait && _job_queue.empty()) { + _job_queue_cvar.wait(); + } + _job_queue.swap(jobs); + } + + for (auto &job : jobs) { + std::move(job)(); + } +} diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 1abbc1d2a4e..98bd8d3508f 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -39,6 +39,8 @@ #include "geomVertexArrayData.h" #include "lightMutex.h" #include "pStatGPUTimer.h" +#include "completionToken.h" +#include "asyncTaskChain.h" class PlaneNode; class Light; @@ -166,6 +168,7 @@ typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei buf typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data); typedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLSHADERSOURCEPROC_P) (GLuint shader, GLsizei count, const GLchar* const *string, const GLint *length); typedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program); @@ -230,6 +233,7 @@ typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufS typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params); typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); +typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data); typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); @@ -345,7 +349,8 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { #endif virtual TextureContext *prepare_texture(Texture *tex); - virtual bool update_texture(TextureContext *tc, bool force); + virtual bool update_texture(TextureContext *tc, bool force, + CompletionToken token = CompletionToken()); virtual void release_texture(TextureContext *tc); virtual void release_textures(const pvector &contexts); virtual bool extract_texture_data(Texture *tex); @@ -391,9 +396,10 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { #ifndef OPENGLES virtual BufferContext *prepare_shader_buffer(ShaderBuffer *data); - void apply_shader_buffer(GLuint base, ShaderBuffer *buffer); + CLP(BufferContext) *apply_shader_buffer(GLuint base, ShaderBuffer *buffer); virtual void release_shader_buffer(BufferContext *bc); virtual void release_shader_buffers(const pvector &contexts); + virtual bool extract_shader_buffer_data(ShaderBuffer *buffer, vector_uchar &data); #endif #ifndef OPENGLES @@ -418,7 +424,6 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { virtual bool framebuffer_copy_to_ram (Texture *tex, int view, int z, const DisplayRegion *dr, const RenderBuffer &rb, ScreenshotRequest *request); - void finish_async_framebuffer_ram_copies(bool force = false); #ifdef SUPPORT_FIXED_FUNCTION void apply_fog(Fog *fog); @@ -636,12 +641,21 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { bool apply_texture(CLP(TextureContext) *gtc, int view); bool apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc, int view); - bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps); - bool upload_texture_image(CLP(TextureContext) *gtc, int view, - bool needs_reload, int mipmap_bias, int num_levels, + bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps, + CompletionToken token = CompletionToken()); + bool upload_texture_view(CLP(TextureContext) *gtc, int view, + bool needs_reload, int mipmap_bias, int num_levels, + GLint internal_format, GLint external_format, + GLenum component_type, bool compressed, + int async_buffers, CompletionToken token); + bool upload_texture_level(bool full_reload, bool compressed, + GLenum target, int level, + int width, int height, int depth, GLint internal_format, GLint external_format, GLenum component_type, - Texture::CompressionMode image_compression); + const unsigned char *image_ptr, + size_t page_size, SparseArray pages, + GLenum usage_hint); void generate_mipmaps(CLP(TextureContext) *gtc); bool upload_simple_texture(CLP(TextureContext) *gtc); @@ -657,6 +671,20 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { void do_point_size(); #endif +#ifndef OPENGLES_1 + void *map_read_buffer(GLenum target, GLuint buffer, size_t size); + void *map_write_discard_buffer(GLenum target, GLuint buffer, size_t size, + bool create_storage); +#endif + +#ifndef OPENGLES_1 + void insert_fence(CompletionToken &&callback); + void process_fences(bool force); +#endif + + void call_later(Completable &&job); + void process_pending_jobs(bool wait); + enum AutoAntialiasMode { AA_poly, AA_line, @@ -796,6 +824,10 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { #endif public: +#ifndef OPENGLES_1 + PFNGLGETINTEGERI_VPROC _glGetIntegeri_v; +#endif + #ifndef OPENGLES_1 bool _use_depth_zero_to_one; bool _use_remapped_depth_range; @@ -903,6 +935,10 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { PFNGLGETBUFFERSUBDATAPROC _glGetBufferSubData; #endif +#ifndef OPENGLES_1 + PFNGLCOPYBUFFERSUBDATAPROC _glCopyBufferSubData; +#endif + #ifdef OPENGLES PFNGLMAPBUFFERRANGEEXTPROC _glMapBufferRange; PFNGLUNMAPBUFFEROESPROC _glUnmapBuffer; @@ -910,6 +946,10 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { PFNGLMAPBUFFERRANGEPROC _glMapBufferRange; #endif +#ifndef OPENGLES_1 + bool _supports_pixel_buffers; +#endif + #ifndef OPENGLES_1 bool _supports_uniform_buffers; bool _supports_shader_buffers; @@ -977,6 +1017,7 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { PFNGLTEXTUREPARAMETERIPROC _glTextureParameteri; PFNGLGENERATETEXTUREMIPMAPPROC _glGenerateTextureMipmap; PFNGLBINDTEXTUREUNITPROC _glBindTextureUnit; + PFNGLMAPNAMEDBUFFERRANGEPROC _glMapNamedBufferRange; #endif #ifndef OPENGLES_1 @@ -1161,12 +1202,15 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { #endif #ifndef OPENGLES_1 - // Stores textures for which memory bariers should be issued. - typedef pset TextureSet; - TextureSet _textures_needing_fetch_barrier; - TextureSet _textures_needing_image_access_barrier; - TextureSet _textures_needing_update_barrier; - TextureSet _textures_needing_framebuffer_barrier; + // This count increments every time the corresponding barrier is issued. + // GLTextureContext et al store copies of this counter, when a write is + // performed on a texture, it will set its counter to match the value on the + // GSG to indicate that it is out of sync and the barrier needs to be issued. + int _texture_fetch_barrier_counter = 0; + int _shader_image_access_barrier_counter = 0; + int _texture_update_barrier_counter = 0; + int _framebuffer_barrier_counter = 0; + int _shader_storage_barrier_counter = 0; #endif // RenderState::SlotMask _inv_state_mask; @@ -1216,16 +1260,21 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { FrameTiming *_current_frame_timing = nullptr; #endif - struct AsyncRamCopy { - PT(ScreenshotRequest) _request; - GLuint _pbo; - GLsync _fence; - GLuint _external_format; - int _view; - void *_mapped_pointer; - size_t _size; + struct Fence { + GLsync _object; + CompletionToken _token; }; - pdeque _async_ram_copies; + pdeque _fences; + +#ifdef HAVE_THREADS + AsyncTaskChain *_async_chain; +#endif + + // Min job system pending a real job system + typedef pvector JobQueue; + Mutex _job_queue_mutex; + ConditionVar _job_queue_cvar; + JobQueue _job_queue; BufferResidencyTracker _renderbuffer_residency; @@ -1270,6 +1319,7 @@ class EXPCL_GL CLP(GraphicsStateGuardian) : public GraphicsStateGuardian { friend class CLP(BufferContext); friend class CLP(ShaderContext); friend class CLP(CgShaderContext); + friend class CLP(TextureContext); friend class CLP(GraphicsBuffer); friend class CLP(OcclusionQueryContext); }; diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 7b1fff3273b..169ae1b6708 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -208,7 +208,7 @@ parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, GLenum param_t // We'll permit this too, simply because we can support it. switch (param_type) { case GL_FLOAT: - bind._piece = Shader::SMP_float; + bind._piece = Shader::SMP_scalar; break; case GL_FLOAT_VEC2: bind._piece = Shader::SMP_vec2; @@ -290,7 +290,6 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext _color_attrib_index = -1; _transform_table_index = -1; _slider_table_index = -1; - _frame_number_loc = -1; _frame_number = -1; _validated = !gl_validate_shaders; @@ -404,7 +403,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext param_count = 0; _glgsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORMS, ¶m_count); - _shader->_ptr_spec.clear(); + //_shader->_ptr_spec.clear(); _shader->_mat_spec.clear(); _shader->_tex_spec.clear(); for (int i = 0; i < param_count; ++i) { @@ -421,6 +420,11 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext } _mat_part_cache = new LVecBase4f[_shader->cp_get_mat_cache_size()]; + _mat_scratch_space = new LVecBase4f[_shader->cp_get_mat_scratch_size()]; + +#ifdef DO_PSTATS + _compute_dispatch_pcollector = PStatCollector(glgsg->_compute_dispatch_pcollector, s->get_debug_name()); +#endif } /** @@ -478,6 +482,8 @@ reflect_attribute(int i, char *name_buffer, GLsizei name_buflen) { case GL_BOOL_VEC2: case GL_BOOL_VEC3: case GL_BOOL_VEC4: + bind._numeric_type = Shader::SPT_bool; + break; case GL_UNSIGNED_INT: case GL_UNSIGNED_INT_VEC2: case GL_UNSIGNED_INT_VEC3: @@ -957,10 +963,11 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } bind._func = Shader::SMF_first; - bind._part[0] = Shader::SMO_apiview_to_apiclip_light_source_i; + bind._part[0] = Shader::SMO_light_source_i; bind._arg[0] = nullptr; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; + bind._offset = 4 * Shader::LA_shadow_view_matrix; } else if (strncmp(name_buffer, "shadowMatrix", 127) == 0) { // Only supported for backward compatibility: includes the model @@ -1071,90 +1078,88 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { GLCAT.error() << "p3d_Material.baseColor should be vec4\n"; } - bind._part[0] = Shader::SMO_attr_material2; + bind._offset = 4 * Shader::MA_base_color; bind._piece = Shader::SMP_vec4; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.ambient") { + } + else if (noprefix == "Material.ambient") { if (param_type != GL_FLOAT_VEC4) { GLCAT.error() << "p3d_Material.ambient should be vec4\n"; } + bind._offset = 4 * Shader::MA_ambient; bind._piece = Shader::SMP_vec4; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.diffuse") { + } + else if (noprefix == "Material.diffuse") { if (param_type != GL_FLOAT_VEC4) { GLCAT.error() << "p3d_Material.diffuse should be vec4\n"; } + bind._offset = 4 * Shader::MA_diffuse; bind._piece = Shader::SMP_vec4; - bind._offset = 4; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.emission") { + } + else if (noprefix == "Material.emission") { if (param_type != GL_FLOAT_VEC4) { GLCAT.error() << "p3d_Material.emission should be vec4\n"; } + bind._offset = 4 * Shader::MA_emission; bind._piece = Shader::SMP_vec4; - bind._offset = 8; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.specular") { + } + else if (noprefix == "Material.specular") { if (param_type != GL_FLOAT_VEC3) { GLCAT.error() << "p3d_Material.specular should be vec3\n"; } + bind._offset = 4 * Shader::MA_specular; bind._piece = Shader::SMP_vec3; - bind._offset = 12; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.shininess") { + } + else if (noprefix == "Material.shininess") { if (param_type != GL_FLOAT) { GLCAT.error() << "p3d_Material.shininess should be float\n"; } - bind._piece = Shader::SMP_float; - bind._offset = 15; + bind._offset = 4 * Shader::MA_specular + 3; + bind._piece = Shader::SMP_scalar; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.roughness") { + } + else if (noprefix == "Material.roughness") { if (param_type != GL_FLOAT) { GLCAT.error() << "p3d_Material.roughness should be float\n"; } - bind._part[0] = Shader::SMO_attr_material2; - bind._piece = Shader::SMP_float; - bind._offset = 7; + bind._offset = 4 * Shader::MA_metallic_ior_roughness + 3; + bind._piece = Shader::SMP_scalar; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.metallic") { + } + else if (noprefix == "Material.metallic") { if (param_type != GL_FLOAT && param_type != GL_BOOL) { GLCAT.error() << "p3d_Material.metallic should be bool or float\n"; } - bind._part[0] = Shader::SMO_attr_material2; - bind._piece = Shader::SMP_float; - bind._offset = 4; + bind._offset = 4 * Shader::MA_metallic_ior_roughness; + bind._piece = Shader::SMP_scalar; _shader->cp_add_mat_spec(bind); return; - - } else if (noprefix == "Material.refractiveIndex") { + } + else if (noprefix == "Material.refractiveIndex") { if (param_type != GL_FLOAT) { GLCAT.error() << "p3d_Material.refractiveIndex should be float\n"; } - bind._part[0] = Shader::SMO_attr_material2; - bind._piece = Shader::SMP_float; - bind._offset = 5; + bind._offset = 4 * Shader::MA_metallic_ior_roughness + 1; + bind._piece = Shader::SMP_scalar; _shader->cp_add_mat_spec(bind); return; } @@ -1228,7 +1233,8 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._arg[1] = nullptr; if (noprefix == "Fog.color") { - bind._part[0] = Shader::SMO_attr_fogcolor; + bind._part[0] = Shader::SMO_attr_fog; + bind._offset = 4 * Shader::FA_color; if (param_type == GL_FLOAT_VEC3) { bind._piece = Shader::SMP_vec3; @@ -1242,9 +1248,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } else if (noprefix == "Fog.density") { bind._part[0] = Shader::SMO_attr_fog; + bind._offset = 4 * Shader::FA_params; if (param_type == GL_FLOAT) { - bind._piece = Shader::SMP_float; + bind._piece = Shader::SMP_scalar; } else { GLCAT.error() << "p3d_Fog.density should be float\n"; @@ -1253,10 +1260,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } else if (noprefix == "Fog.start") { bind._part[0] = Shader::SMO_attr_fog; + bind._offset = 4 * Shader::FA_params + 1; if (param_type == GL_FLOAT) { - bind._piece = Shader::SMP_float; - bind._offset = 1; + bind._piece = Shader::SMP_scalar; } else { GLCAT.error() << "p3d_Fog.start should be float\n"; @@ -1265,10 +1272,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } else if (noprefix == "Fog.end") { bind._part[0] = Shader::SMO_attr_fog; + bind._offset = 4 * Shader::FA_params + 2; if (param_type == GL_FLOAT) { - bind._piece = Shader::SMP_float; - bind._offset = 2; + bind._piece = Shader::SMP_scalar; } else { GLCAT.error() << "p3d_Fog.end should be float\n"; @@ -1277,10 +1284,10 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { } else if (noprefix == "Fog.scale") { bind._part[0] = Shader::SMO_attr_fog; + bind._offset = 4 * Shader::FA_params + 3; if (param_type == GL_FLOAT) { - bind._piece = Shader::SMP_float; - bind._offset = 3; + bind._piece = Shader::SMP_scalar; } else { GLCAT.error() << "p3d_Fog.scale should be float\n"; @@ -1347,14 +1354,81 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._id = arg_id; bind._func = Shader::SMF_first; bind._index = index; - bind._part[0] = Shader::SMO_light_source_i_vec_attrib; - bind._arg[0] = InternalName::make(member_name); + bind._part[0] = Shader::SMO_light_source_i; + bind._arg[0] = nullptr; bind._part[1] = Shader::SMO_identity; bind._arg[1] = nullptr; + GLenum expected = GL_FLOAT_VEC4; + if (member_name == "color") { + bind._offset = 4 * Shader::LA_color; + } + else if (member_name == "specular") { + bind._offset = 4 * Shader::LA_specular; + } + else if (member_name == "ambient") { + bind._offset = 4 * Shader::LA_ambient; + } + else if (member_name == "diffuse") { + bind._offset = 4 * Shader::LA_diffuse; + } + else if (member_name == "position") { + bind._offset = 4 * Shader::LA_position; + } + else if (member_name == "halfVector") { + bind._offset = 4 * Shader::LA_half_vector; + } + else if (member_name == "spotDirection") { + bind._offset = 4 * Shader::LA_spot_direction; + } + else if (member_name == "spotCosCutoff") { + bind._offset = 4 * Shader::LA_spot_params; + expected = GL_FLOAT; + } + else if (member_name == "spotCutoff") { + bind._offset = 4 * Shader::LA_spot_params + 1; + expected = GL_FLOAT; + } + else if (member_name == "spotExponent") { + bind._offset = 4 * Shader::LA_spot_params + 2; + expected = GL_FLOAT; + } + else if (member_name == "attenuation") { + bind._offset = 4 * Shader::LA_attenuation; + expected = GL_FLOAT_VEC3; + } + else if (member_name == "constantAttenuation") { + bind._offset = 4 * Shader::LA_attenuation; + expected = GL_FLOAT; + } + else if (member_name == "linearAttenuation") { + bind._offset = 4 * Shader::LA_attenuation + 1; + expected = GL_FLOAT; + } + else if (member_name == "quadraticAttenuation") { + bind._offset = 4 * Shader::LA_attenuation + 2; + expected = GL_FLOAT; + } + else if (member_name == "radius") { + bind._offset = 4 * Shader::LA_attenuation + 3; + expected = GL_FLOAT; + } + else { + GLCAT.error() + << "Invalid light struct member " << member_name << "\n"; + return; + } + + // It's okay to declare as vec3 if we allow vec4. + if (param_type != expected && (expected != GL_FLOAT_VEC4 || param_type != GL_FLOAT_VEC3)) { + GLCAT.error() + << "p3d_LightSource[]." << member_name << " has unexpected type\n"; + return; + } + switch (param_type) { case GL_FLOAT: - bind._piece = Shader::SMP_float; + bind._piece = Shader::SMP_scalar; break; case GL_FLOAT_VEC2: @@ -1370,8 +1444,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { break; default: - GLCAT.error() - << "p3d_LightSource[]." << member_name << " should be float or vec\n"; + assert(false); return; } _shader->cp_add_mat_spec(bind); @@ -1442,7 +1515,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { return; } else if (noprefix == "FrameTime") { - bind._piece = Shader::SMP_float; + bind._piece = Shader::SMP_scalar; bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_frame_time; bind._part[1] = Shader::SMO_identity; @@ -1450,7 +1523,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { return; } else if (noprefix == "DeltaFrameTime") { - bind._piece = Shader::SMP_float; + bind._piece = Shader::SMP_scalar; bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_frame_delta; bind._part[1] = Shader::SMO_identity; @@ -1458,12 +1531,15 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { return; } else if (noprefix == "FrameNumber") { - // We don't currently support ints with this mechanism, so we special- - // case this one. + bind._piece = Shader::SMP_scalar; + bind._func = Shader::SMF_first; + bind._part[0] = Shader::SMO_frame_number; + bind._part[1] = Shader::SMO_identity; + bind._numeric_type = Shader::SPT_int; if (param_type != GL_INT) { GLCAT.error() << "osg_FrameNumber should be uniform int\n"; } else { - _frame_number_loc = p; + _shader->cp_add_mat_spec(bind); } return; } @@ -1596,7 +1672,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._id = arg_id; switch (param_type) { case GL_FLOAT: - bind._piece = Shader::SMP_float; + bind._piece = Shader::SMP_scalar; break; case GL_FLOAT_VEC2: bind._piece = Shader::SMP_vec2; @@ -1628,59 +1704,106 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { case GL_UNSIGNED_INT_VEC2: case GL_UNSIGNED_INT_VEC3: case GL_UNSIGNED_INT_VEC4: { - Shader::ShaderPtrSpec bind; + Shader::ShaderMatSpec bind; bind._id = arg_id; - switch (param_type) { - case GL_BOOL: - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: bind._dim[1] = 1; break; - case GL_BOOL_VEC2: - case GL_INT_VEC2: - case GL_UNSIGNED_INT_VEC2: - case GL_FLOAT_VEC2: bind._dim[1] = 2; break; - case GL_BOOL_VEC3: - case GL_INT_VEC3: - case GL_UNSIGNED_INT_VEC3: - case GL_FLOAT_VEC3: bind._dim[1] = 3; break; - case GL_BOOL_VEC4: - case GL_INT_VEC4: - case GL_UNSIGNED_INT_VEC4: - case GL_FLOAT_VEC4: bind._dim[1] = 4; break; - case GL_FLOAT_MAT3: bind._dim[1] = 9; break; - case GL_FLOAT_MAT4: bind._dim[1] = 16; break; - } + bind._func = Shader::SMF_shader_input_ptr; switch (param_type) { case GL_BOOL: + bind._piece = Shader::SMP_scalar; + bind._numeric_type = Shader::SPT_bool; + bind._num_components = 1; + break; case GL_BOOL_VEC2: + bind._piece = Shader::SMP_vec2; + bind._numeric_type = Shader::SPT_bool; + bind._num_components = 2; + break; case GL_BOOL_VEC3: + bind._piece = Shader::SMP_vec3; + bind._numeric_type = Shader::SPT_bool; + bind._num_components = 3; + break; case GL_BOOL_VEC4: + bind._piece = Shader::SMP_vec4; + bind._numeric_type = Shader::SPT_bool; + bind._num_components = 4; + break; case GL_UNSIGNED_INT: + bind._piece = Shader::SMP_scalar; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 1; + break; case GL_UNSIGNED_INT_VEC2: + bind._piece = Shader::SMP_vec2; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 2; + break; case GL_UNSIGNED_INT_VEC3: + bind._piece = Shader::SMP_vec3; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 3; + break; case GL_UNSIGNED_INT_VEC4: - bind._type = Shader::SPT_uint; + bind._piece = Shader::SMP_vec4; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 4; break; case GL_INT: + bind._piece = Shader::SMP_scalar; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 1; + break; case GL_INT_VEC2: + bind._piece = Shader::SMP_vec2; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 2; + break; case GL_INT_VEC3: + bind._piece = Shader::SMP_vec3; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 3; + break; case GL_INT_VEC4: - bind._type = Shader::SPT_int; + bind._piece = Shader::SMP_vec4; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 4; break; case GL_FLOAT: + bind._piece = Shader::SMP_scalar; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 1; + break; case GL_FLOAT_VEC2: + bind._piece = Shader::SMP_vec2; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 2; + break; case GL_FLOAT_VEC3: + bind._piece = Shader::SMP_vec3; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 3; + break; case GL_FLOAT_VEC4: + bind._piece = Shader::SMP_vec4; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 4; + break; case GL_FLOAT_MAT3: + bind._piece = Shader::SMP_mat3_whole; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 9; + break; case GL_FLOAT_MAT4: - bind._type = Shader::SPT_float; + bind._piece = Shader::SMP_mat4_whole; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 16; break; } - bind._arg = InternalName::make(param_name); - bind._dim[0] = 1; - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame; - bind._dep[1] = Shader::SSD_NONE; - _shader->_ptr_spec.push_back(bind); + bind._part[0] = Shader::SMO_INVALID; + bind._part[1] = Shader::SMO_INVALID; + bind._arg[0] = InternalName::make(param_name); + bind._arg[1] = nullptr; + _shader->cp_add_mat_spec(bind); return; } case GL_IMAGE_2D: @@ -1720,7 +1843,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { << " is bound to image unit " << binding << "\n"; } - if (binding >= _glsl_img_inputs.size()) { + if (binding >= (GLint)_glsl_img_inputs.size()) { _glsl_img_inputs.resize(binding + 1); } @@ -1772,55 +1895,107 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { case GL_FLOAT_VEC4: case GL_FLOAT_MAT3: case GL_FLOAT_MAT4: { - Shader::ShaderPtrSpec bind; + Shader::ShaderMatSpec bind; bind._id = arg_id; - switch (param_type) { - case GL_BOOL: - case GL_INT: - case GL_FLOAT: bind._dim[1] = 1; break; - case GL_BOOL_VEC2: - case GL_INT_VEC2: - case GL_FLOAT_VEC2: bind._dim[1] = 2; break; - case GL_BOOL_VEC3: - case GL_INT_VEC3: - case GL_FLOAT_VEC3: bind._dim[1] = 3; break; - case GL_BOOL_VEC4: - case GL_INT_VEC4: - case GL_FLOAT_VEC4: bind._dim[1] = 4; break; - case GL_FLOAT_MAT3: bind._dim[1] = 9; break; - case GL_FLOAT_MAT4: bind._dim[1] = 16; break; - } + bind._func = Shader::SMF_shader_input_ptr; switch (param_type) { case GL_BOOL: + bind._piece = Shader::SMP_scalar_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 1; + break; case GL_BOOL_VEC2: + bind._piece = Shader::SMP_vec2_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 2; + break; case GL_BOOL_VEC3: + bind._piece = Shader::SMP_vec3_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 3; + break; case GL_BOOL_VEC4: + bind._piece = Shader::SMP_vec4_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 4; + break; case GL_UNSIGNED_INT: + bind._piece = Shader::SMP_scalar_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 1; + break; case GL_UNSIGNED_INT_VEC2: + bind._piece = Shader::SMP_vec2_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 2; + break; case GL_UNSIGNED_INT_VEC3: + bind._piece = Shader::SMP_vec3_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 3; + break; case GL_UNSIGNED_INT_VEC4: - bind._type = Shader::SPT_uint; + bind._piece = Shader::SMP_vec4_array; + bind._numeric_type = Shader::SPT_uint; + bind._num_components = 4; break; case GL_INT: + bind._piece = Shader::SMP_scalar_array; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 1; + break; case GL_INT_VEC2: + bind._piece = Shader::SMP_vec2_array; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 2; + break; case GL_INT_VEC3: + bind._piece = Shader::SMP_vec3_array; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 3; + break; case GL_INT_VEC4: - bind._type = Shader::SPT_int; + bind._piece = Shader::SMP_vec4_array; + bind._numeric_type = Shader::SPT_int; + bind._num_components = 4; break; case GL_FLOAT: + bind._piece = Shader::SMP_scalar_array; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 1; + break; case GL_FLOAT_VEC2: + bind._piece = Shader::SMP_vec2_array; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 2; + break; case GL_FLOAT_VEC3: + bind._piece = Shader::SMP_vec3_array; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 3; + break; case GL_FLOAT_VEC4: + bind._piece = Shader::SMP_vec4_array; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 4; + break; case GL_FLOAT_MAT3: + bind._piece = Shader::SMP_mat3_array; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 9; + break; case GL_FLOAT_MAT4: - bind._type = Shader::SPT_float; + bind._piece = Shader::SMP_mat4_array; + bind._numeric_type = Shader::SPT_float; + bind._num_components = 16; break; } - bind._arg = InternalName::make(param_name); - bind._dim[0] = param_size; - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame; - bind._dep[1] = Shader::SSD_NONE; - _shader->_ptr_spec.push_back(bind); + bind._part[0] = Shader::SMO_INVALID; + bind._part[1] = Shader::SMO_INVALID; + bind._arg[0] = InternalName::make(param_name); + bind._arg[1] = nullptr; + bind._array_count = param_size; + _shader->cp_add_mat_spec(bind); return; } default: @@ -1967,6 +2142,7 @@ CLP(ShaderContext):: ~CLP(ShaderContext)() { // Don't call release_resources; we may not have an active context. delete[] _mat_part_cache; + delete[] _mat_scratch_space; } /** @@ -2160,177 +2336,80 @@ issue_parameters(int altered) { << " (altered 0x" << hex << altered << dec << ")\n"; } - // We have no way to track modifications to PTAs, so we assume that they are - // modified every frame and when we switch ShaderAttribs. - if (altered & (Shader::SSD_shaderinputs | Shader::SSD_frame)) { - - // If we have an osg_FrameNumber input, set it now. - if ((altered & Shader::SSD_frame) != 0 && _frame_number_loc >= 0) { - _glgsg->_glUniform1i(_frame_number_loc, _frame_number); - } - - // Iterate through _ptr parameters - for (int i = 0; i < (int)_shader->_ptr_spec.size(); ++i) { - Shader::ShaderPtrSpec &spec = _shader->_ptr_spec[i]; - - Shader::ShaderPtrData ptr_data; - if (!_glgsg->fetch_ptr_parameter(spec, ptr_data)) { //the input is not contained in ShaderPtrData - release_resources(); - return; - } - - nassertd(spec._dim[1] > 0) continue; - - GLint p = spec._id._seqno; - int array_size = min(spec._dim[0], (int)ptr_data._size / spec._dim[1]); - switch (spec._type) { - case Shader::SPT_float: - { - float *data = nullptr; - - switch (ptr_data._type) { - case Shader::SPT_int: - // Convert int data to float data. - data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]); - for (int i = 0; i < (array_size * spec._dim[1]); ++i) { - data[i] = (float)(((int*)ptr_data._ptr)[i]); - } - break; - - case Shader::SPT_uint: - // Convert unsigned int data to float data. - data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]); - for (int i = 0; i < (array_size * spec._dim[1]); ++i) { - data[i] = (float)(((unsigned int*)ptr_data._ptr)[i]); - } - break; - - case Shader::SPT_double: - // Downgrade double data to float data. - data = (float*) alloca(sizeof(float) * array_size * spec._dim[1]); - for (int i = 0; i < (array_size * spec._dim[1]); ++i) { - data[i] = (float)(((double*)ptr_data._ptr)[i]); - } - break; - - case Shader::SPT_float: - data = (float*)ptr_data._ptr; - break; - - default: - nassertd(false) continue; - } - - switch (spec._dim[1]) { - case 1: _glgsg->_glUniform1fv(p, array_size, (float*)data); continue; - case 2: _glgsg->_glUniform2fv(p, array_size, (float*)data); continue; - case 3: _glgsg->_glUniform3fv(p, array_size, (float*)data); continue; - case 4: _glgsg->_glUniform4fv(p, array_size, (float*)data); continue; - case 9: _glgsg->_glUniformMatrix3fv(p, array_size, GL_FALSE, (float*)data); continue; - case 16: _glgsg->_glUniformMatrix4fv(p, array_size, GL_FALSE, (float*)data); continue; - } - nassertd(false) continue; - } - break; - - case Shader::SPT_int: - if (ptr_data._type != Shader::SPT_int && - ptr_data._type != Shader::SPT_uint) { - GLCAT.error() - << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n"; - - // Deactivate it to make sure the user doesn't get flooded with this - // error. - spec._dep[0] = 0; - spec._dep[1] = 0; - - } else { - switch (spec._dim[1]) { - case 1: _glgsg->_glUniform1iv(p, array_size, (int*)ptr_data._ptr); continue; - case 2: _glgsg->_glUniform2iv(p, array_size, (int*)ptr_data._ptr); continue; - case 3: _glgsg->_glUniform3iv(p, array_size, (int*)ptr_data._ptr); continue; - case 4: _glgsg->_glUniform4iv(p, array_size, (int*)ptr_data._ptr); continue; - } - nassertd(false) continue; - } - break; - - case Shader::SPT_uint: - if (ptr_data._type != Shader::SPT_uint && - ptr_data._type != Shader::SPT_int) { - GLCAT.error() - << "Cannot pass floating-point data to integer shader input '" << spec._id._name << "'\n"; - - // Deactivate it to make sure the user doesn't get flooded with this - // error. - spec._dep[0] = 0; - spec._dep[1] = 0; - - } else { - switch (spec._dim[1]) { - case 1: _glgsg->_glUniform1uiv(p, array_size, (GLuint *)ptr_data._ptr); continue; - case 2: _glgsg->_glUniform2uiv(p, array_size, (GLuint *)ptr_data._ptr); continue; - case 3: _glgsg->_glUniform3uiv(p, array_size, (GLuint *)ptr_data._ptr); continue; - case 4: _glgsg->_glUniform4uiv(p, array_size, (GLuint *)ptr_data._ptr); continue; - } - nassertd(false) continue; - } - break; - - case Shader::SPT_double: - GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n"; - - // Deactivate it to make sure the user doesn't get flooded with this - // error. - spec._dep[0] = 0; - spec._dep[1] = 0; - - default: - continue; - } - } - } - if (altered & _shader->_mat_deps) { - _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); + if (altered & _shader->_mat_cache_deps) { + _glgsg->update_shader_matrix_cache(_shader, _mat_part_cache, altered); + } for (Shader::ShaderMatSpec &spec : _shader->_mat_spec) { if ((altered & spec._dep) == 0) { continue; } - const LVecBase4f *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, altered); + const LVecBase4f *val = _glgsg->fetch_specified_value(spec, _mat_part_cache, _mat_scratch_space); if (!val) continue; const float *data = val->get_data(); data += spec._offset; GLint p = spec._id._seqno; - switch (spec._piece) { - case Shader::SMP_float: _glgsg->_glUniform1fv(p, 1, data); continue; - case Shader::SMP_vec2: _glgsg->_glUniform2fv(p, 1, data); continue; - case Shader::SMP_vec3: _glgsg->_glUniform3fv(p, 1, data); continue; - case Shader::SMP_vec4: _glgsg->_glUniform4fv(p, 1, data); continue; - case Shader::SMP_vec4_array: _glgsg->_glUniform4fv(p, spec._array_count, data); continue; - case Shader::SMP_mat4_whole: _glgsg->_glUniformMatrix4fv(p, 1, GL_FALSE, data); continue; - case Shader::SMP_mat4_array: _glgsg->_glUniformMatrix4fv(p, spec._array_count, GL_FALSE, data); continue; - case Shader::SMP_mat4_transpose: _glgsg->_glUniformMatrix4fv(p, 1, GL_TRUE, data); continue; - case Shader::SMP_mat4_column: _glgsg->_glUniform4f(p, data[0], data[4], data[8], data[12]); continue; - case Shader::SMP_mat4_upper3x3: - { - LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); - _glgsg->_glUniformMatrix3fv(p, 1, false, upper3.get_data()); - continue; + if (spec._numeric_type == Shader::SPT_float) { + switch (spec._piece) { + case Shader::SMP_scalar: _glgsg->_glUniform1fv(p, 1, data); continue; + case Shader::SMP_vec2: _glgsg->_glUniform2fv(p, 1, data); continue; + case Shader::SMP_vec3: _glgsg->_glUniform3fv(p, 1, data); continue; + case Shader::SMP_vec4: _glgsg->_glUniform4fv(p, 1, data); continue; + case Shader::SMP_scalar_array: _glgsg->_glUniform1fv(p, spec._array_count, data); continue; + case Shader::SMP_vec2_array: _glgsg->_glUniform2fv(p, spec._array_count, data); continue; + case Shader::SMP_vec3_array: _glgsg->_glUniform3fv(p, spec._array_count, data); continue; + case Shader::SMP_vec4_array: _glgsg->_glUniform4fv(p, spec._array_count, data); continue; + case Shader::SMP_mat3_whole: _glgsg->_glUniformMatrix3fv(p, 1, GL_FALSE, data); continue; + case Shader::SMP_mat3_array: _glgsg->_glUniformMatrix3fv(p, spec._array_count, GL_FALSE, data); continue; + case Shader::SMP_mat4_whole: _glgsg->_glUniformMatrix4fv(p, 1, GL_FALSE, data); continue; + case Shader::SMP_mat4_array: _glgsg->_glUniformMatrix4fv(p, spec._array_count, GL_FALSE, data); continue; + case Shader::SMP_mat4_transpose: _glgsg->_glUniformMatrix4fv(p, 1, GL_TRUE, data); continue; + case Shader::SMP_mat4_column: _glgsg->_glUniform4f(p, data[0], data[4], data[8], data[12]); continue; + case Shader::SMP_mat4_upper3x3: + { + LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); + _glgsg->_glUniformMatrix3fv(p, 1, false, upper3.get_data()); + continue; + } + case Shader::SMP_mat4_transpose3x3: + { + LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); + _glgsg->_glUniformMatrix3fv(p, 1, true, upper3.get_data()); + continue; + } } - case Shader::SMP_mat4_transpose3x3: - { - LMatrix3f upper3(data[0], data[1], data[2], data[4], data[5], data[6], data[8], data[9], data[10]); - _glgsg->_glUniformMatrix3fv(p, 1, true, upper3.get_data()); - continue; + } + else if (spec._numeric_type == Shader::SPT_int) { + switch (spec._piece) { + case Shader::SMP_scalar: _glgsg->_glUniform1iv(p, 1, (const GLint *)data); continue; + case Shader::SMP_vec2: _glgsg->_glUniform2iv(p, 1, (const GLint *)data); continue; + case Shader::SMP_vec3: _glgsg->_glUniform3iv(p, 1, (const GLint *)data); continue; + case Shader::SMP_vec4: _glgsg->_glUniform4iv(p, 1, (const GLint *)data); continue; + case Shader::SMP_scalar_array: _glgsg->_glUniform1iv(p, spec._array_count, (const GLint *)data); continue; + case Shader::SMP_vec2_array: _glgsg->_glUniform2iv(p, spec._array_count, (const GLint *)data); continue; + case Shader::SMP_vec3_array: _glgsg->_glUniform3iv(p, spec._array_count, (const GLint *)data); continue; + case Shader::SMP_vec4_array: _glgsg->_glUniform4iv(p, spec._array_count, (const GLint *)data); continue; + default: assert(false); + } + } + else if (spec._numeric_type == Shader::SPT_uint || spec._numeric_type == Shader::SPT_bool) { + switch (spec._piece) { + case Shader::SMP_scalar: _glgsg->_glUniform1uiv(p, 1, (const GLuint *)data); continue; + case Shader::SMP_vec2: _glgsg->_glUniform2uiv(p, 1, (const GLuint *)data); continue; + case Shader::SMP_vec3: _glgsg->_glUniform3uiv(p, 1, (const GLuint *)data); continue; + case Shader::SMP_vec4: _glgsg->_glUniform4uiv(p, 1, (const GLuint *)data); continue; + case Shader::SMP_scalar_array: _glgsg->_glUniform1uiv(p, spec._array_count, (const GLuint *)data); continue; + case Shader::SMP_vec2_array: _glgsg->_glUniform2uiv(p, spec._array_count, (const GLuint *)data); continue; + case Shader::SMP_vec3_array: _glgsg->_glUniform3uiv(p, spec._array_count, (const GLuint *)data); continue; + case Shader::SMP_vec4_array: _glgsg->_glUniform4uiv(p, spec._array_count, (const GLuint *)data); continue; + default: assert(false); } - case Shader::SMP_int: _glgsg->_glUniform1i(p, ((int *)data)[0]); continue; - case Shader::SMP_ivec2: _glgsg->_glUniform2iv(p, 1, (int *)data); continue; - case Shader::SMP_ivec3: _glgsg->_glUniform3iv(p, 1, (int *)data); continue; - case Shader::SMP_ivec4: _glgsg->_glUniform4iv(p, 1, (int *)data); continue; + } + else { + nassert_raise("double-precision uniform passing not supported"); } } } @@ -2597,6 +2676,10 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { update_slider_table(table); } + // This ought to be moved elsewhere, but it's convenient to do this here for + // now since it's called before every Geom is drawn. + issue_memory_barriers(); + _glgsg->report_my_gl_errors(); return true; @@ -2734,12 +2817,6 @@ update_shader_texture_bindings(ShaderContext *prev) { int view = _glgsg->get_current_tex_view_offset(); gl_tex = gtc->get_view_index(view); - -#ifndef OPENGLES - if (gtc->needs_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)) { - barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; - } -#endif } } input._writable = false; @@ -2800,7 +2877,17 @@ update_shader_texture_bindings(ShaderContext *prev) { access = GL_READ_ONLY; gl_tex = 0; } + } else { + // If no parameters were specified, we have to assume writable access. + input._writable = true; } + +#ifndef OPENGLES + if (gtc->needs_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT, input._writable)) { + barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; + } +#endif + _glgsg->_glBindImageTexture(i, gl_tex, bind_level, layered, bind_layer, access, gtc->_internal_format); } @@ -2890,7 +2977,7 @@ update_shader_texture_bindings(ShaderContext *prev) { #ifndef OPENGLES // If it was recently written to, we will have to issue a memory barrier // soon. - if (gtc->needs_barrier(GL_TEXTURE_FETCH_BARRIER_BIT)) { + if (gtc->needs_barrier(GL_TEXTURE_FETCH_BARRIER_BIT, false)) { barriers |= GL_TEXTURE_FETCH_BARRIER_BIT; } #endif @@ -2964,7 +3051,35 @@ update_shader_buffer_bindings(ShaderContext *prev) { " (expected at least " << block._min_size << " bytes)\n"; } #endif - _glgsg->apply_shader_buffer(block._binding_index, buffer); + block._gbc = _glgsg->apply_shader_buffer(block._binding_index, buffer); + } +#endif +} + +/** + * Issues memory barriers for shader buffers, should be called before a draw. + */ +void CLP(ShaderContext):: +issue_memory_barriers() { +#ifndef OPENGLES + bool barrier_needed = false; + for (StorageBlock &block : _storage_blocks) { + if (block._gbc != nullptr && + block._gbc->_shader_storage_barrier_counter == _glgsg->_shader_storage_barrier_counter) { + barrier_needed = true; + break; + } + } + + if (barrier_needed) { + _glgsg->issue_memory_barrier(GL_SHADER_STORAGE_BARRIER_BIT); + } + + // We assume that all SSBOs will be written to, for now. + for (StorageBlock &block : _storage_blocks) { + if (block._gbc != nullptr) { + block._gbc->_shader_storage_barrier_counter = _glgsg->_shader_storage_barrier_counter; + } } #endif } diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index b42fa975387..3088170ec3c 100644 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -58,6 +58,7 @@ class EXPCL_GL CLP(ShaderContext) final : public ShaderContext { void disable_shader_texture_bindings() override; void update_shader_texture_bindings(ShaderContext *prev) override; void update_shader_buffer_bindings(ShaderContext *prev) override; + void issue_memory_barriers(); bool uses_standard_vertex_arrays(void) override { return _uses_standard_vertex_arrays; @@ -91,12 +92,12 @@ class EXPCL_GL CLP(ShaderContext) final : public ShaderContext { GLint _slider_table_index; GLsizei _transform_table_size; GLsizei _slider_table_size; - GLint _frame_number_loc; GLint _frame_number; #ifndef OPENGLES struct StorageBlock { CPT(InternalName) _name; + CLP(BufferContext) *_gbc = nullptr; GLuint _binding_index; GLuint _min_size; }; @@ -113,11 +114,16 @@ class EXPCL_GL CLP(ShaderContext) final : public ShaderContext { pvector _glsl_img_inputs; LVecBase4f *_mat_part_cache = nullptr; + LVecBase4f *_mat_scratch_space = nullptr; CLP(GraphicsStateGuardian) *_glgsg; bool _uses_standard_vertex_arrays; +#ifdef DO_PSTATS + PStatCollector _compute_dispatch_pcollector; +#endif + void glsl_report_shader_errors(GLuint shader, Shader::ShaderType type, bool fatal); void glsl_report_program_errors(GLuint program, bool fatal); bool glsl_compile_shader(Shader::ShaderType type); diff --git a/panda/src/glstuff/glTextureContext_src.I b/panda/src/glstuff/glTextureContext_src.I index bde6a4d977a..a0a986e80f9 100644 --- a/panda/src/glstuff/glTextureContext_src.I +++ b/panda/src/glstuff/glTextureContext_src.I @@ -59,3 +59,43 @@ get_view_buffer(int view) const { return 0; } } + +/** + * Returns true if an async upload is pending. + */ +INLINE bool CLP(TextureContext):: +is_upload_pending() const { + // We can't simply compare _uploads_started to _uploads_finished, since + // they also get set to the same by cancel_pending_uploads() + return _uploads_pending > 0; +} + +/** + * Waits for all uploads to be finished. + */ +INLINE void CLP(TextureContext):: +wait_pending_uploads() const { + if (is_upload_pending()) { + do_wait_pending_uploads(); + } +} + +/** + * Cancels all asynchronous uploads. Not guaranteed to be cancelled by the + * time this returns, consider following this up with a call to + * wait_pending_uploads(). + */ +INLINE void CLP(TextureContext):: +cancel_pending_uploads() { + _uploads_finished = _uploads_started; +} + +/** + * Waits for an unused PBO unless we're not at the given limit of PBOs yet. + */ +INLINE void CLP(TextureContext):: +wait_for_unused_pbo(int limit) const { + if (_unused_pbos.empty() && _num_pbos >= limit) { + do_wait_for_unused_pbo(limit); + } +} diff --git a/panda/src/glstuff/glTextureContext_src.cxx b/panda/src/glstuff/glTextureContext_src.cxx index 7572ef8a4f4..efc001df347 100644 --- a/panda/src/glstuff/glTextureContext_src.cxx +++ b/panda/src/glstuff/glTextureContext_src.cxx @@ -13,6 +13,8 @@ #include "pnotify.h" +static PStatCollector _wait_async_texture_uploads_pcollector("Wait:Async Texture Uploads"); + TypeHandle CLP(TextureContext)::_type_handle; /** @@ -48,6 +50,8 @@ evict_lru() { */ void CLP(TextureContext):: reset_data(GLenum target, int num_views) { + cancel_pending_uploads(); + // Free the texture resources. set_num_views(0); @@ -63,12 +67,13 @@ reset_data(GLenum target, int num_views) { #ifndef OPENGLES_1 // Mark the texture as coherent. - if (gl_enable_memory_barriers) { - _glgsg->_textures_needing_fetch_barrier.erase(this); - _glgsg->_textures_needing_image_access_barrier.erase(this); - _glgsg->_textures_needing_update_barrier.erase(this); - _glgsg->_textures_needing_framebuffer_barrier.erase(this); - } + _texture_fetch_barrier_counter = _glgsg->_texture_fetch_barrier_counter - 1; + _shader_image_read_barrier_counter = _glgsg->_shader_image_access_barrier_counter - 1; + _shader_image_write_barrier_counter = _glgsg->_shader_image_access_barrier_counter - 1; + _texture_read_barrier_counter = _glgsg->_texture_update_barrier_counter - 1; + _texture_write_barrier_counter = _glgsg->_shader_image_access_barrier_counter - 1; + _framebuffer_read_barrier_counter = _glgsg->_framebuffer_barrier_counter - 1; + _framebuffer_write_barrier_counter = _glgsg->_framebuffer_barrier_counter - 1; #endif } @@ -168,26 +173,50 @@ set_num_views(int num_views) { #ifndef OPENGLES_1 /** - * + * Returns true if the texture needs a barrier before a read or write of the + * given kind. If writing is false, only writes are synced, otherwise both + * reads and writes are synced. */ bool CLP(TextureContext):: -needs_barrier(GLbitfield barrier) { +needs_barrier(GLbitfield barrier, bool writing) { if (!gl_enable_memory_barriers) { return false; } - return (((barrier & GL_TEXTURE_FETCH_BARRIER_BIT) && - _glgsg->_textures_needing_fetch_barrier.count(this))) - || (((barrier & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) && - _glgsg->_textures_needing_image_access_barrier.count(this))) - || (((barrier & GL_TEXTURE_UPDATE_BARRIER_BIT) && - _glgsg->_textures_needing_update_barrier.count(this))) - || (((barrier & GL_FRAMEBUFFER_BARRIER_BIT) && - _glgsg->_textures_needing_framebuffer_barrier.count(this))); + if (barrier & GL_TEXTURE_FETCH_BARRIER_BIT) { + // This is always a read, so only sync RAW. + if (_glgsg->_texture_fetch_barrier_counter == _texture_fetch_barrier_counter) { + return true; + } + } + + if (barrier & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) { + // Sync WAR, WAW and RAW, but not RAR. + if ((writing && _glgsg->_shader_image_access_barrier_counter == _shader_image_read_barrier_counter) || + (_glgsg->_shader_image_access_barrier_counter == _shader_image_write_barrier_counter)) { + return true; + } + } + + if (barrier & GL_TEXTURE_UPDATE_BARRIER_BIT) { + if ((writing && _glgsg->_texture_update_barrier_counter == _texture_read_barrier_counter) || + (_glgsg->_texture_update_barrier_counter == _texture_write_barrier_counter)) { + return true; + } + } + + if (barrier & GL_FRAMEBUFFER_BARRIER_BIT) { + if ((writing && _glgsg->_framebuffer_barrier_counter == _framebuffer_read_barrier_counter) || + (_glgsg->_framebuffer_barrier_counter == _framebuffer_write_barrier_counter)) { + return true; + } + } + + return false; } /** - * Mark a texture as needing a memory barrier, since a non-coherent read or + * Mark a texture as needing a memory barrier, since an unsynchronized read or * write just happened to it. If 'wrote' is true, it was written to. */ void CLP(TextureContext):: @@ -199,16 +228,73 @@ mark_incoherent(bool wrote) { // If we only read from it, the next read operation won't need another // barrier, since it'll be reading the same data. if (wrote) { - _glgsg->_textures_needing_fetch_barrier.insert(this); + _texture_fetch_barrier_counter = _glgsg->_texture_fetch_barrier_counter; + _shader_image_write_barrier_counter = _glgsg->_shader_image_access_barrier_counter; + _texture_write_barrier_counter = _glgsg->_shader_image_access_barrier_counter; + _framebuffer_write_barrier_counter = _glgsg->_framebuffer_barrier_counter; } // We could still write to it before we read from it, so we have to always - // insert these barriers. This could be slightly optimized so that we don't - // issue a barrier between consecutive image reads, but that may not be - // worth the trouble. - _glgsg->_textures_needing_image_access_barrier.insert(this); - _glgsg->_textures_needing_update_barrier.insert(this); - _glgsg->_textures_needing_framebuffer_barrier.insert(this); + // insert these barriers. + _shader_image_read_barrier_counter = _glgsg->_shader_image_access_barrier_counter; + _texture_read_barrier_counter = _glgsg->_texture_update_barrier_counter; + _framebuffer_read_barrier_counter = _glgsg->_framebuffer_barrier_counter; } #endif // !OPENGLES_1 + +/** + * Returns a PBO with the given size to the pool of unused PBOs. + */ +void CLP(TextureContext):: +return_pbo(GLuint pbo, size_t size) { + // Also triggers when the number of buffers is -1 (which effectively means + // to always delete the buffers after use). + if (_num_pbos > get_texture()->get_num_async_transfer_buffers() || + size < _pbo_size) { + // We have too many PBOs, or this PBO is no longer of the proper + // size, so delete it rather than returning it to the pool. + _num_pbos--; + _glgsg->_glDeleteBuffers(1, &pbo); + } else { + _unused_pbos.push_front(pbo); + } +} + +/** + * Deletes all unused PBOs. + */ +void CLP(TextureContext):: +delete_unused_pbos() { + if (!_unused_pbos.empty()) { + for (GLuint pbo : _unused_pbos) { + _glgsg->_glDeleteBuffers(1, &pbo); + } + _num_pbos -= (int)_unused_pbos.size(); + _unused_pbos.clear(); + } +} + +/** + * Waits for all uploads to be finished. + */ +void CLP(TextureContext):: +do_wait_pending_uploads() const { + PStatTimer timer(_wait_async_texture_uploads_pcollector); + do { + _glgsg->process_pending_jobs(true); + } + while (is_upload_pending()); +} + +/** + * + */ +void CLP(TextureContext):: +do_wait_for_unused_pbo(int limit) const { + PStatTimer timer(_wait_async_texture_uploads_pcollector); + do { + _glgsg->process_pending_jobs(true); + } + while (_unused_pbos.empty() && _num_pbos >= limit); +} diff --git a/panda/src/glstuff/glTextureContext_src.h b/panda/src/glstuff/glTextureContext_src.h index c4244884714..03626a46ce7 100644 --- a/panda/src/glstuff/glTextureContext_src.h +++ b/panda/src/glstuff/glTextureContext_src.h @@ -41,12 +41,24 @@ class EXPCL_GL CLP(TextureContext) : public TextureContext { INLINE GLuint get_view_buffer(int view) const; #ifdef OPENGLES_1 - static constexpr bool needs_barrier(GLbitfield barrier) { return false; }; + static constexpr bool needs_barrier(GLbitfield barrier, bool writing) { return false; }; #else - bool needs_barrier(GLbitfield barrier); + bool needs_barrier(GLbitfield barrier, bool writing); void mark_incoherent(bool wrote); #endif + INLINE bool is_upload_pending() const; + INLINE void wait_pending_uploads() const; + INLINE void cancel_pending_uploads(); + + void return_pbo(GLuint pbo, size_t size); + void delete_unused_pbos(); + INLINE void wait_for_unused_pbo(int limit) const; + +private: + void do_wait_pending_uploads() const; + void do_wait_for_unused_pbo(int limit) const; + private: // This is the GL "name" of the texture object. GLuint _index; @@ -76,8 +88,25 @@ class EXPCL_GL CLP(TextureContext) : public TextureContext { GLenum _target; SamplerState _active_sampler; + // These counters are used to prevent out-of-order updates. + int _uploads_started = 0; + int _uploads_finished = 0; + int _uploads_pending = 0; + pdeque _unused_pbos; + int _num_pbos = 0; + size_t _pbo_size = 0; + CLP(GraphicsStateGuardian) *_glgsg; + // These are set to the equivalent counter in glgsg when a write is performed. + int _texture_fetch_barrier_counter = -1; + int _shader_image_read_barrier_counter = -1; + int _shader_image_write_barrier_counter = -1; + int _texture_read_barrier_counter = -1; + int _texture_write_barrier_counter = -1; + int _framebuffer_read_barrier_counter = -1; + int _framebuffer_write_barrier_counter = -1; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/glstuff/glmisc_src.cxx b/panda/src/glstuff/glmisc_src.cxx index f223ef266e7..d1ae931c7ce 100644 --- a/panda/src/glstuff/glmisc_src.cxx +++ b/panda/src/glstuff/glmisc_src.cxx @@ -22,6 +22,11 @@ ConfigVariableBool gl_forward_compatible PRC_DESC("Setting this to true will request a forward-compatible OpenGL " "context, which will not support the fixed-function pipeline.")); +ConfigVariableBool gl_support_dsa + ("gl-support-dsa", true, + PRC_DESC("Configure this false if you suspect your GL's implementation of " + "Direct State Access is broken.")); + ConfigVariableBool gl_support_fbo ("gl-support-fbo", true, PRC_DESC("Configure this false if your GL's implementation of " @@ -321,6 +326,19 @@ ConfigVariableBool gl_depth_zero_to_one "range from 0 to 1, matching other graphics APIs. This setting " "requires OpenGL 4.5, or NVIDIA GeForce 8+ hardware.")); +ConfigVariableInt gl_texture_transfer_num_threads + ("gl-texture-transfer-num-threads", 2, + PRC_DESC("The number of threads that will be started to upload and download " + "texture data asynchronously, either via the setup_async_transfer " + "interface on the the Texture class or via the async screenshot " + "interface.")); + +ConfigVariableEnum gl_texture_transfer_thread_priority + ("gl-texture-transfer-thread-priority", TP_normal, + PRC_DESC("The default thread priority to assign to the threads created for " + "asynchronous texture transfers. The default is 'normal'; you may " + "also specify 'low', 'high', or 'urgent'.")); + extern ConfigVariableBool gl_parallel_arrays; void CLP(init_classes)() { diff --git a/panda/src/glstuff/glmisc_src.h b/panda/src/glstuff/glmisc_src.h index 1cc96726fe5..deb219dc5a9 100644 --- a/panda/src/glstuff/glmisc_src.h +++ b/panda/src/glstuff/glmisc_src.h @@ -17,6 +17,7 @@ #include "configVariableEnum.h" #include "geomEnums.h" #include "coordinateSystem.h" +#include "threadPriority.h" // Define some macros to transparently map to the double or float versions of // the OpenGL function names. @@ -35,6 +36,7 @@ extern EXPCL_GL ConfigVariableInt gl_version; extern EXPCL_GL ConfigVariableBool gl_forward_compatible; extern EXPCL_GL ConfigVariableBool gl_support_fbo; +extern ConfigVariableBool gl_support_dsa; extern ConfigVariableBool gl_cheap_textures; extern ConfigVariableBool gl_ignore_clamp; extern ConfigVariableBool gl_support_clamp_to_border; @@ -75,6 +77,8 @@ extern ConfigVariableBool gl_support_shadow_filter; extern ConfigVariableBool gl_support_vertex_array_bgra; extern ConfigVariableBool gl_force_image_bindings_writeonly; extern ConfigVariableEnum gl_coordinate_system; +extern ConfigVariableInt gl_texture_transfer_num_threads; +extern ConfigVariableEnum gl_texture_transfer_thread_priority; extern EXPCL_GL void CLP(init_classes)(); diff --git a/panda/src/glxdisplay/glxGraphicsBuffer.cxx b/panda/src/glxdisplay/glxGraphicsBuffer.cxx index 6ede9a3e361..7a29be94f62 100644 --- a/panda/src/glxdisplay/glxGraphicsBuffer.cxx +++ b/panda/src/glxdisplay/glxGraphicsBuffer.cxx @@ -166,7 +166,8 @@ open_buffer() { // with the old gsg. DCAST_INTO_R(glxgsg, _gsg, false); - if (!glxgsg->_context_has_pbuffer || + if (glxgsg->get_engine() != _engine || + !glxgsg->_context_has_pbuffer || !glxgsg->get_fb_properties().subsumes(_fb_properties)) { // We need a new pixel format, and hence a new GSG. glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg); diff --git a/panda/src/glxdisplay/glxGraphicsPipe.cxx b/panda/src/glxdisplay/glxGraphicsPipe.cxx index e4ec8380fbf..e4ed9ca2f6d 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.cxx +++ b/panda/src/glxdisplay/glxGraphicsPipe.cxx @@ -130,6 +130,9 @@ make_output(const string &name, (flags & (BF_require_parasite | BF_require_window)) != 0) { return nullptr; } + if (host->get_engine() != engine) { + return nullptr; + } // Early failure - if we are sure that this buffer WONT meet specs, we can // bail out early. if ((flags & BF_fb_props_optional) == 0) { diff --git a/panda/src/glxdisplay/glxGraphicsWindow.cxx b/panda/src/glxdisplay/glxGraphicsWindow.cxx index 449d1f66a03..e882bc98fbe 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.cxx +++ b/panda/src/glxdisplay/glxGraphicsWindow.cxx @@ -184,7 +184,8 @@ open_window() { // If the old gsg has the wrong pixel format, create a new one that shares // with the old gsg. DCAST_INTO_R(glxgsg, _gsg, false); - if (!glxgsg->get_fb_properties().subsumes(_fb_properties)) { + if (glxgsg->get_engine() != _engine || + !glxgsg->get_fb_properties().subsumes(_fb_properties)) { glxgsg = new glxGraphicsStateGuardian(_engine, _pipe, glxgsg); glxgsg->choose_pixel_format(_fb_properties, glx_pipe->get_display(), glx_pipe->get_screen(), false, false); _gsg = glxgsg; diff --git a/panda/src/gobj/bufferContext.cxx b/panda/src/gobj/bufferContext.cxx index b268400d353..4ee4f1833de 100644 --- a/panda/src/gobj/bufferContext.cxx +++ b/panda/src/gobj/bufferContext.cxx @@ -12,6 +12,7 @@ */ #include "bufferContext.h" +#include "lightMutexHolder.h" TypeHandle BufferContext::_type_handle; @@ -43,7 +44,8 @@ BufferContext:: void BufferContext:: set_owning_chain(BufferContextChain *chain) { if (chain != _owning_chain) { - if (_owning_chain != nullptr){ + if (_owning_chain != nullptr) { + LightMutexHolder holder(_owning_chain->_lock); --(_owning_chain->_count); _owning_chain->adjust_bytes(-(int)_data_size_bytes); remove_from_list(); @@ -52,6 +54,7 @@ set_owning_chain(BufferContextChain *chain) { _owning_chain = chain; if (_owning_chain != nullptr) { + LightMutexHolder holder(_owning_chain->_lock); ++(_owning_chain->_count); _owning_chain->adjust_bytes((int)_data_size_bytes); insert_before(_owning_chain); diff --git a/panda/src/gobj/bufferContext.h b/panda/src/gobj/bufferContext.h index 60c9ab33336..0d6d49b5e42 100644 --- a/panda/src/gobj/bufferContext.h +++ b/panda/src/gobj/bufferContext.h @@ -73,7 +73,7 @@ class EXPCL_PANDA_GOBJ BufferContext : public SavedContext, private LinkedListNo TypedWritableReferenceCount *_object; private: - BufferResidencyTracker *_residency; + BufferResidencyTracker *const _residency; int _residency_state; size_t _data_size_bytes; diff --git a/panda/src/gobj/bufferContextChain.cxx b/panda/src/gobj/bufferContextChain.cxx index 4f27c90c883..780ab233500 100644 --- a/panda/src/gobj/bufferContextChain.cxx +++ b/panda/src/gobj/bufferContextChain.cxx @@ -14,11 +14,15 @@ #include "bufferContextChain.h" #include "bufferContext.h" #include "indent.h" +#include "lightMutexHolder.h" /** * Returns the first BufferContext object stored in the tracker. You can walk * through the entire list of objects stored on the tracker by calling * get_next() on each returned object, until the return value is NULL. + * + * This does not grab the lock; make sure you are holding the lock while + * iterating over the chain. */ BufferContext *BufferContextChain:: get_first() { @@ -32,9 +36,11 @@ get_first() { /** * Moves all of the BufferContexts from the other tracker onto this one. + * The other chain must be locked. */ void BufferContextChain:: take_from(BufferContextChain &other) { + LightMutexHolder holder(_lock); _total_size += other._total_size; _count += other._count; other._total_size = 0; @@ -55,6 +61,7 @@ take_from(BufferContextChain &other) { */ void BufferContextChain:: write(std::ostream &out, int indent_level) const { + LightMutexHolder holder(_lock); indent(out, indent_level) << _count << " objects, consuming " << _total_size << " bytes:\n"; diff --git a/panda/src/gobj/bufferContextChain.h b/panda/src/gobj/bufferContextChain.h index b995c2e5839..153401b264a 100644 --- a/panda/src/gobj/bufferContextChain.h +++ b/panda/src/gobj/bufferContextChain.h @@ -16,6 +16,7 @@ #include "pandabase.h" #include "linkedListNode.h" +#include "lightMutex.h" class BufferContext; @@ -47,6 +48,9 @@ class EXPCL_PANDA_GOBJ BufferContextChain : private LinkedListNode { size_t _total_size; int _count; +public: + LightMutex _lock; + friend class BufferContext; }; diff --git a/panda/src/gobj/bufferResidencyTracker.cxx b/panda/src/gobj/bufferResidencyTracker.cxx index 9ac4fef735a..3d05fbee835 100644 --- a/panda/src/gobj/bufferResidencyTracker.cxx +++ b/panda/src/gobj/bufferResidencyTracker.cxx @@ -117,6 +117,7 @@ write(std::ostream &out, int indent_level) const { */ void BufferResidencyTracker:: move_inactive(BufferContextChain &inactive, BufferContextChain &active) { + LightMutexHolder active_holder(active._lock); BufferContext *node = active.get_first(); while (node != nullptr) { nassertv((node->_residency_state & S_active) != 0); diff --git a/panda/src/gobj/geomPatches.cxx b/panda/src/gobj/geomPatches.cxx index f5fe9711d07..63ee7fcd1e3 100644 --- a/panda/src/gobj/geomPatches.cxx +++ b/panda/src/gobj/geomPatches.cxx @@ -71,21 +71,6 @@ get_primitive_type() const { return PT_patches; } -/** - * If the primitive type is a simple type in which all primitives have the - * same number of vertices, like patches, returns the number of vertices per - * primitive. If the primitive type is a more complex type in which different - * primitives might have different numbers of vertices, for instance a - * triangle strip, returns 0. - * - * In the case of GeomPatches, this returns the fixed number that was - * specified to the constructor. - */ -int GeomPatches:: -get_num_vertices_per_primitive() const { - return _num_vertices_per_patch; -} - /** * Calls the appropriate method on the GSG to draw the primitive. */ diff --git a/panda/src/gobj/geomPatches.h b/panda/src/gobj/geomPatches.h index 85cda81e59c..92c84b58c4b 100644 --- a/panda/src/gobj/geomPatches.h +++ b/panda/src/gobj/geomPatches.h @@ -32,7 +32,9 @@ class EXPCL_PANDA_GOBJ GeomPatches : public GeomPrimitive { virtual PT(GeomPrimitive) make_copy() const; virtual PrimitiveType get_primitive_type() const; - virtual int get_num_vertices_per_primitive() const; + virtual int get_num_vertices_per_primitive() const final { + return _num_vertices_per_patch; + } public: virtual bool draw(GraphicsStateGuardianBase *gsg, diff --git a/panda/src/gobj/internalName_ext.cxx b/panda/src/gobj/internalName_ext.cxx index c7a145f23cb..ab8e49eec8c 100644 --- a/panda/src/gobj/internalName_ext.cxx +++ b/panda/src/gobj/internalName_ext.cxx @@ -74,7 +74,7 @@ PyObject *Extension:: __reduce__() const { std::string name = _this->get_name(); return Py_BuildValue("(N(s#))", - PyObject_GetAttrString((PyObject *)&Dtool_InternalName._PyType, "make"), name.c_str(), name.size()); + PyObject_GetAttrString((PyObject *)Dtool_GetPyTypeObject(&Dtool_InternalName), "make"), name.c_str(), name.size()); } #endif // HAVE_PYTHON diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index b76b0524765..3089537dd2c 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -1515,9 +1515,24 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) { Texture *tex = qti->first; TextureContext *tc = tex->prepare_now(this, gsg); if (tc != nullptr) { - gsg->update_texture(tc, true); - if (qti->second != nullptr) { - qti->second->set_result(tc); + if (tex->get_num_async_transfer_buffers() == 0) { + gsg->update_texture(tc, true); + if (qti->second != nullptr) { + qti->second->set_result(tc); + } + } else { + // Async update + CompletionToken token; + if (qti->second != nullptr) { + token = [tc, fut = std::move(qti->second)] (bool success) { + if (success) { + fut->set_result(tc); + } else { + fut->notify_removed(); + } + }; + } + gsg->update_texture(tc, false, std::move(token)); } } } diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index 067ab9527c9..fc4ac4e7ad5 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -381,16 +381,16 @@ cp_dependency(ShaderMatInput inp) { if (inp == SMO_INVALID) { return SSD_NONE; } - if (inp == SMO_attr_material || inp == SMO_attr_material2) { + if (inp == SMO_attr_material) { dep |= SSD_material | SSD_frame; } - if (inp == SMO_attr_color || inp == SMO_attr_material2) { + if (inp == SMO_attr_color) { dep |= SSD_color; } if (inp == SMO_attr_colorscale) { dep |= SSD_colorscale; } - if (inp == SMO_attr_fog || inp == SMO_attr_fogcolor) { + if (inp == SMO_attr_fog) { dep |= SSD_fog | SSD_frame; } if ((inp == SMO_model_to_view) || @@ -459,12 +459,12 @@ cp_dependency(ShaderMatInput inp) { } } if ((inp == SMO_light_ambient) || - (inp == SMO_light_source_i_vec_attrib) || + (inp == SMO_light_source_i) || (inp == SMO_apiview_to_apiclip_light_source_i) || (inp == SMO_light_source_i_packed)) { dep |= SSD_light | SSD_frame; } - if (inp == SMO_light_source_i_vec_attrib || + if (inp == SMO_light_source_i || inp == SMO_apiview_to_apiclip_light_source_i || inp == SMO_light_source_i_packed || inp == SMO_mat_constant_x_attrib || @@ -512,6 +512,90 @@ cp_dependency(ShaderMatInput inp) { return dep; } +/** + * Given ShaderMatInput, returns the size in the cache that this part requires. + */ +int Shader:: +cp_size(ShaderMatInput inp) { + switch (inp) { + case SMO_INVALID: + return 0; + + case SMO_window_size: + case SMO_pixel_size: + case SMO_texpad_x: + case SMO_texpix_x: + case SMO_attr_color: + case SMO_attr_colorscale: + case SMO_satten_x: + case SMO_plane_x: + case SMO_clipplane_x: + case SMO_vec_constant_x: + case SMO_frame_number: + case SMO_frame_time: + case SMO_frame_delta: + case SMO_vec_constant_x_attrib: + case SMO_light_ambient: + case SMO_light_product_i_ambient: + case SMO_light_product_i_diffuse: + case SMO_light_product_i_specular: + case SMO_apiview_clipplane_i: + case SMO_tex_is_alpha_i: + case SMO_texscale_i: + case SMO_texcolor_i: + case SMO_texconst_i: + case SMO_attr_pointparams: + return 1; + + case SMO_identity: + case SMO_alight_x: + case SMO_dlight_x: + case SMO_plight_x: + case SMO_slight_x: + case SMO_texmat_i: + case SMO_mat_constant_x: + case SMO_world_to_view: + case SMO_view_to_world: + case SMO_model_to_view: + case SMO_view_to_model: + case SMO_apiview_to_view: + case SMO_view_to_apiview: + case SMO_clip_to_view: + case SMO_view_to_clip: + case SMO_apiclip_to_view: + case SMO_view_to_apiclip: + case SMO_view_x_to_view: + case SMO_view_to_view_x: + case SMO_apiview_x_to_view: + case SMO_view_to_apiview_x: + case SMO_clip_x_to_view: + case SMO_view_to_clip_x: + case SMO_apiclip_x_to_view: + case SMO_view_to_apiclip_x: + case SMO_mat_constant_x_attrib: + case SMO_apiview_to_apiclip_light_source_i: + case SMO_model_to_apiview: + case SMO_apiview_to_model: + case SMO_apiview_to_apiclip: + case SMO_apiclip_to_apiview: + case SMO_inv_texmat_i: + case SMO_light_source_i_packed: + return 4; + + case SMO_attr_material: + return MA_COUNT; + + case SMO_light_source_i: + return LA_COUNT; + + case SMO_attr_fog: + return FA_COUNT; + } + + nassertr(false, 0); + return 0; +} + /** * Adds the given ShaderMatSpec to the shader's mat spec table. */ @@ -581,7 +665,7 @@ cp_add_mat_spec(ShaderMatSpec &spec) { for (int i = 0; i < 2; ++i) { if (spec._part[i] == SMO_texmat_i || spec._part[i] == SMO_inv_texmat_i || - spec._part[i] == SMO_light_source_i_vec_attrib || + spec._part[i] == SMO_light_source_i || spec._part[i] == SMO_apiview_to_apiclip_light_source_i || spec._part[i] == SMO_light_product_i_ambient || spec._part[i] == SMO_light_product_i_diffuse || @@ -602,6 +686,9 @@ cp_add_mat_spec(ShaderMatSpec &spec) { int num_parts = (spec._func != SMF_first) ? 2 : 1; for (int p = 0; p < num_parts; ++p) { + if (spec._part[p] == SMO_INVALID) { + continue; + } int dep = cp_dependency(spec._part[p]); spec._dep |= dep; @@ -635,6 +722,7 @@ cp_add_mat_spec(ShaderMatSpec &spec) { } offset += part._count * part._size; } + int size = cp_size(spec._part[p]); if (i == _mat_parts.size()) { // Didn't find this part yet, create a new one. ShaderMatPart part; @@ -642,91 +730,24 @@ cp_add_mat_spec(ShaderMatSpec &spec) { part._count = end[p]; part._arg = spec._arg[p]; part._dep = dep; - - switch (part._part) { - case SMO_INVALID: - part._size = 0; - break; - - case SMO_window_size: - case SMO_pixel_size: - case SMO_texpad_x: - case SMO_texpix_x: - case SMO_attr_color: - case SMO_attr_colorscale: - case SMO_satten_x: - case SMO_plane_x: - case SMO_clipplane_x: - case SMO_vec_constant_x: - case SMO_attr_fog: - case SMO_attr_fogcolor: - case SMO_frame_number: - case SMO_frame_time: - case SMO_frame_delta: - case SMO_vec_constant_x_attrib: - case SMO_light_ambient: - case SMO_light_source_i_vec_attrib: - case SMO_light_product_i_ambient: - case SMO_light_product_i_diffuse: - case SMO_light_product_i_specular: - case SMO_apiview_clipplane_i: - case SMO_tex_is_alpha_i: - case SMO_texscale_i: - case SMO_texcolor_i: - case SMO_texconst_i: - case SMO_attr_pointparams: - part._size = 1; - break; - - case SMO_attr_material2: - part._size = 2; - break; - - case SMO_identity: - case SMO_attr_material: - case SMO_alight_x: - case SMO_dlight_x: - case SMO_plight_x: - case SMO_slight_x: - case SMO_texmat_i: - case SMO_mat_constant_x: - case SMO_world_to_view: - case SMO_view_to_world: - case SMO_model_to_view: - case SMO_view_to_model: - case SMO_apiview_to_view: - case SMO_view_to_apiview: - case SMO_clip_to_view: - case SMO_view_to_clip: - case SMO_apiclip_to_view: - case SMO_view_to_apiclip: - case SMO_view_x_to_view: - case SMO_view_to_view_x: - case SMO_apiview_x_to_view: - case SMO_view_to_apiview_x: - case SMO_clip_x_to_view: - case SMO_view_to_clip_x: - case SMO_apiclip_x_to_view: - case SMO_view_to_apiclip_x: - case SMO_mat_constant_x_attrib: - case SMO_apiview_to_apiclip_light_source_i: - case SMO_model_to_apiview: - case SMO_apiview_to_model: - case SMO_apiview_to_apiclip: - case SMO_apiclip_to_apiview: - case SMO_inv_texmat_i: - case SMO_light_source_i_packed: - part._size = 4; - break; - } + part._size = size; if (spec._func != SMF_first) { assert(part._size == 4); } + _mat_cache_deps |= part._dep; _mat_parts.push_back(std::move(part)); } - spec._cache_offset[p] = offset + begin[p]; + spec._cache_offset[p] = offset + begin[p] * size; + } + if (spec._func == SMF_shader_input_ptr) { + _mat_scratch_size = std::max(_mat_scratch_size, spec._array_count); + + // We specify SSD_frame because a PTA may be modified by the app from + // frame to frame, and we have no way to know. So, we must respecify a + // PTA at least once every frame. + spec._dep |= SSD_general | SSD_shaderinputs | SSD_frame; } _mat_spec.push_back(spec); @@ -746,6 +767,15 @@ cp_get_mat_cache_size() const { return size; } +/** + * Returns the total amount of scratch space required to fetch the largest + * shader input of this shader. + */ +size_t Shader:: +cp_get_mat_scratch_size() const { + return _mat_scratch_size; +} + #ifdef HAVE_CG /** * @@ -1167,6 +1197,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._arg[0] = nullptr; bind._part[1] = SMO_identity; bind._arg[1] = nullptr; + bind._offset = FA_params; } else if (pieces[1] == "fogcolor") { if (!cp_errchk_parameter_float(p,3,4)) { return false; @@ -1174,10 +1205,11 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._id = p._id; bind._piece = SMP_vec4; bind._func = SMF_first; - bind._part[0] = SMO_attr_fogcolor; + bind._part[0] = SMO_attr_fog; bind._arg[0] = nullptr; bind._part[1] = SMO_identity; bind._arg[1] = nullptr; + bind._offset = FA_color; } else if (pieces[1] == "ambient") { if (!cp_errchk_parameter_float(p,3,4)) { return false; @@ -1208,11 +1240,12 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { bind._id = p._id; bind._piece = SMP_vec4; bind._func = SMF_first; - bind._part[0] = SMO_light_source_i_vec_attrib; - bind._arg[0] = InternalName::make("specular"); + bind._part[0] = SMO_light_source_i; + bind._arg[0] = nullptr; bind._part[1] = SMO_identity; bind._arg[1] = nullptr; bind._index = atoi(pieces[1].c_str() + 5); + bind._offset = LA_specular; } else if (pieces[1] == "pointparams") { if (!cp_errchk_parameter_float(p,3,4)) { return false; @@ -1483,7 +1516,7 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { if (!cp_errchk_parameter_float(p, 1, 1)) { return false; } - bind._piece = SMP_float; + bind._piece = SMP_scalar; bind._part[0] = SMO_frame_time; bind._arg[0] = nullptr; @@ -1620,11 +1653,11 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { (!cp_errchk_parameter_uniform(p))) { return false; } - bool k_prefix = false; + //bool k_prefix = false; // solve backward compatibility issue if (pieces[0] == "k") { - k_prefix = true; + //k_prefix = true; basename = basename.substr(2); } @@ -1635,25 +1668,25 @@ compile_parameter(ShaderArgInfo &p, int *arg_dim) { case SAC_matrix: case SAC_scalar: case SAC_array: { - if (!cp_errchk_parameter_ptr(p)) + if (!cp_errchk_parameter_ptr(p)) { return false; + } - ShaderPtrSpec bind; - bind._id = p._id; - bind._arg = kinputname; - bind._info = p; - - // We specify SSD_frame because a PTA may be modified by the app from - // frame to frame, and we have no way to know. So, we must respecify a - // PTA at least once every frame. - bind._dep[0] = SSD_general | SSD_shaderinputs | SSD_frame; - bind._dep[1] = SSD_NONE; - - memcpy(bind._dim,arg_dim,sizeof(int)*3); + ShaderMatSpec bind; + bind._id = p._id; + bind._func = SMF_shader_input_ptr; + bind._part[0] = SMO_INVALID; + bind._part[1] = SMO_INVALID; + bind._arg[0] = kinputname; + bind._arg[1] = nullptr; + bind._array_count = arg_dim[0] * arg_dim[1]; + bind._num_components = arg_dim[2]; + bind._numeric_type = p._numeric_type; + bind._piece = (ShaderMatPiece)(SMP_scalar + (arg_dim[2] - 1)); // if dim[0] = -1, glShaderContext will not check the param size - if (k_prefix) bind._dim[0] = -1; - _ptr_spec.push_back(bind); + //if (k_prefix) bind._dim[0] = -1; + cp_add_mat_spec(bind); return true; } @@ -2285,11 +2318,6 @@ cg_analyze_shader(const ShaderCaps &caps) { _tex_spec[i]._id._seqno = seqno++; } - for (size_t i = 0; i < _ptr_spec.size(); ++i) { - _ptr_spec[i]._id._seqno = seqno++; - _ptr_spec[i]._info._id = _ptr_spec[i]._id; - } - /* // The following code is present to work around a bug in the Cg compiler. // It does not generate correct code for shadow map lookups when using arbfp1. @@ -2452,9 +2480,8 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context, size_t n_mat = _mat_spec.size(); size_t n_tex = _tex_spec.size(); size_t n_var = _var_spec.size(); - size_t n_ptr = _ptr_spec.size(); - map.resize(n_mat + n_tex + n_var + n_ptr); + map.resize(n_mat + n_tex + n_var); // This is a bit awkward, we have to go in and seperate out the combined // program, since all the parameter bindings have changed. @@ -2513,19 +2540,6 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context, map[id._seqno] = p; } - for (size_t i = 0; i < n_ptr; ++i) { - const ShaderArgId &id = _ptr_spec[i]._id; - map[id._seqno] = cgGetNamedParameter(programs_by_type[id._type], id._name.c_str()); - - if (shader_cat.is_debug()) { - const char *resource = cgGetParameterResourceName(map[id._seqno]); - if (resource != nullptr) { - shader_cat.debug() << "Uniform ptr parameter " << id._name - << " is bound to resource " << resource << "\n"; - } - } - } - // Transfer ownership of the compiled shader. if (_cg_vprogram != 0) { cgDestroyProgram(_cg_vprogram); diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index 1b87d51c313..4bd548d3319 100644 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -33,7 +33,7 @@ #include "pta_LVecBase3.h" #include "pta_LVecBase2.h" #include "pStatCollector.h" -#include "epvector.h" +#include "pvector.h" #include "asyncFuture.h" #include "bamCacheRecord.h" @@ -173,7 +173,6 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { SMO_view_to_apiclip_x, SMO_attr_fog, - SMO_attr_fogcolor, SMO_frame_number, SMO_frame_time, @@ -183,7 +182,8 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { SMO_vec_constant_x_attrib, SMO_light_ambient, - SMO_light_source_i_vec_attrib, + SMO_light_source_i, + SMO_light_source_i_packed, SMO_apiview_to_apiclip_light_source_i, SMO_light_product_i_ambient, @@ -200,14 +200,9 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { SMO_inv_texmat_i, - // Additional properties for PBR materials - SMO_attr_material2, - // Hack for text rendering. Don't use in user shaders. SMO_tex_is_alpha_i, - SMO_light_source_i_packed, - // Texture scale component of texture matrix. SMO_texscale_i, @@ -292,21 +287,22 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { }; enum ShaderMatPiece { - SMP_float, + SMP_scalar, SMP_vec2, SMP_vec3, SMP_vec4, + SMP_scalar_array, + SMP_vec2_array, + SMP_vec3_array, SMP_vec4_array, + SMP_mat3_whole, + SMP_mat3_array, SMP_mat4_whole, SMP_mat4_array, SMP_mat4_transpose, SMP_mat4_column, SMP_mat4_upper3x3, SMP_mat4_transpose3x3, - SMP_int, - SMP_ivec2, - SMP_ivec3, - SMP_ivec4, }; enum ShaderStateDep { @@ -339,6 +335,7 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { SMF_transform_dlight, SMF_transform_plight, SMF_transform_slight, + SMF_shader_input_ptr, }; struct ShaderArgId { @@ -352,9 +349,43 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { SPT_double, SPT_int, SPT_uint, + SPT_bool, SPT_unknown }; + // Attributes (vec4) of the material structure. + enum MaterialAttribute { + MA_ambient, + MA_diffuse, + MA_emission, + MA_specular, // shininess in w + MA_base_color, + MA_metallic_ior_roughness, + MA_COUNT, + }; + + // Attributes (vec4) of the light structure. + enum LightAttribute { + LA_color, + LA_specular, + LA_ambient, + LA_diffuse, + LA_position, + LA_half_vector, + LA_spot_direction, + LA_spot_params, // spotCosCutoff, spotCutoff, spotExponent + LA_attenuation, // and radius + LA_shadow_view_matrix, // mat4 + LA_COUNT = LA_shadow_view_matrix + 4, + }; + + // Attributes (vec4) of the fog structure. + enum FogAttribute { + FA_params, // exp density, start, end, scale + FA_color, + FA_COUNT, + }; + struct ShaderArgInfo { ShaderArgId _id; ShaderArgClass _class; @@ -438,12 +469,13 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { ShaderMatFunc _func; ShaderMatInput _part[2]; PT(InternalName) _arg[2]; - LMatrix4f _value; int _dep = SSD_NONE; int _index = 0; ShaderMatPiece _piece; int _offset = 0; int _array_count = 1; + int _num_components; + ShaderPtrType _numeric_type = SPT_float; }; struct ShaderTexSpec { @@ -546,8 +578,10 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { vector_string &pieces, int &next, ShaderMatSpec &spec, bool fromflag); int cp_dependency(ShaderMatInput inp); + int cp_size(ShaderMatInput inp); void cp_add_mat_spec(ShaderMatSpec &spec); size_t cp_get_mat_cache_size() const; + size_t cp_get_mat_scratch_size() const; #ifdef HAVE_CG void cg_recurse_parameters(CGparameter parameter, @@ -607,13 +641,13 @@ class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount { #endif public: - pvector _ptr_spec; - epvector _mat_spec; + pvector _mat_spec; pvector _tex_spec; pvector _var_spec; pvector _mat_parts; + int _mat_cache_deps = 0; int _mat_deps = 0; - int _mat_cache_size = 0; + int _mat_scratch_size = 4; bool _error_flag; ShaderFile _text; diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index 0d349f6653b..de82e7580c1 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -278,7 +278,7 @@ set_clear_color(const LColor &color) { INLINE void Texture:: clear_clear_color() { CDWriter cdata(_cycler, true); - cdata->_has_clear_color = true; + cdata->_has_clear_color = false; } /** @@ -2139,6 +2139,14 @@ rescale_texture() { return do_rescale_texture(cdata); } +/** + * Returns the number previously passed to setup_async_transfer(). + */ +INLINE int Texture:: +get_num_async_transfer_buffers() const { + return _num_async_transfer_buffers.load(std::memory_order_relaxed); +} + /** * Works like adjust_size, but also considers the texture class. Movie * textures, for instance, always pad outwards, regardless of textures- diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 59ddcdc61e9..b8b1f5bbf15 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -1570,6 +1570,27 @@ get_view_modified_pages(UpdateSeq since, int view, int n) const { return result; } +/** + * Sets the number of buffers for asynchronous upload of texture data. If this + * number is higher than 0, future texture uploads will occur in the background, + * up to the provided amount at a time. The asynchronous upload will be + * triggered by calls to prepare() or when the texture comes into view and + * allow-incomplete-render is true. + * + * Each buffer is only large enough to contain a single view, so you may wish + * to create twice as many buffers if you want to update twice as many views. + * + * You can also pass the special value -1, which means to create as many + * buffers as is necessary for all asynchronous uploads to take place, and they + * will be deleted afterwards automatically. + * + * This setting will take effect immediately. + */ +void Texture:: +setup_async_transfer(int num_buffers) { + _num_async_transfer_buffers.store(num_buffers); +} + /** * Indicates that the texture should be enqueued to be prepared in the * indicated prepared_objects at the beginning of the next frame. This will @@ -5704,7 +5725,14 @@ do_modify_ram_image(CData *cdata) { } else { do_clear_ram_mipmap_images(cdata); } - return cdata->_ram_images[0]._image; + PTA_uchar data = cdata->_ram_images[0]._image; + if (data.get_node_ref_count() > 0) { + // Copy on write, if an upload thread is reading this now. + PTA_uchar new_data = PTA_uchar::empty_array(0); + new_data.v() = data.v(); + data.swap(new_data); + } + return data; } /** @@ -5779,7 +5807,15 @@ do_modify_ram_mipmap_image(CData *cdata, int n) { cdata->_ram_images[n]._image.empty()) { do_make_ram_mipmap_image(cdata, n); } - return cdata->_ram_images[n]._image; + + PTA_uchar data = cdata->_ram_images[n]._image; + if (data.get_node_ref_count() > 0) { + // Copy on write, if an upload thread is reading this now. + PTA_uchar new_data = PTA_uchar::empty_array(0); + new_data.v() = data.v(); + data.swap(new_data); + } + return data; } /** @@ -10183,13 +10219,15 @@ do_write_datagram_header(CData *cdata, BamWriter *manager, Datagram &me, bool &h << "Texture file " << cdata->_fullpath << " found as " << filename << "\n"; } - if (!has_bam_dir || !alpha_filename.make_relative_to(bam_dir, true)) { - alpha_filename.find_on_searchpath(get_model_path()); - } - if (gobj_cat.is_debug()) { - gobj_cat.debug() - << "Alpha image " << cdata->_alpha_fullpath - << " found as " << alpha_filename << "\n"; + if (!alpha_filename.empty()) { + if (!has_bam_dir || !alpha_filename.make_relative_to(bam_dir, true)) { + alpha_filename.find_on_searchpath(get_model_path()); + } + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "Alpha image " << cdata->_alpha_fullpath + << " found as " << alpha_filename << "\n"; + } } break; diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index f6ec5eb1f2a..4ba2b58169b 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -47,6 +47,7 @@ #include "pfmFile.h" #include "asyncTask.h" #include "extension.h" +#include "patomic.h" class TextureContext; class FactoryParams; @@ -536,6 +537,8 @@ class EXPCL_PANDA_GOBJ Texture : public TypedWritableReferenceCount, public Nama MAKE_PROPERTY(auto_texture_scale, get_auto_texture_scale, set_auto_texture_scale); + void setup_async_transfer(int num_buffers); + PT(AsyncFuture) prepare(PreparedGraphicsObjects *prepared_objects); bool is_prepared(PreparedGraphicsObjects *prepared_objects) const; bool was_image_modified(PreparedGraphicsObjects *prepared_objects) const; @@ -628,6 +631,7 @@ class EXPCL_PANDA_GOBJ Texture : public TypedWritableReferenceCount, public Nama public: void texture_uploaded(); + INLINE int get_num_async_transfer_buffers() const; virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const; @@ -1072,6 +1076,8 @@ class EXPCL_PANDA_GOBJ Texture : public TypedWritableReferenceCount, public Nama typedef pmap Contexts; Contexts _contexts; + patomic_signed_lock_free _num_async_transfer_buffers { 0 }; + // It is common, when using normal maps, specular maps, gloss maps, and // such, to use a file naming convention where the filenames of the special // maps are derived by concatenating a suffix to the name of the diffuse diff --git a/panda/src/gobj/textureCollection_ext.cxx b/panda/src/gobj/textureCollection_ext.cxx index 127bba9ac5e..46e99202804 100644 --- a/panda/src/gobj/textureCollection_ext.cxx +++ b/panda/src/gobj/textureCollection_ext.cxx @@ -31,13 +31,14 @@ __init__(PyObject *self, PyObject *sequence) { return; } + Py_BEGIN_CRITICAL_SECTION(fast); Py_ssize_t size = PySequence_Fast_GET_SIZE(fast); _this->reserve(size); for (int i = 0; i < size; ++i) { PyObject *item = PySequence_Fast_GET_ITEM(fast, i); if (item == nullptr) { - return; + break; } Texture *tex; @@ -48,13 +49,12 @@ __init__(PyObject *self, PyObject *sequence) { stream << "Element " << i << " in sequence passed to TextureCollection constructor is not a Texture"; std::string str = stream.str(); PyErr_SetString(PyExc_TypeError, str.c_str()); - Py_DECREF(fast); - return; + break; } else { _this->add_texture(tex); } } - + Py_END_CRITICAL_SECTION(); Py_DECREF(fast); } diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.I b/panda/src/grutil/pipeOcclusionCullTraverser.I index d5e8685afd9..9d51d185040 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.I +++ b/panda/src/grutil/pipeOcclusionCullTraverser.I @@ -42,8 +42,8 @@ get_occlusion_mask() const { * */ INLINE PipeOcclusionCullTraverser::PendingObject:: -PendingObject(CullableObject *object) : - _object(object) +PendingObject(CullableObject &&object) : + _object(std::move(object)) { } diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.cxx b/panda/src/grutil/pipeOcclusionCullTraverser.cxx index 62828319b35..ab0e859ceac 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.cxx +++ b/panda/src/grutil/pipeOcclusionCullTraverser.cxx @@ -217,28 +217,19 @@ end_traverse() { _current_query = nullptr; _next_query = nullptr; - PendingObjects::iterator oi; - for (oi = _pending_objects.begin(); oi != _pending_objects.end(); ++oi) { - PendingObject &pobj = (*oi); + for (PendingObject &pobj : _pending_objects) { if (pobj._query == nullptr) { _occlusion_untested_pcollector.add_level(1); - _true_cull_handler->record_object(pobj._object, this); + _true_cull_handler->record_object(std::move(pobj._object), this); } else { int num_fragments = pobj._query->get_num_fragments(); if (num_fragments != 0) { _occlusion_passed_pcollector.add_level(1); - _true_cull_handler->record_object(pobj._object, this); + _true_cull_handler->record_object(std::move(pobj._object), this); } else { _occlusion_failed_pcollector.add_level(1); - delete pobj._object; } } - - // The CullableObject has by now either been recorded (which will - // eventually delete it) or deleted directly. -#ifndef NDEBUG - pobj._object = nullptr; -#endif // NDEBUG } _pending_objects.clear(); CullTraverser::end_traverse(); @@ -363,9 +354,9 @@ traverse_below(CullTraverserData &data) { * the end of the scene. */ void PipeOcclusionCullTraverser:: -record_object(CullableObject *object, const CullTraverser *traverser) { +record_object(CullableObject &&object, const CullTraverser *traverser) { nassertv(traverser == this); - PendingObject pobj(object); + PendingObject pobj(std::move(object)); Thread *current_thread = get_current_thread(); @@ -379,13 +370,13 @@ record_object(CullableObject *object, const CullTraverser *traverser) { // ancestor. Don't perform another one. pobj._query = _current_query; - } else if (object->_geom->get_nested_vertices(current_thread) < min_occlusion_vertices) { + } else if (pobj._object._geom->get_nested_vertices(current_thread) < min_occlusion_vertices) { // This object is too small to bother testing for occlusions. } else { // Issue an occlusion test for this object. - CPT(BoundingVolume) vol = object->_geom->get_bounds(current_thread); - CPT(TransformState) net_transform = _inv_cs_world_transform->compose(object->_internal_transform); + CPT(BoundingVolume) vol = pobj._object._geom->get_bounds(current_thread); + CPT(TransformState) net_transform = _inv_cs_world_transform->compose(pobj._object._internal_transform); CPT(TransformState) internal_transform; CPT(Geom) geom; if (get_volume_viz(vol, geom, net_transform, internal_transform)) { @@ -394,7 +385,7 @@ record_object(CullableObject *object, const CullTraverser *traverser) { } } - _pending_objects.push_back(pobj); + _pending_objects.push_back(std::move(pobj)); } /** @@ -608,14 +599,13 @@ perform_occlusion_test(const Geom *geom, const TransformState *net_transform, gsg->begin_occlusion_query(); - CullableObject *viz = - new CullableObject(geom, _solid_test_state, internal_transform); + CullableObject viz(geom, _solid_test_state, internal_transform); static ConfigVariableBool test_occlude("test-occlude", false); if (test_occlude) { - _true_cull_handler->record_object(viz, _internal_trav); + _true_cull_handler->record_object(std::move(viz), _internal_trav); } else { - _internal_cull_handler->record_object(viz, _internal_trav); + _internal_cull_handler->record_object(std::move(viz), _internal_trav); } PT(OcclusionQueryContext) query = gsg->end_occlusion_query(); @@ -654,13 +644,9 @@ show_results(int num_fragments, const Geom *geom, TransparencyAttrib::make(TransparencyAttrib::M_alpha), ColorAttrib::make_flat(color)); - CullableObject *internal_viz = - new CullableObject(geom, state, internal_transform); - _internal_cull_handler->record_object(internal_viz, _internal_trav); + _internal_cull_handler->record_object(CullableObject(geom, state, internal_transform), _internal_trav); // Also render the viz in the main scene. internal_transform = get_scene()->get_cs_world_transform()->compose(net_transform); - CullableObject *main_viz = - new CullableObject(geom, state, internal_transform); - _true_cull_handler->record_object(main_viz, this); + _true_cull_handler->record_object(CullableObject(geom, state, internal_transform), this); } diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.h b/panda/src/grutil/pipeOcclusionCullTraverser.h index d41c5acff43..f193b997e66 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.h +++ b/panda/src/grutil/pipeOcclusionCullTraverser.h @@ -39,7 +39,7 @@ class GraphicsStateGuardian; * in grutil instead, for lack of any better ideas. */ class EXPCL_PANDA_GRUTIL PipeOcclusionCullTraverser : public CullTraverser, - public CullHandler { + public CullHandler { PUBLISHED: explicit PipeOcclusionCullTraverser(GraphicsOutput *host); PipeOcclusionCullTraverser(const PipeOcclusionCullTraverser ©) = delete; @@ -59,7 +59,7 @@ class EXPCL_PANDA_GRUTIL PipeOcclusionCullTraverser : public CullTraverser, virtual bool is_in_view(CullTraverserData &data); virtual void traverse_below(CullTraverserData &data); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); private: @@ -110,10 +110,10 @@ class EXPCL_PANDA_GRUTIL PipeOcclusionCullTraverser : public CullTraverser, class PendingObject { public: - INLINE PendingObject(CullableObject *object); + INLINE PendingObject(CullableObject &&object); INLINE ~PendingObject(); - CullableObject *_object; + CullableObject _object; PT(OcclusionQueryContext) _query; }; typedef pvector PendingObjects; diff --git a/panda/src/grutil/shaderTerrainMesh.cxx b/panda/src/grutil/shaderTerrainMesh.cxx index 339db9c3830..4b42a359384 100644 --- a/panda/src/grutil/shaderTerrainMesh.cxx +++ b/panda/src/grutil/shaderTerrainMesh.cxx @@ -544,8 +544,8 @@ void ShaderTerrainMesh::add_for_draw(CullTraverser *trav, CullTraverserData &dat state = state->set_attrib(current_shader_attrib, 10000); // Emit chunk - CullableObject *object = new CullableObject(_chunk_geom, std::move(state), std::move(modelview_transform)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + _chunk_geom, std::move(state), std::move(modelview_transform)), trav); // After rendering, increment the view index ++_current_view_index; diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 80d31f5c3c4..d49f144046f 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -22,6 +22,7 @@ #include "lightMutex.h" #include "patomic.h" #include "small_vector.h" +#include "completionToken.h" // A handful of forward references. @@ -149,6 +150,7 @@ class EXPCL_PANDA_GSGBASE GraphicsStateGuardianBase : public TypedWritableRefere virtual TextureContext *prepare_texture(Texture *tex)=0; virtual bool update_texture(TextureContext *tc, bool force)=0; + virtual bool update_texture(TextureContext *tc, bool force, CompletionToken token)=0; virtual void release_texture(TextureContext *tc)=0; virtual void release_textures(const pvector &contexts)=0; virtual bool extract_texture_data(Texture *tex)=0; diff --git a/panda/src/iphone/ipfreeze.py b/panda/src/iphone/ipfreeze.py index 8762b95b630..a18a20b9fc6 100755 --- a/panda/src/iphone/ipfreeze.py +++ b/panda/src/iphone/ipfreeze.py @@ -66,7 +66,7 @@ def usage(code, msg = ''): libs = '' libs += ' -framework Foundation -framework UIKit' if link_all_static: - libs += ' -lframework -lputil -lcollide -lpgraph -lchan -ltext -lpnmimage -lpnmimagetypes -levent -leffects -lgobj -ldisplay -lmathutil -lexpress -ldgraph -ldevice -ltform -llinmath -lpstatclient -lpanda -lglstuff -lrecorder -lpgui -lchar -lpipeline -lpandabase -llerp -lgsgbase -ldownloader -lparametrics -lpgraphnodes -lcull -lgrutil -lnet -lmovies -lnativenet -laudio -linterrogatedb -ldconfig -ldtoolutil -ldtoolbase -lprc -liphonedisplay -lpandaexpress -lpanda' + libs += ' -lframework -lputil -lcollide -lpgraph -lchan -ltext -lpnmimage -lpnmimagetypes -levent -leffects -lgobj -ldisplay -lmathutil -lexpress -ldgraph -ldevice -ltform -llinmath -lpstatclient -lpanda -lglstuff -lrecorder -lpgui -lchar -lpipeline -lpandabase -llerp -lgsgbase -ldownloader -lparametrics -lpgraphnodes -lcull -lgrutil -lnet -lmovies -lnativenet -laudio -ldconfig -ldtoolutil -ldtoolbase -lprc -liphonedisplay -lpandaexpress -lpanda' libs += ' -lphysics -lparticlesystem -lpandaphysics' libs += ' -ldistort -leffects -lpandafx' libs += ' -ldirectbase -ldcparser -ldeadrec -ldistributed -lhttp -lshowbase -linterval -lmotiontrail -ldirect' diff --git a/panda/src/linmath/compose_matrix_src.cxx b/panda/src/linmath/compose_matrix_src.cxx index 180f498e84d..e5694b71199 100644 --- a/panda/src/linmath/compose_matrix_src.cxx +++ b/panda/src/linmath/compose_matrix_src.cxx @@ -323,52 +323,82 @@ unwind_yup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr) { mat.get_row(z,2); // Project Z into the XZ plane. + FLOATTYPE heading = 0; FLOATNAME(LVector2) xz(z[0], z[2]); - xz = normalize(xz); - - // Compute the rotation about the +Y (up) axis. This is yaw, or "heading". - FLOATTYPE heading = rad_2_deg(((FLOATTYPE)catan2(xz[0], xz[1]))); - - // Unwind the heading, and continue. - FLOATNAME(LMatrix3) rot_y; - rot_y.set_rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f), - CS_yup_right); - - x = x * rot_y; - y = y * rot_y; - z = z * rot_y; + if (xz.normalize()) { + // Compute the rotation about the +Y (up) axis. This is yaw, or "heading". + heading = catan2(xz[0], xz[1]); + + // Unwind the heading, and continue. + FLOATNAME(LMatrix3) rot_y; + rot_y._m(0, 0) = xz[1]; + rot_y._m(0, 1) = 0; + rot_y._m(0, 2) = xz[0]; + + rot_y._m(1, 0) = 0; + rot_y._m(1, 1) = 1; + rot_y._m(1, 2) = 0; + + rot_y._m(2, 0) = -xz[0]; + rot_y._m(2, 1) = 0; + rot_y._m(2, 2) = xz[1]; + + x = x * rot_y; + y = y * rot_y; + z = z * rot_y; + } // Project the rotated Z into the YZ plane. + FLOATTYPE pitch = 0; FLOATNAME(LVector2) yz(z[1], z[2]); - yz = normalize(yz); - - // Compute the rotation about the +X (right) axis. This is pitch. - FLOATTYPE pitch = rad_2_deg((FLOATTYPE)(-catan2(yz[0], yz[1]))); - - // Unwind the pitch. - FLOATNAME(LMatrix3) rot_x; - rot_x.set_rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f), - CS_yup_right); - - x = x * rot_x; - y = y * rot_x; - z = z * rot_x; + if (yz.normalize()) { + // Compute the rotation about the +X (right) axis. This is pitch. + pitch = -catan2(yz[0], yz[1]); + + // Unwind the pitch. + FLOATNAME(LMatrix3) rot_x; + rot_x._m(0, 0) = 1; + rot_x._m(0, 1) = 0; + rot_x._m(0, 2) = 0; + + rot_x._m(1, 0) = 0; + rot_x._m(1, 1) = yz[1]; + rot_x._m(1, 2) = yz[0]; + + rot_x._m(2, 0) = 0; + rot_x._m(2, 1) = -yz[0]; + rot_x._m(2, 2) = yz[1]; + + x = x * rot_x; + y = y * rot_x; + z = z * rot_x; + } // Project the rotated X onto the XY plane. + FLOATTYPE roll = 0; FLOATNAME(LVector2) xy(x[0], x[1]); - xy = normalize(xy); - - // Compute the rotation about the +Z (back) axis. This is roll. - FLOATTYPE roll = -rad_2_deg(((FLOATTYPE)catan2(xy[1], xy[0]))); - - // Unwind the roll from the axes, and continue. - FLOATNAME(LMatrix3) rot_z; - rot_z.set_rotate_mat_normaxis(roll, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f), - CS_yup_right); - - x = x * rot_z; - y = y * rot_z; - z = z * rot_z; + if (xy.normalize()) { + // Compute the rotation about the +Z (back) axis. This is roll. + roll = -catan2(xy[1], xy[0]); + + // Unwind the roll from the axes, and continue. + FLOATNAME(LMatrix3) rot_z; + rot_z._m(0, 0) = xy[0]; + rot_z._m(0, 1) = -xy[1]; + rot_z._m(0, 2) = 0; + + rot_z._m(1, 0) = xy[1]; + rot_z._m(1, 1) = xy[0]; + rot_z._m(1, 2) = 0; + + rot_z._m(2, 0) = 0; + rot_z._m(2, 1) = 0; + rot_z._m(2, 2) = 1; + + x = x * rot_z; + y = y * rot_z; + z = z * rot_z; + } // Reset the matrix to reflect the unwinding. mat.set_row(0, x); @@ -376,9 +406,9 @@ unwind_yup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr) { mat.set_row(2, z); // Return the three rotation components. - hpr[0] = heading; - hpr[1] = pitch; - hpr[2] = roll; + hpr[0] = rad_2_deg(heading); + hpr[1] = rad_2_deg(pitch); + hpr[2] = rad_2_deg(roll); } /** @@ -398,52 +428,82 @@ unwind_zup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr) { mat.get_row(z,2); // Project Y into the XY plane. + FLOATTYPE heading = 0; FLOATNAME(LVector2) xy(y[0], y[1]); - xy = normalize(xy); - - // Compute the rotation about the +Z (up) axis. This is yaw, or "heading". - FLOATTYPE heading = -rad_2_deg(((FLOATTYPE)catan2(xy[0], xy[1]))); - - // Unwind the heading, and continue. - FLOATNAME(LMatrix3) rot_z; - rot_z.set_rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f), - CS_zup_right); - - x = x * rot_z; - y = y * rot_z; - z = z * rot_z; + if (xy.normalize()) { + // Compute the rotation about the +Z (up) axis. This is yaw, or "heading". + heading = -catan2(xy[0], xy[1]); + + // Unwind the heading, and continue. + FLOATNAME(LMatrix3) rot_z; + rot_z._m(0, 0) = xy[1]; + rot_z._m(0, 1) = xy[0]; + rot_z._m(0, 2) = 0; + + rot_z._m(1, 0) = -xy[0]; + rot_z._m(1, 1) = xy[1]; + rot_z._m(1, 2) = 0; + + rot_z._m(2, 0) = 0; + rot_z._m(2, 1) = 0; + rot_z._m(2, 2) = 1; + + x = x * rot_z; + y = y * rot_z; + z = z * rot_z; + } // Project the rotated Y into the YZ plane. + FLOATTYPE pitch = 0; FLOATNAME(LVector2) yz(y[1], y[2]); - yz = normalize(yz); - - // Compute the rotation about the +X (right) axis. This is pitch. - FLOATTYPE pitch = rad_2_deg(((FLOATTYPE)catan2(yz[1], yz[0]))); - - // Unwind the pitch. - FLOATNAME(LMatrix3) rot_x; - rot_x.set_rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f), - CS_zup_right); - - x = x * rot_x; - y = y * rot_x; - z = z * rot_x; + if (yz.normalize()) { + // Compute the rotation about the +X (right) axis. This is pitch. + pitch = catan2(yz[1], yz[0]); + + // Unwind the pitch. + FLOATNAME(LMatrix3) rot_x; + rot_x._m(0, 0) = 1; + rot_x._m(0, 1) = 0; + rot_x._m(0, 2) = 0; + + rot_x._m(1, 0) = 0; + rot_x._m(1, 1) = yz[0]; + rot_x._m(1, 2) = -yz[1]; + + rot_x._m(2, 0) = 0; + rot_x._m(2, 1) = yz[1]; + rot_x._m(2, 2) = yz[0]; + + x = x * rot_x; + y = y * rot_x; + z = z * rot_x; + } // Project X into the XZ plane. + FLOATTYPE roll = 0; FLOATNAME(LVector2) xz(x[0], x[2]); - xz = normalize(xz); - + if (xz.normalize()) { // Compute the rotation about the -Y (back) axis. This is roll. - FLOATTYPE roll = -rad_2_deg(((FLOATTYPE)catan2(xz[1], xz[0]))); + roll = -catan2(xz[1], xz[0]); - // Unwind the roll from the axes, and continue. - FLOATNAME(LMatrix3) rot_y; - rot_y.set_rotate_mat_normaxis(-roll, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f), - CS_zup_right); + // Unwind the roll from the axes, and continue. + FLOATNAME(LMatrix3) rot_y; + rot_y._m(0, 0) = xz[0]; + rot_y._m(0, 1) = 0; + rot_y._m(0, 2) = -xz[1]; - x = x * rot_y; - y = y * rot_y; - z = z * rot_y; + rot_y._m(1, 0) = 0; + rot_y._m(1, 1) = 1; + rot_y._m(1, 2) = 0; + + rot_y._m(2, 0) = xz[1]; + rot_y._m(2, 1) = 0; + rot_y._m(2, 2) = xz[0]; + + x = x * rot_y; + y = y * rot_y; + z = z * rot_y; + } // Reset the matrix to reflect the unwinding. mat.set_row(0, x); @@ -451,9 +511,9 @@ unwind_zup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr) { mat.set_row(2, z); // Return the three rotation components. - hpr[0] = heading; - hpr[1] = pitch; - hpr[2] = roll; + hpr[0] = rad_2_deg(heading); + hpr[1] = rad_2_deg(pitch); + hpr[2] = rad_2_deg(roll); } /** @@ -473,10 +533,12 @@ decompose_matrix(const FLOATNAME(LMatrix3) &mat, cs = get_default_coordinate_system(); } +#ifdef _DEBUG if (linmath_cat.is_debug()) { linmath_cat.debug() << "decomposing " << mat << " via cs " << cs << "\n"; } +#endif // Extract the rotation and scale, according to the coordinate system of // choice. @@ -534,10 +596,12 @@ decompose_matrix(const FLOATNAME(LMatrix3) &mat, return false; } +#ifdef _DEBUG if (linmath_cat.is_debug()) { linmath_cat.debug() << "after unwind, mat is " << new_mat << "\n"; } +#endif scale.set(new_mat(0, 0), new_mat(1, 1), new_mat(2, 2)); diff --git a/panda/src/linmath/dblnames.h b/panda/src/linmath/dblnames.h index c2c646b750d..47d143713e2 100644 --- a/panda/src/linmath/dblnames.h +++ b/panda/src/linmath/dblnames.h @@ -33,6 +33,7 @@ #undef FLOATTYPE_IS_INT #undef STRINGIFY #undef FLOATNAME_STR +#undef FLOATTYPE_REPR #define FLOATTYPE double #define FLOATNAME(ARG) ARG##d @@ -41,3 +42,16 @@ #define STRINGIFY(ARG) #ARG #define FLOATNAME_STR(ARG) STRINGIFY(ARG##d) + +#define FLOATTYPE_REPR(v, str) do { \ + double v_copy = (v); \ + char *into_str = (str); \ + if (v_copy < 1e16 && v_copy > -1e16 && \ + (double)(long long)v_copy == v_copy) { \ + snprintf(into_str, 32, "%lld", (long long)v_copy); \ + } else { \ + pdtoa(v_copy, into_str); \ + } \ +} while (0) + +#include "pdtoa.h" diff --git a/panda/src/linmath/fltnames.h b/panda/src/linmath/fltnames.h index d8d4762ddbe..c634b97cacf 100644 --- a/panda/src/linmath/fltnames.h +++ b/panda/src/linmath/fltnames.h @@ -33,6 +33,7 @@ #undef FLOATTYPE_IS_INT #undef STRINGIFY #undef FLOATNAME_STR +#undef FLOATTYPE_REPR #define FLOATTYPE float #define FLOATNAME(ARG) ARG##f @@ -41,3 +42,16 @@ #define STRINGIFY(ARG) #ARG #define FLOATNAME_STR(ARG) STRINGIFY(ARG##f) + +#define FLOATTYPE_REPR(v, str) do { \ + float v_copy = (v); \ + char *into_str = (str); \ + if (v_copy < 1e16f && v_copy > -1e16f && \ + (float)(long long)v_copy == v_copy) { \ + snprintf(into_str, 32, "%lld", (long long)v_copy); \ + } else { \ + pftoa(v_copy, into_str); \ + } \ +} while (0) + +#include "pdtoa.h" diff --git a/panda/src/linmath/intnames.h b/panda/src/linmath/intnames.h index 2a01d71e05f..a7e1ae7cb88 100644 --- a/panda/src/linmath/intnames.h +++ b/panda/src/linmath/intnames.h @@ -33,6 +33,7 @@ #undef FLOATTYPE_IS_INT #undef STRINGIFY #undef FLOATNAME_STR +#undef FLOATTYPE_REPR #define FLOATTYPE int #define FLOATNAME(ARG) ARG##i @@ -42,3 +43,5 @@ #define STRINGIFY(ARG) #ARG #define FLOATNAME_STR(ARG) STRINGIFY(ARG##i) + +#define FLOATTYPE_REPR(v, str) (snprintf((str), 12, "%d", (v))) diff --git a/panda/src/linmath/lmatrix3_ext_src.I b/panda/src/linmath/lmatrix3_ext_src.I index 38b47f4c047..f5759e3821f 100644 --- a/panda/src/linmath/lmatrix3_ext_src.I +++ b/panda/src/linmath/lmatrix3_ext_src.I @@ -47,18 +47,21 @@ __rmul__(FLOATTYPE scalar) const { */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LMatrix3" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_m(0, 0)) << ", " - << MAYBE_ZERO(_this->_m(0, 1)) << ", " - << MAYBE_ZERO(_this->_m(0, 2)) << ", " + char buf[32 * 17] = "LMatrix4"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_m(0, 0), p); + p += strlen(p); - << MAYBE_ZERO(_this->_m(1, 0)) << ", " - << MAYBE_ZERO(_this->_m(1, 1)) << ", " - << MAYBE_ZERO(_this->_m(1, 2)) << ", " + for (int i = 1; i < 9; ++i) { + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->get_data()[i], p); + p += strlen(p); + } - << MAYBE_ZERO(_this->_m(2, 0)) << ", " - << MAYBE_ZERO(_this->_m(2, 1)) << ", " - << MAYBE_ZERO(_this->_m(2, 2)) << ")"; - return out.str(); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } diff --git a/panda/src/linmath/lmatrix4_ext_src.I b/panda/src/linmath/lmatrix4_ext_src.I index 2d4e6d07fbb..9370b5d3b99 100644 --- a/panda/src/linmath/lmatrix4_ext_src.I +++ b/panda/src/linmath/lmatrix4_ext_src.I @@ -48,26 +48,21 @@ __rmul__(FLOATTYPE scalar) const { */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LMatrix4" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_m(0, 0)) << ", " - << MAYBE_ZERO(_this->_m(0, 1)) << ", " - << MAYBE_ZERO(_this->_m(0, 2)) << ", " - << MAYBE_ZERO(_this->_m(0, 3)) << ", " + char buf[32 * 17] = "LMatrix4"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_m(0, 0), p); + p += strlen(p); - << MAYBE_ZERO(_this->_m(1, 0)) << ", " - << MAYBE_ZERO(_this->_m(1, 1)) << ", " - << MAYBE_ZERO(_this->_m(1, 2)) << ", " - << MAYBE_ZERO(_this->_m(1, 3)) << ", " - - << MAYBE_ZERO(_this->_m(2, 0)) << ", " - << MAYBE_ZERO(_this->_m(2, 1)) << ", " - << MAYBE_ZERO(_this->_m(2, 2)) << ", " - << MAYBE_ZERO(_this->_m(2, 3)) << ", " + for (int i = 1; i < 16; ++i) { + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->get_data()[i], p); + p += strlen(p); + } - << MAYBE_ZERO(_this->_m(3, 0)) << ", " - << MAYBE_ZERO(_this->_m(3, 1)) << ", " - << MAYBE_ZERO(_this->_m(3, 2)) << ", " - << MAYBE_ZERO(_this->_m(3, 3)) << ")"; - return out.str(); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } diff --git a/panda/src/linmath/lorientation_src.I b/panda/src/linmath/lorientation_src.I index 8cc56aa2359..684f71118c5 100644 --- a/panda/src/linmath/lorientation_src.I +++ b/panda/src/linmath/lorientation_src.I @@ -70,7 +70,7 @@ FLOATNAME(LOrientation)(const FLOATNAME(LMatrix4) &m) { */ INLINE_LINMATH FLOATNAME(LOrientation) FLOATNAME(LOrientation):: operator * (const FLOATNAME(LRotation) &other) const { - return multiply((FLOATNAME(LOrientation) &)other); + return multiply((const FLOATNAME(LOrientation) &)other); } /** @@ -80,5 +80,5 @@ operator * (const FLOATNAME(LRotation) &other) const { INLINE_LINMATH FLOATNAME(LOrientation) FLOATNAME(LOrientation):: operator * (const FLOATNAME(LQuaternion) &other) const { nassert_raise("LOrientation * LQuaternion is undefined; use LOrientation * LRotation or LQuaternion * LQuaternion"); - return multiply((FLOATNAME(LOrientation) &)other); + return multiply((const FLOATNAME(LOrientation) &)other); } diff --git a/panda/src/linmath/lpoint2_ext_src.I b/panda/src/linmath/lpoint2_ext_src.I index 09f357686f7..44bd412ebf1 100644 --- a/panda/src/linmath/lpoint2_ext_src.I +++ b/panda/src/linmath/lpoint2_ext_src.I @@ -16,11 +16,19 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LPoint2" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ")"; - return out.str(); + char buf[96] = "LPoint2"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** diff --git a/panda/src/linmath/lpoint3_ext_src.I b/panda/src/linmath/lpoint3_ext_src.I index b45b62e936a..a1bb81f3293 100644 --- a/panda/src/linmath/lpoint3_ext_src.I +++ b/panda/src/linmath/lpoint3_ext_src.I @@ -16,12 +16,23 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LPoint3" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ", " - << MAYBE_ZERO(_this->_v(2)) << ")"; - return out.str(); + char buf[128] = "LPoint3"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(2), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** diff --git a/panda/src/linmath/lpoint4_ext_src.I b/panda/src/linmath/lpoint4_ext_src.I index ee64b2c287d..bbab239c916 100644 --- a/panda/src/linmath/lpoint4_ext_src.I +++ b/panda/src/linmath/lpoint4_ext_src.I @@ -16,13 +16,27 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LPoint4" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ", " - << MAYBE_ZERO(_this->_v(2)) << ", " - << MAYBE_ZERO(_this->_v(3)) << ")"; - return out.str(); + char buf[160] = "LPoint4"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(2), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(3), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** diff --git a/panda/src/linmath/lvecBase2_ext_src.I b/panda/src/linmath/lvecBase2_ext_src.I index d435399721d..adb8e793e95 100644 --- a/panda/src/linmath/lvecBase2_ext_src.I +++ b/panda/src/linmath/lvecBase2_ext_src.I @@ -24,11 +24,19 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LVecBase2" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ")"; - return out.str(); + char buf[96] = "LVecBase2"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** @@ -175,7 +183,7 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) { #endif } else { PyErr_Format(PyExc_ValueError, "'%.200s' object is not iterable", - assign->ob_type->tp_name); + Py_TYPE(assign)->tp_name); } return -1; } diff --git a/panda/src/linmath/lvecBase3_ext_src.I b/panda/src/linmath/lvecBase3_ext_src.I index e69e0f00de2..07a83a010d9 100644 --- a/panda/src/linmath/lvecBase3_ext_src.I +++ b/panda/src/linmath/lvecBase3_ext_src.I @@ -24,12 +24,23 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LVecBase3" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ", " - << MAYBE_ZERO(_this->_v(2)) << ")"; - return out.str(); + char buf[128] = "LVecBase3"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(2), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** @@ -176,7 +187,7 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) { #endif } else { PyErr_Format(PyExc_ValueError, "'%.200s' object is not iterable", - assign->ob_type->tp_name); + Py_TYPE(assign)->tp_name); } return -1; } @@ -408,3 +419,4 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const { #undef PYNUMBER_FLOATTYPE #undef PY_AS_FLOATTYPE +#undef FLOATTYPE_TO_STR diff --git a/panda/src/linmath/lvecBase4_ext_src.I b/panda/src/linmath/lvecBase4_ext_src.I index 44c97033d7e..40647bff427 100644 --- a/panda/src/linmath/lvecBase4_ext_src.I +++ b/panda/src/linmath/lvecBase4_ext_src.I @@ -24,13 +24,27 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LVecBase4" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ", " - << MAYBE_ZERO(_this->_v(2)) << ", " - << MAYBE_ZERO(_this->_v(3)) << ")"; - return out.str(); + char buf[160] = "LVecBase4"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(2), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(3), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** @@ -182,7 +196,7 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) { #endif } else { PyErr_Format(PyExc_ValueError, "'%.200s' object is not iterable", - assign->ob_type->tp_name); + Py_TYPE(assign)->tp_name); } return -1; } diff --git a/panda/src/linmath/lvector2_ext_src.I b/panda/src/linmath/lvector2_ext_src.I index dba65a1b61d..88449328ec7 100644 --- a/panda/src/linmath/lvector2_ext_src.I +++ b/panda/src/linmath/lvector2_ext_src.I @@ -16,11 +16,19 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LVector2" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ")"; - return out.str(); + char buf[96] = "LVector2"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** diff --git a/panda/src/linmath/lvector3_ext_src.I b/panda/src/linmath/lvector3_ext_src.I index 1c309ef87e6..7b7403384b7 100644 --- a/panda/src/linmath/lvector3_ext_src.I +++ b/panda/src/linmath/lvector3_ext_src.I @@ -16,12 +16,23 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LVector3" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ", " - << MAYBE_ZERO(_this->_v(2)) << ")"; - return out.str(); + char buf[128] = "LVector3"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(2), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** diff --git a/panda/src/linmath/lvector4_ext_src.I b/panda/src/linmath/lvector4_ext_src.I index dd8b3a6b48c..4a2fc80ca66 100644 --- a/panda/src/linmath/lvector4_ext_src.I +++ b/panda/src/linmath/lvector4_ext_src.I @@ -16,13 +16,27 @@ */ INLINE_LINMATH std::string Extension:: __repr__() const { - std::ostringstream out; - out << "LVector4" << FLOATTOKEN << "(" - << MAYBE_ZERO(_this->_v(0)) << ", " - << MAYBE_ZERO(_this->_v(1)) << ", " - << MAYBE_ZERO(_this->_v(2)) << ", " - << MAYBE_ZERO(_this->_v(3)) << ")"; - return out.str(); + char buf[160] = "LVector4"; + char *p = buf + strlen(buf); + *(p++) = FLOATTOKEN; + *(p++) = '('; + FLOATTYPE_REPR(_this->_v(0), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(1), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(2), p); + p += strlen(p); + *(p++) = ','; + *(p++) = ' '; + FLOATTYPE_REPR(_this->_v(3), p); + p += strlen(p); + *(p++) = ')'; + *p = '\0'; + return std::string(buf, p - buf); } /** diff --git a/panda/src/ode/odeSpace_ext.cxx b/panda/src/ode/odeSpace_ext.cxx index 4c6fb56161d..27f4cbbb6a7 100644 --- a/panda/src/ode/odeSpace_ext.cxx +++ b/panda/src/ode/odeSpace_ext.cxx @@ -72,7 +72,7 @@ collide(PyObject* arg, PyObject* callback) { nassertr(callback != nullptr, -1); if (!PyCallable_Check(callback)) { - PyErr_Format(PyExc_TypeError, "'%s' object is not callable", callback->ob_type->tp_name); + PyErr_Format(PyExc_TypeError, "'%s' object is not callable", Py_TYPE(callback)->tp_name); return -1; } else if (_this->get_id() == nullptr) { diff --git a/panda/src/ode/odeUtil_ext.cxx b/panda/src/ode/odeUtil_ext.cxx index e3115bfda68..545fbb6f1a2 100644 --- a/panda/src/ode/odeUtil_ext.cxx +++ b/panda/src/ode/odeUtil_ext.cxx @@ -28,7 +28,7 @@ int Extension:: collide2(const OdeGeom &geom1, const OdeGeom &geom2, PyObject* arg, PyObject* callback) { nassertr(callback != nullptr, -1); if (!PyCallable_Check(callback)) { - PyErr_Format(PyExc_TypeError, "'%s' object is not callable", callback->ob_type->tp_name); + PyErr_Format(PyExc_TypeError, "'%s' object is not callable", Py_TYPE(callback)->tp_name); return -1; } else { _python_callback = Py_XNewRef(callback); diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index 5d49c2dda36..cf1e073c9bc 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/panda/src/parametrics/ropeNode.cxx @@ -329,10 +329,8 @@ render_thread(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** @@ -375,10 +373,8 @@ render_tape(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** @@ -428,10 +424,8 @@ render_billboard(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** @@ -489,10 +483,8 @@ render_tube(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** @@ -523,8 +515,16 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments, LPoint3 point; result->eval_segment_point(segment, 0.0f, point); + // We need a bit more relaxed threshold to prevent breaks between + // segments, see GitHub issue #1325. +#ifdef STDFLOAT_DOUBLE + static const double threshold = 1.0e-8; +#else + static const float threshold = 1.0e-4f; +#endif + if (curve_segment == nullptr || - !point.almost_equal(last_point)) { + !point.almost_equal(last_point, threshold)) { // If the first point of this segment is different from the last point // of the previous segment, end the previous segment and begin a new // one. diff --git a/panda/src/parametrics/sheetNode.cxx b/panda/src/parametrics/sheetNode.cxx index 620a35512fa..cac84092786 100644 --- a/panda/src/parametrics/sheetNode.cxx +++ b/panda/src/parametrics/sheetNode.cxx @@ -319,10 +319,8 @@ render_sheet(CullTraverser *trav, CullTraverserData &data, state = state->add_attrib(ColorAttrib::make_vertex()); } - CullableObject *object = - new CullableObject(geom, state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), data.get_internal_transform(trav)), trav); } /** diff --git a/panda/src/pgraph/cullHandler.cxx b/panda/src/pgraph/cullHandler.cxx index b8f889706d5..3350e0a6d70 100644 --- a/panda/src/pgraph/cullHandler.cxx +++ b/panda/src/pgraph/cullHandler.cxx @@ -40,10 +40,9 @@ CullHandler:: * expected to delete it later. */ void CullHandler:: -record_object(CullableObject *object, const CullTraverser *traverser) { - nout << *object->_geom << " " << *object->_internal_transform << " " - << *object->_state << "\n"; - delete object; +record_object(CullableObject &&object, const CullTraverser *traverser) { + nout << *object._geom << " " << *object._internal_transform << " " + << *object._state << "\n"; } /** diff --git a/panda/src/pgraph/cullHandler.h b/panda/src/pgraph/cullHandler.h index 9d42d6bad82..a5877d5eb94 100644 --- a/panda/src/pgraph/cullHandler.h +++ b/panda/src/pgraph/cullHandler.h @@ -30,7 +30,7 @@ class EXPCL_PANDA_PGRAPH CullHandler { CullHandler(); virtual ~CullHandler(); - virtual void record_object(CullableObject *object, + virtual void record_object(CullableObject &&object, const CullTraverser *traverser); virtual void end_traverse(); diff --git a/panda/src/pgraph/cullResult.I b/panda/src/pgraph/cullResult.I index 303a06dfd87..a0ea58eb3fe 100644 --- a/panda/src/pgraph/cullResult.I +++ b/panda/src/pgraph/cullResult.I @@ -16,6 +16,7 @@ */ INLINE CullResult:: ~CullResult() { + delete_page(_page); } /** @@ -32,6 +33,19 @@ get_bin(int bin_index) { return make_new_bin(bin_index); } +/** + * Allocates memory for a new CullableObject that is associated with this + * CullResult. + */ +INLINE CullableObject *CullResult:: +alloc_object(CullableObject &&object) { + AllocationPage *page = _page; + if (page->_size >= page->_capacity) { + page = new_page(); + } + return new (page->_memory + sizeof(CullableObject) * (page->_size++)) CullableObject(std::move(object)); +} + /** * If the user configured flash-bin-binname, then update the object's state to * flash all the geometry in the bin. diff --git a/panda/src/pgraph/cullResult.cxx b/panda/src/pgraph/cullResult.cxx index b6b238f8383..d4b1550935a 100644 --- a/panda/src/pgraph/cullResult.cxx +++ b/panda/src/pgraph/cullResult.cxx @@ -61,6 +61,8 @@ CullResult(GraphicsStateGuardianBase *gsg, _gsg(gsg), _draw_region_pcollector(draw_region_pcollector) { + _page = &_first_page; + #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif @@ -100,13 +102,13 @@ make_next() const { * the owner of the object pointer, and will eventually delete it. */ void CullResult:: -add_object(CullableObject *object, const CullTraverser *traverser) { +add_object(CullableObject &&object, const CullTraverser *traverser) { static const LColor flash_alpha_color(0.92, 0.96, 0.10, 1.0f); static const LColor flash_binary_color(0.21f, 0.67f, 0.24, 1.0f); static const LColor flash_multisample_color(0.78f, 0.05f, 0.81f, 1.0f); static const LColor flash_dual_color(0.92, 0.01f, 0.01f, 1.0f); - nassertv(object->_draw_callback != nullptr || object->_geom != nullptr); + nassertv(object._draw_callback != nullptr || object._geom != nullptr); bool force = !traverser->get_effective_incomplete_render(); Thread *current_thread = traverser->get_current_thread(); @@ -114,62 +116,60 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // This is probably a good time to check for an auto rescale setting. const RescaleNormalAttrib *rescale; - object->_state->get_attrib_def(rescale); + object._state->get_attrib_def(rescale); if (rescale->get_mode() == RescaleNormalAttrib::M_auto) { RescaleNormalAttrib::Mode mode; - if (object->_internal_transform->has_identity_scale()) { + if (object._internal_transform->has_identity_scale()) { mode = RescaleNormalAttrib::M_none; - } else if (object->_internal_transform->has_uniform_scale()) { + } else if (object._internal_transform->has_uniform_scale()) { mode = RescaleNormalAttrib::M_rescale; } else { mode = RescaleNormalAttrib::M_normalize; } - object->_state = object->_state->compose(get_rescale_normal_state(mode)); + object._state = object._state->compose(get_rescale_normal_state(mode)); } // Check for a special wireframe setting. const RenderModeAttrib *rmode; - if (object->_state->get_attrib(rmode)) { + if (object._state->get_attrib(rmode)) { if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) { - CullableObject *wireframe_part = new CullableObject(*object); + CullableObject wireframe_part(object); const ShaderAttrib *shader = nullptr; - object->_state->get_attrib(shader); - wireframe_part->_state = get_wireframe_overlay_state(rmode, shader); + object._state->get_attrib(shader); + wireframe_part._state = get_wireframe_overlay_state(rmode, shader); - if (wireframe_part->munge_geom - (_gsg, _gsg->get_geom_munger(wireframe_part->_state, current_thread), + if (wireframe_part.munge_geom + (_gsg, _gsg->get_geom_munger(wireframe_part._state, current_thread), traverser, force)) { int wireframe_bin_index = bin_manager->find_bin("fixed"); CullBin *bin = get_bin(wireframe_bin_index); nassertv(bin != nullptr); - check_flash_bin(wireframe_part->_state, bin_manager, wireframe_bin_index); - bin->add_object(wireframe_part, current_thread); - } else { - delete wireframe_part; + check_flash_bin(wireframe_part._state, bin_manager, wireframe_bin_index); + bin->add_object(alloc_object(std::move(wireframe_part)), current_thread); } - object->_state = object->_state->compose(get_wireframe_filled_state()); + object._state = object._state->compose(get_wireframe_filled_state()); } } // Check to see if there's a special transparency setting. const TransparencyAttrib *trans; - if (object->_state->get_attrib(trans)) { + if (object._state->get_attrib(trans)) { switch (trans->get_mode()) { case TransparencyAttrib::M_alpha: case TransparencyAttrib::M_premultiplied_alpha: // M_alpha implies an alpha-write test, so we don't waste time writing // 0-valued pixels. - object->_state = object->_state->compose(get_alpha_state()); - check_flash_transparency(object->_state, flash_alpha_color); + object._state = object._state->compose(get_alpha_state()); + check_flash_transparency(object._state, flash_alpha_color); break; case TransparencyAttrib::M_binary: // M_binary is implemented by explicitly setting the alpha test. - object->_state = object->_state->compose(get_binary_state()); - check_flash_transparency(object->_state, flash_binary_color); + object._state = object._state->compose(get_binary_state()); + check_flash_transparency(object._state, flash_binary_color); break; case TransparencyAttrib::M_multisample: @@ -177,14 +177,14 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // The multisample modes are implemented using M_binary if the GSG in // use doesn't support multisample. if (!_gsg->get_supports_multisample()) { - object->_state = object->_state->compose(get_binary_state()); + object._state = object._state->compose(get_binary_state()); } - check_flash_transparency(object->_state, flash_multisample_color); + check_flash_transparency(object._state, flash_multisample_color); break; case TransparencyAttrib::M_dual: #ifndef NDEBUG - check_flash_transparency(object->_state, flash_dual_color); + check_flash_transparency(object._state, flash_dual_color); #endif if (!m_dual) { // If m_dual is configured off, it becomes M_alpha. @@ -198,7 +198,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) { // falls back to M_alpha. { const CullBinAttrib *bin_attrib; - if (!object->_state->get_attrib(bin_attrib) || + if (!object._state->get_attrib(bin_attrib) || bin_attrib->get_bin_name().empty()) { // We make a copy of the object to draw the transparent part; this // gets placed in the transparent bin. @@ -206,28 +206,25 @@ add_object(CullableObject *object, const CullTraverser *traverser) { if (m_dual_transparent) #endif { - CullableObject *transparent_part = new CullableObject(*object); + CullableObject transparent_part(object); CPT(RenderState) transparent_state = get_dual_transparent_state(); - transparent_part->_state = object->_state->compose(transparent_state); - if (transparent_part->munge_geom - (_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread), + transparent_part._state = object._state->compose(transparent_state); + if (transparent_part.munge_geom + (_gsg, _gsg->get_geom_munger(transparent_part._state, current_thread), traverser, force)) { - int transparent_bin_index = transparent_part->_state->get_bin_index(); + int transparent_bin_index = transparent_part._state->get_bin_index(); CullBin *bin = get_bin(transparent_bin_index); nassertv(bin != nullptr); - check_flash_bin(transparent_part->_state, bin_manager, transparent_bin_index); - bin->add_object(transparent_part, current_thread); - } else { - delete transparent_part; + check_flash_bin(transparent_part._state, bin_manager, transparent_bin_index); + bin->add_object(alloc_object(std::move(transparent_part)), current_thread); } } // Now we can draw the opaque part. This will end up in the opaque // bin. - object->_state = object->_state->compose(get_dual_opaque_state()); + object._state = object._state->compose(get_dual_opaque_state()); #ifndef NDEBUG if (!m_dual_opaque) { - delete object; return; } #endif @@ -242,20 +239,18 @@ add_object(CullableObject *object, const CullTraverser *traverser) { } } - int bin_index = object->_state->get_bin_index(); + int bin_index = object._state->get_bin_index(); CullBin *bin = get_bin(bin_index); nassertv(bin != nullptr); - check_flash_bin(object->_state, bin_manager, bin_index); + check_flash_bin(object._state, bin_manager, bin_index); // Munge vertices as needed for the GSG's requirements, and the object's // current state. - if (object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser, force)) { + if (object.munge_geom(_gsg, _gsg->get_geom_munger(object._state, current_thread), traverser, force)) { // The object may or may not now be fully resident, but this may not // matter, since the GSG may have the necessary buffers already loaded. // We'll let the GSG ultimately decide whether to render it. - bin->add_object(object, current_thread); - } else { - delete object; + bin->add_object(alloc_object(std::move(object)), current_thread); } } @@ -371,6 +366,33 @@ make_new_bin(int bin_index) { return bin_ptr; } +/** + * Creates a new AllocationPage replacing the old one. + */ +CullResult::AllocationPage *CullResult:: +new_page() { + AllocationPage *page = new AllocationPage; + page->_next = _page; + _page = page; + return page; +} + +/** + * + */ +void CullResult:: +delete_page(AllocationPage *page) { + size_t size = std::exchange(page->_size, 0); + for (size_t i = 0; i < size; ++i) { + ((CullableObject *)page->_memory)[i].~CullableObject(); + } + AllocationPage *next = page->_next; + if (next != nullptr) { + delete_page(next); + delete page; + } +} + /** * Returns a RenderState containing the given rescale normal attribute. */ diff --git a/panda/src/pgraph/cullResult.h b/panda/src/pgraph/cullResult.h index 24c0df3d787..ff7cb5fd51a 100644 --- a/panda/src/pgraph/cullResult.h +++ b/panda/src/pgraph/cullResult.h @@ -45,6 +45,7 @@ class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount { public: CullResult(GraphicsStateGuardianBase *gsg, const PStatCollector &draw_region_pcollector); + CullResult(const CullResult ©) = delete; INLINE ~CullResult(); PUBLISHED: @@ -52,7 +53,7 @@ class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount { INLINE CullBin *get_bin(int bin_index); - void add_object(CullableObject *object, const CullTraverser *traverser); + void add_object(CullableObject &&object, const CullTraverser *traverser); void finish_cull(SceneSetup *scene_setup, Thread *current_thread); void draw(Thread *current_thread); @@ -64,6 +65,11 @@ class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount { private: CullBin *make_new_bin(int bin_index); + struct AllocationPage; + AllocationPage *new_page(); + void delete_page(AllocationPage *page); + INLINE CullableObject *alloc_object(CullableObject &&object); + INLINE void check_flash_bin(CPT(RenderState) &state, CullBinManager *bin_manager, int bin_index); INLINE void check_flash_transparency(CPT(RenderState) &state, const LColor &color); @@ -88,6 +94,16 @@ class EXPCL_PANDA_PGRAPH CullResult : public ReferenceCount { bool _show_transparency = false; + // Arena allocator for CullableObjects. + struct AllocationPage { + AllocationPage *_next = nullptr; + static const size_t _capacity = 64; + size_t _size = 0; + alignas(CullableObject) unsigned char _memory[sizeof(CullableObject) * _capacity]; + }; + AllocationPage *_page; + AllocationPage _first_page; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index aa1ea8eaa2a..1982439e0d2 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -259,15 +259,8 @@ draw_bounding_volume(const BoundingVolume *vol, if (bounds_viz != nullptr) { _geoms_pcollector.add_level(2); - CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), - internal_transform); - _cull_handler->record_object(outer_viz, this); - - CullableObject *inner_viz = - new CullableObject(std::move(bounds_viz), get_bounds_inner_viz_state(), - internal_transform); - _cull_handler->record_object(inner_viz, this); + _cull_handler->record_object(CullableObject(bounds_viz, get_bounds_outer_viz_state(), internal_transform), this); + _cull_handler->record_object(CullableObject(std::move(bounds_viz), get_bounds_inner_viz_state(), internal_transform), this); } } @@ -309,11 +302,10 @@ show_bounds(CullTraverserData &data, bool tight) { if (bounds_viz != nullptr) { _geoms_pcollector.add_level(1); - CullableObject *outer_viz = - new CullableObject(std::move(bounds_viz), get_bounds_outer_viz_state(), - internal_transform); - outer_viz->_instances = data._instances; - _cull_handler->record_object(outer_viz, this); + CullableObject outer_viz(std::move(bounds_viz), get_bounds_outer_viz_state(), + internal_transform); + outer_viz._instances = data._instances; + _cull_handler->record_object(std::move(outer_viz), this); } } else if (data._instances == nullptr) { draw_bounding_volume(node->get_bounds(), internal_transform); diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index b11b464657a..46fdc228c6d 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -24,7 +24,6 @@ #include "geomNode.h" #include "cullTraverserData.h" #include "pStatCollector.h" -#include "deletedChain.h" #include "graphicsStateGuardianBase.h" #include "sceneSetup.h" #include "lightMutex.h" @@ -46,7 +45,10 @@ class EXPCL_PANDA_PGRAPH CullableObject { CPT(TransformState) internal_transform); INLINE CullableObject(const CullableObject ©); + INLINE CullableObject(CullableObject &&from) noexcept = default; + INLINE void operator = (const CullableObject ©); + INLINE CullableObject &operator = (CullableObject &&from) noexcept = default; bool munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, const CullTraverser *traverser, bool force); @@ -64,8 +66,6 @@ class EXPCL_PANDA_PGRAPH CullableObject { bool force, Thread *current_thread); public: - ALLOC_DELETED_CHAIN(CullableObject); - void output(std::ostream &out) const; public: diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 2b758c1cea9..0443dfc2081 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -538,10 +538,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { if (!geom->is_empty()) { CPT(RenderState) state = data._state->compose(geoms.get_geom_state(0)); if (!state->has_cull_callback() || state->cull_callback(trav, data)) { - CullableObject *object = - new CullableObject(std::move(geom), std::move(state), std::move(internal_transform)); - object->_instances = data._instances; - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(std::move(geom), std::move(state), std::move(internal_transform)); + object._instances = data._instances; + trav->get_cull_handler()->record_object(std::move(object), trav); } } } @@ -562,10 +561,9 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { if (data._instances != nullptr) { // Draw each individual instance. We don't bother culling each // individual Geom for each instance; that is probably way too slow. - CullableObject *object = - new CullableObject(std::move(geom), std::move(state), internal_transform); - object->_instances = data._instances; - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(std::move(geom), std::move(state), internal_transform); + object._instances = data._instances; + trav->get_cull_handler()->record_object(std::move(object), trav); continue; } @@ -588,9 +586,8 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { } } - CullableObject *object = - new CullableObject(std::move(geom), std::move(state), internal_transform); - trav->get_cull_handler()->record_object(object, trav); + trav->get_cull_handler()->record_object(CullableObject( + std::move(geom), std::move(state), internal_transform), trav); } } } diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index 15b130592d1..a051aeaf35f 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -392,13 +392,17 @@ try_load_file(const Filename &pathname, const LoaderOptions &options, sgr.premunge(result, RenderState::make_empty()); } - if (allow_ram_cache && result->is_of_type(ModelRoot::get_class_type())) { - // Store the loaded model in the RAM cache, and make sure we return a - // copy so that this node can be modified independently from the RAM - // cached version. - ModelPool::add_model(pathname, DCAST(ModelRoot, result.p())); - if ((options.get_flags() & LoaderOptions::LF_allow_instance) == 0) { - result = NodePath(result).copy_to(NodePath()).node(); + if (result->is_of_type(ModelRoot::get_class_type())) { + ((ModelRoot *)result.p())->set_fullpath(pathname); + + if (allow_ram_cache) { + // Store the loaded model in the RAM cache, and make sure we return a + // copy so that this node can be modified independently from the RAM + // cached version. + ModelPool::add_model(pathname, DCAST(ModelRoot, result.p())); + if ((options.get_flags() & LoaderOptions::LF_allow_instance) == 0) { + result = NodePath(result).copy_to(NodePath()).node(); + } } } diff --git a/panda/src/pgraph/modelPool.I b/panda/src/pgraph/modelPool.I index efa8fa99f8e..ff796e59538 100644 --- a/panda/src/pgraph/modelPool.I +++ b/panda/src/pgraph/modelPool.I @@ -42,7 +42,7 @@ verify_model(const Filename &filename) { * date (and hasn't been modified in the meantime), and if not, will still * return NULL. */ -INLINE ModelRoot *ModelPool:: +INLINE PT(ModelRoot) ModelPool:: get_model(const Filename &filename, bool verify) { return get_ptr()->ns_get_model(filename, verify); } @@ -54,7 +54,7 @@ get_model(const Filename &filename, bool verify) { * is true and the file has recently changed). If the model file cannot be * found, or cannot be loaded for some reason, returns NULL. */ -INLINE ModelRoot *ModelPool:: +INLINE PT(ModelRoot) ModelPool:: load_model(const Filename &filename, const LoaderOptions &options) { return get_ptr()->ns_load_model(filename, options); } diff --git a/panda/src/pgraph/modelPool.cxx b/panda/src/pgraph/modelPool.cxx index c53e2b867f8..76452b40055 100644 --- a/panda/src/pgraph/modelPool.cxx +++ b/panda/src/pgraph/modelPool.cxx @@ -48,7 +48,7 @@ ns_has_model(const Filename &filename) { /** * The nonstatic implementation of get_model(). */ -ModelRoot *ModelPool:: +PT(ModelRoot) ModelPool:: ns_get_model(const Filename &filename, bool verify) { PT(ModelRoot) cached_model; @@ -116,54 +116,31 @@ ns_get_model(const Filename &filename, bool verify) { /** * The nonstatic implementation of load_model(). */ -ModelRoot *ModelPool:: +PT(ModelRoot) ModelPool:: ns_load_model(const Filename &filename, const LoaderOptions &options) { - - // First check if it has already been loaded and is still current. + // First check if it's been cached under the given filename (for backward + // compatibility reasons) PT(ModelRoot) cached_model = ns_get_model(filename, true); if (cached_model != nullptr) { return cached_model; } - // Look on disk for the current file. LoaderOptions new_options(options); - new_options.set_flags((new_options.get_flags() | LoaderOptions::LF_no_ram_cache) & - ~LoaderOptions::LF_search); + new_options.set_flags(new_options.get_flags() & ~LoaderOptions::LF_no_ram_cache); Loader *model_loader = Loader::get_global_ptr(); PT(PandaNode) panda_node = model_loader->load_sync(filename, new_options); PT(ModelRoot) node; - if (panda_node.is_null()) { - // This model was not found. - - } else { + if (!panda_node.is_null()) { if (panda_node->is_of_type(ModelRoot::get_class_type())) { node = DCAST(ModelRoot, panda_node); - } else { // We have to construct a ModelRoot node to put it under. node = new ModelRoot(filename); node->add_child(panda_node); } - node->set_fullpath(filename); - } - - { - LightMutexHolder holder(_lock); - - // Look again, in case someone has just loaded the model in another - // thread. - Models::const_iterator ti; - ti = _models.find(filename); - if (ti != _models.end() && (*ti).second != cached_model) { - // This model was previously loaded. - return (*ti).second; - } - - _models[filename] = node; } - return node; } diff --git a/panda/src/pgraph/modelPool.h b/panda/src/pgraph/modelPool.h index 8e0476c6822..da9046c927d 100644 --- a/panda/src/pgraph/modelPool.h +++ b/panda/src/pgraph/modelPool.h @@ -43,9 +43,9 @@ class EXPCL_PANDA_PGRAPH ModelPool { PUBLISHED: INLINE static bool has_model(const Filename &filename); INLINE static bool verify_model(const Filename &filename); - INLINE static ModelRoot *get_model(const Filename &filename, bool verify); - BLOCKING INLINE static ModelRoot *load_model(const Filename &filename, - const LoaderOptions &options = LoaderOptions()); + INLINE static PT(ModelRoot) get_model(const Filename &filename, bool verify); + BLOCKING INLINE static PT(ModelRoot) load_model(const Filename &filename, + const LoaderOptions &options = LoaderOptions()); INLINE static void add_model(const Filename &filename, ModelRoot *model); INLINE static void release_model(const Filename &filename); @@ -65,9 +65,9 @@ class EXPCL_PANDA_PGRAPH ModelPool { INLINE ModelPool(); bool ns_has_model(const Filename &filename); - ModelRoot *ns_get_model(const Filename &filename, bool verify); - ModelRoot *ns_load_model(const Filename &filename, - const LoaderOptions &options); + PT(ModelRoot) ns_get_model(const Filename &filename, bool verify); + PT(ModelRoot) ns_load_model(const Filename &filename, + const LoaderOptions &options); void ns_add_model(const Filename &filename, ModelRoot *model); void ns_release_model(const Filename &filename); diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index b8f82f779ff..21328a58886 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -884,6 +884,8 @@ class EXPCL_PANDA_PGRAPH NodePath { INLINE void set_collide_mask(CollideMask new_mask, CollideMask bits_to_change = CollideMask::all_on(), TypeHandle node_type = TypeHandle::none()); + EXTENSION(void set_collide_owner(PyObject *owner)); + // Comparison methods INLINE bool operator == (const NodePath &other) const; INLINE bool operator != (const NodePath &other) const; diff --git a/panda/src/pgraph/nodePathCollection_ext.cxx b/panda/src/pgraph/nodePathCollection_ext.cxx index a06caf8380d..de0267e5896 100644 --- a/panda/src/pgraph/nodePathCollection_ext.cxx +++ b/panda/src/pgraph/nodePathCollection_ext.cxx @@ -36,13 +36,14 @@ __init__(PyObject *self, PyObject *sequence) { return; } + Py_BEGIN_CRITICAL_SECTION(fast); Py_ssize_t size = PySequence_Fast_GET_SIZE(fast); _this->reserve(size); for (int i = 0; i < size; ++i) { PyObject *item = PySequence_Fast_GET_ITEM(fast, i); if (item == nullptr) { - return; + break; } NodePath *path; @@ -52,13 +53,12 @@ __init__(PyObject *self, PyObject *sequence) { stream << "Element " << i << " in sequence passed to NodePathCollection constructor is not a NodePath"; std::string str = stream.str(); PyErr_SetString(PyExc_TypeError, str.c_str()); - Py_DECREF(fast); - return; + break; } else { _this->add_path(*path); } } - + Py_END_CRITICAL_SECTION(); Py_DECREF(fast); } @@ -75,7 +75,7 @@ __reduce__(PyObject *self) const { // object whose constructor we should call (e.g. this), and the arguments // necessary to reconstruct this object. - PyObject *this_class = (PyObject *)self->ob_type; + PyObject *this_class = (PyObject *)Py_TYPE(self); if (this_class == nullptr) { return nullptr; } diff --git a/panda/src/pgraph/nodePath_ext.cxx b/panda/src/pgraph/nodePath_ext.cxx index 23cfb172d25..060a96e44df 100644 --- a/panda/src/pgraph/nodePath_ext.cxx +++ b/panda/src/pgraph/nodePath_ext.cxx @@ -15,6 +15,7 @@ #include "typedWritable_ext.h" #include "shaderInput_ext.h" #include "shaderAttrib.h" +#include "collisionNode.h" #ifdef HAVE_PYTHON @@ -56,10 +57,10 @@ __deepcopy__(PyObject *self, PyObject *memo) const { extern struct Dtool_PyTypedObject Dtool_NodePath; // Borrowed reference. - PyObject *dupe = PyDict_GetItem(memo, self); - if (dupe != nullptr) { + PyObject *dupe; + if (PyDict_GetItemRef(memo, self, &dupe) > 0) { // Already in the memo dictionary. - return Py_NewRef(dupe); + return dupe; } NodePath *np_dupe; @@ -279,19 +280,21 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { PyObject *key, *value; Py_ssize_t pos = 0; + Py_BEGIN_CRITICAL_SECTION(kwargs); while (PyDict_Next(kwargs, &pos, &key, &value)) { char *buffer; Py_ssize_t length; buffer = (char *)PyUnicode_AsUTF8AndSize(key, &length); if (buffer == nullptr) { Dtool_Raise_TypeError("NodePath.set_shader_inputs accepts only string keywords"); - return; + break; } CPT_InternalName name(std::string(buffer, length)); ShaderInput &input = attrib->_inputs[name]; invoke_extension(&input).__init__(std::move(name), value); } + Py_END_CRITICAL_SECTION(); if (!PyErr_Occurred()) { node->set_attrib(ShaderAttrib::return_new(attrib)); @@ -325,4 +328,62 @@ get_tight_bounds(const NodePath &other) const { } } +/** + * Recursively assigns a weak reference to the given owner object to all + * collision nodes at this level and below. + * + * You may pass in None to clear all owners below this level. + * + * Note that there is no corresponding get_collide_owner(), since there may be + * multiple nodes below this level with different owners. + */ +void Extension:: +set_collide_owner(PyObject *owner) { + if (owner != Py_None) { + PyObject *ref = PyWeakref_NewRef(owner, nullptr); + if (ref != nullptr) { + r_set_collide_owner(_this->node(), ref); + Py_DECREF(ref); + } + } else { + r_clear_collide_owner(_this->node()); + } +} + +/** + * Recursive implementation of set_collide_owner. weakref must be a weak ref + * object. + */ +void Extension:: +r_set_collide_owner(PandaNode *node, PyObject *weakref) { + if (node->is_collision_node()) { + CollisionNode *cnode = (CollisionNode *)node; + cnode->set_owner(Py_NewRef(weakref), + [](void *obj) { Py_DECREF((PyObject *)obj); }); + } + + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + r_set_collide_owner(cr.get_child(i), weakref); + } +} + +/** + * Recursive implementation of set_collide_owner(None). + */ +void Extension:: +r_clear_collide_owner(PandaNode *node) { + if (node->is_collision_node()) { + CollisionNode *cnode = (CollisionNode *)node; + cnode->clear_owner(); + } + + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + r_clear_collide_owner(cr.get_child(i)); + } +} + #endif // HAVE_PYTHON diff --git a/panda/src/pgraph/nodePath_ext.h b/panda/src/pgraph/nodePath_ext.h index b1127f930d2..b6f03b792cf 100644 --- a/panda/src/pgraph/nodePath_ext.h +++ b/panda/src/pgraph/nodePath_ext.h @@ -54,6 +54,12 @@ class Extension : public ExtensionBase { void set_shader_inputs(PyObject *args, PyObject *kwargs); PyObject *get_tight_bounds(const NodePath &other = NodePath()) const; + + void set_collide_owner(PyObject *owner); + +private: + static void r_set_collide_owner(PandaNode *node, PyObject *weakref); + static void r_clear_collide_owner(PandaNode *node); }; BEGIN_PUBLISH diff --git a/panda/src/pgraph/occluderNode.cxx b/panda/src/pgraph/occluderNode.cxx index a1db42c3c36..408f5e28f19 100644 --- a/panda/src/pgraph/occluderNode.cxx +++ b/panda/src/pgraph/occluderNode.cxx @@ -141,17 +141,15 @@ bool OccluderNode:: cull_callback(CullTraverser *trav, CullTraverserData &data) { // Normally, an OccluderNode is invisible. But if someone shows it, we will // draw a visualization, a checkerboard-textured polygon. - CullableObject *occluder_viz = - new CullableObject(get_occluder_viz(trav, data), get_occluder_viz_state(trav, data), - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(occluder_viz, trav); + trav->get_cull_handler()->record_object(CullableObject( + get_occluder_viz(trav, data), get_occluder_viz_state(trav, data), + data.get_internal_transform(trav)), trav); // Also get the frame. nassertr(_frame_viz != nullptr, false); - CullableObject *frame_viz = - new CullableObject(_frame_viz, get_frame_viz_state(trav, data), - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(frame_viz, trav); + trav->get_cull_handler()->record_object(CullableObject( + _frame_viz, get_frame_viz_state(trav, data), + data.get_internal_transform(trav)), trav); // Now carry on to render our child nodes. return true; diff --git a/panda/src/pgraph/pandaNode_ext.cxx b/panda/src/pgraph/pandaNode_ext.cxx index cd7ca8b2529..f1d25ed08e9 100644 --- a/panda/src/pgraph/pandaNode_ext.cxx +++ b/panda/src/pgraph/pandaNode_ext.cxx @@ -47,10 +47,10 @@ __deepcopy__(PyObject *self, PyObject *memo) const { extern struct Dtool_PyTypedObject Dtool_PandaNode; // Borrowed reference. - PyObject *dupe = PyDict_GetItem(memo, self); - if (dupe != nullptr) { + PyObject *dupe; + if (PyDict_GetItemRef(memo, self, &dupe) > 0) { // Already in the memo dictionary. - return Py_NewRef(dupe); + return dupe; } PT(PandaNode) node_dupe = _this->copy_subgraph(); @@ -122,12 +122,11 @@ get_python_tag(PyObject *key) const { } PyObject *dict = ((PythonTagDataImpl *)_this->_python_tag_data.p())->_dict; - PyObject *value = PyDict_GetItem(dict, key); - if (value == nullptr) { - value = Py_None; + PyObject *value; + if (PyDict_GetItemRef(dict, key, &value) == 0) { + value = Py_NewRef(Py_None); } - // PyDict_GetItem returns a borrowed reference. - return Py_NewRef(value); + return value; } /** @@ -142,7 +141,7 @@ has_python_tag(PyObject *key) const { } PyObject *dict = ((PythonTagDataImpl *)_this->_python_tag_data.p())->_dict; - return (PyDict_GetItem(dict, key) != nullptr); + return PyDict_Contains(dict, key); } /** @@ -157,7 +156,8 @@ clear_python_tag(PyObject *key) { } PyObject *dict = do_get_python_tags(); - if (PyDict_GetItem(dict, key) != nullptr) { + Py_BEGIN_CRITICAL_SECTION(dict); + if (PyDict_Contains(dict, key)) { PyDict_DelItem(dict, key); } @@ -166,6 +166,7 @@ clear_python_tag(PyObject *key) { // unique reference to the tags, so clear the tag object. _this->_python_tag_data.clear(); } + Py_END_CRITICAL_SECTION(); } /** diff --git a/panda/src/pgraph/planeNode.cxx b/panda/src/pgraph/planeNode.cxx index dbae5ff960c..4a290a24544 100644 --- a/panda/src/pgraph/planeNode.cxx +++ b/panda/src/pgraph/planeNode.cxx @@ -140,10 +140,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // Normally, a PlaneNode is invisible. But if someone shows it, we will // draw a visualization, a nice yellow wireframe. - CullableObject *plane_viz = - new CullableObject(get_viz(trav, data), data._state, - data.get_internal_transform(trav)); - trav->get_cull_handler()->record_object(plane_viz, trav); + trav->get_cull_handler()->record_object(CullableObject( + get_viz(trav, data), data._state, data.get_internal_transform(trav)), trav); // Now carry on to render our child nodes. return true; diff --git a/panda/src/pgraph/pythonLoaderFileType.cxx b/panda/src/pgraph/pythonLoaderFileType.cxx index 9076a3535e9..aa4b84cceb5 100644 --- a/panda/src/pgraph/pythonLoaderFileType.cxx +++ b/panda/src/pgraph/pythonLoaderFileType.cxx @@ -89,26 +89,25 @@ init(PyObject *loader) { return false; } - PyObject *sequence = PySequence_Fast(extensions, "extensions must be a sequence"); - PyObject **items = PySequence_Fast_ITEMS(sequence); - Py_ssize_t num_items = PySequence_Fast_GET_SIZE(sequence); + PyObject *tuple = PySequence_Tuple(extensions); + Py_ssize_t num_items = PyTuple_GET_SIZE(tuple); Py_DECREF(extensions); if (num_items == 0) { PyErr_SetString(PyExc_ValueError, "extensions list may not be empty"); - Py_DECREF(sequence); + Py_DECREF(tuple); return false; } bool found_extension = false; for (Py_ssize_t i = 0; i < num_items; ++i) { - PyObject *extension = items[i]; + PyObject *extension = PyTuple_GET_ITEM(tuple, i); const char *extension_str; Py_ssize_t extension_len; extension_str = PyUnicode_AsUTF8AndSize(extension, &extension_len); if (extension_str == nullptr) { - Py_DECREF(sequence); + Py_DECREF(tuple); return false; } @@ -127,7 +126,7 @@ init(PyObject *loader) { } } } - Py_DECREF(sequence); + Py_DECREF(tuple); if (!found_extension) { PyObject *repr = PyObject_Repr(loader); diff --git a/panda/src/pgraph/renderState_ext.cxx b/panda/src/pgraph/renderState_ext.cxx index 6cfe05965e0..085d79d6f90 100644 --- a/panda/src/pgraph/renderState_ext.cxx +++ b/panda/src/pgraph/renderState_ext.cxx @@ -56,7 +56,7 @@ make(PyObject *args, PyObject *kwds) { int override = 0; if (py_override != nullptr) { - override = _PyLong_AsInt(py_override); + override = PyLong_AsInt(py_override); if (override == -1 && PyErr_Occurred()) { return nullptr; } diff --git a/panda/src/pgraph/shaderAttrib_ext.cxx b/panda/src/pgraph/shaderAttrib_ext.cxx index b599d5ab255..012095935ae 100644 --- a/panda/src/pgraph/shaderAttrib_ext.cxx +++ b/panda/src/pgraph/shaderAttrib_ext.cxx @@ -46,22 +46,28 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) const { PyObject *key, *value; Py_ssize_t pos = 0; + Py_BEGIN_CRITICAL_SECTION(kwargs); while (PyDict_Next(kwargs, &pos, &key, &value)) { char *buffer; Py_ssize_t length; buffer = (char *)PyUnicode_AsUTF8AndSize(key, &length); if (buffer == nullptr) { Dtool_Raise_TypeError("ShaderAttrib.set_shader_inputs accepts only string keywords"); - delete attrib; - return nullptr; + break; } CPT_InternalName name(std::string(buffer, length)); ShaderInput &input = attrib->_inputs[name]; invoke_extension(&input).__init__(std::move(name), value); } + Py_END_CRITICAL_SECTION(); - return ShaderAttrib::return_new(attrib); + if (!PyErr_Occurred()) { + return ShaderAttrib::return_new(attrib); + } else { + delete attrib; + return nullptr; + } } #endif // HAVE_PYTHON diff --git a/panda/src/pgraph/shaderInput_ext.cxx b/panda/src/pgraph/shaderInput_ext.cxx index d7496120b69..e9c83c18fcc 100644 --- a/panda/src/pgraph/shaderInput_ext.cxx +++ b/panda/src/pgraph/shaderInput_ext.cxx @@ -269,12 +269,20 @@ __init__(CPT_InternalName name, PyObject *value, int priority) { } else if (PySequence_Check(value) && !PyUnicode_CheckExact(value)) { // Iterate over the sequence to make sure all have the same type. +#ifdef Py_GIL_DISABLED + PyObject *fast = PySequence_Tuple(value); +#else PyObject *fast = PySequence_Fast(value, "unknown type passed to ShaderInput"); +#endif if (fast == nullptr) { return; } +#ifdef Py_GIL_DISABLED + Py_ssize_t num_items = PyTuple_GET_SIZE(fast); +#else Py_ssize_t num_items = PySequence_Fast_GET_SIZE(fast); +#endif if (num_items <= 0) { // We can't determine the type of a list of size 0. _this->_type = ShaderInput::M_numeric; @@ -289,6 +297,9 @@ __init__(CPT_InternalName name, PyObject *value, int priority) { for (Py_ssize_t i = 0; i < num_items; ++i) { PyObject *item = items[i]; + //FIXME: if these items are not tuples, this is not thread-safe in the + // free-threaded build. Convert everything to tuples, and push to a + // vector? if (PySequence_Check(item)) { Py_ssize_t itemsize = PySequence_Size(item); if (known_itemsize >= 0 && itemsize != known_itemsize) { @@ -310,7 +321,7 @@ __init__(CPT_InternalName name, PyObject *value, int priority) { Dtool_Raise_TypeError("unknown element type in sequence passed as element of sequence passed to ShaderInput"); Py_DECREF(subitem); Py_DECREF(fast); - break; + return; } Py_DECREF(subitem); } diff --git a/panda/src/pgraphnodes/callbackNode.cxx b/panda/src/pgraphnodes/callbackNode.cxx index 2e555dfd1eb..8ebb38cd15d 100644 --- a/panda/src/pgraphnodes/callbackNode.cxx +++ b/panda/src/pgraphnodes/callbackNode.cxx @@ -121,11 +121,10 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { // Geoms, however. CallbackObject *cbobj = get_draw_callback(); if (cbobj != nullptr) { - CullableObject *object = - new CullableObject(nullptr, data._state, - data.get_internal_transform(trav)); - object->set_draw_callback(cbobj); - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(nullptr, data._state, + data.get_internal_transform(trav)); + object.set_draw_callback(cbobj); + trav->get_cull_handler()->record_object(std::move(object), trav); } } diff --git a/panda/src/pgraphnodes/computeNode.cxx b/panda/src/pgraphnodes/computeNode.cxx index 8c757e2860b..505989762d2 100644 --- a/panda/src/pgraphnodes/computeNode.cxx +++ b/panda/src/pgraphnodes/computeNode.cxx @@ -82,11 +82,10 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { // OK, render this node. Rendering this node means creating a // CullableObject for the Dispatcher. We don't need to pass any Geoms, // however. - CullableObject *object = - new CullableObject(nullptr, data._state, - data.get_internal_transform(trav)); - object->set_draw_callback(_dispatcher); - trav->get_cull_handler()->record_object(object, trav); + CullableObject object(nullptr, data._state, + data.get_internal_transform(trav)); + object.set_draw_callback(_dispatcher); + trav->get_cull_handler()->record_object(std::move(object), trav); } /** diff --git a/panda/src/pgraphnodes/lightLensNode.cxx b/panda/src/pgraphnodes/lightLensNode.cxx index 0aabcb07b4a..cb84c28dfbe 100644 --- a/panda/src/pgraphnodes/lightLensNode.cxx +++ b/panda/src/pgraphnodes/lightLensNode.cxx @@ -19,6 +19,7 @@ #include "renderState.h" #include "cullFaceAttrib.h" #include "colorWriteAttrib.h" +#include "lightAttrib.h" #include "graphicsStateGuardianBase.h" TypeHandle LightLensNode::_type_handle; @@ -37,10 +38,14 @@ LightLensNode(const std::string &name, Lens *lens) : _shadow_caster = false; _sb_size.set(512, 512); _sb_sort = -10; - // set_initial_state(RenderState::make(ShaderAttrib::make_off(), 1000)); + // Backface culling helps eliminating artifacts. - set_initial_state(RenderState::make(CullFaceAttrib::make_reverse(), - ColorWriteAttrib::make(ColorWriteAttrib::C_off))); + static CPT(RenderState) default_initial_state = + RenderState::make( + CullFaceAttrib::make_reverse(), + ColorWriteAttrib::make(ColorWriteAttrib::C_off) + )->set_attrib(LightAttrib::make_all_off(), RenderState::get_max_priority()); + set_initial_state(default_initial_state); } /** diff --git a/panda/src/pgraphnodes/nodeCullCallbackData.cxx b/panda/src/pgraphnodes/nodeCullCallbackData.cxx index 5a9dbc9e0ac..32faac3930d 100644 --- a/panda/src/pgraphnodes/nodeCullCallbackData.cxx +++ b/panda/src/pgraphnodes/nodeCullCallbackData.cxx @@ -48,11 +48,10 @@ upcall() { // any Geoms, however. CallbackObject *cbobj = cbnode->get_draw_callback(); if (cbobj != nullptr) { - CullableObject *object = - new CullableObject(nullptr, _data._state, - _data.get_internal_transform(_trav)); - object->set_draw_callback(cbobj); - _trav->get_cull_handler()->record_object(object, _trav); + CullableObject object(nullptr, _data._state, + _data.get_internal_transform(_trav)); + object.set_draw_callback(cbobj); + _trav->get_cull_handler()->record_object(std::move(object), _trav); } } diff --git a/panda/src/pgui/pgItem.cxx b/panda/src/pgui/pgItem.cxx index 7d2e884f82c..d612e889ccb 100644 --- a/panda/src/pgui/pgItem.cxx +++ b/panda/src/pgui/pgItem.cxx @@ -775,9 +775,14 @@ move(const MouseWatcherParameter ¶m) { */ void PGItem:: background_press(const MouseWatcherParameter ¶m) { - for (PGItem *item : _background_focus) { + // We have to be careful, because objects may remove themselves from the set + // while we're iterating over it. + auto it = _background_focus.begin(); + while (it != _background_focus.end()) { + PGItem *item = *it++; if (!item->get_focus()) { - item->press(param, true); + PT(PGItem) item_ref(item); + item_ref->press(param, true); } } } @@ -787,9 +792,12 @@ background_press(const MouseWatcherParameter ¶m) { */ void PGItem:: background_release(const MouseWatcherParameter ¶m) { - for (PGItem *item : _background_focus) { + auto it = _background_focus.begin(); + while (it != _background_focus.end()) { + PGItem *item = *it++; if (!item->get_focus()) { - item->release(param, true); + PT(PGItem) item_ref(item); + item_ref->release(param, true); } } } @@ -799,9 +807,12 @@ background_release(const MouseWatcherParameter ¶m) { */ void PGItem:: background_keystroke(const MouseWatcherParameter ¶m) { - for (PGItem *item : _background_focus) { + auto it = _background_focus.begin(); + while (it != _background_focus.end()) { + PGItem *item = *it++; if (!item->get_focus()) { - item->keystroke(param, true); + PT(PGItem) item_ref(item); + item_ref->keystroke(param, true); } } } @@ -811,9 +822,12 @@ background_keystroke(const MouseWatcherParameter ¶m) { */ void PGItem:: background_candidate(const MouseWatcherParameter ¶m) { - for (PGItem *item : _background_focus) { + auto it = _background_focus.begin(); + while (it != _background_focus.end()) { + PGItem *item = *it++; if (!item->get_focus()) { - item->candidate(param, true); + PT(PGItem) item_ref(item); + item_ref->candidate(param, true); } } } diff --git a/panda/src/pipeline/cycleDataLockedStageReader.I b/panda/src/pipeline/cycleDataLockedStageReader.I index 6cee154bb71..4fef7c86948 100644 --- a/panda/src/pipeline/cycleDataLockedStageReader.I +++ b/panda/src/pipeline/cycleDataLockedStageReader.I @@ -184,7 +184,7 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader © template INLINE CycleDataLockedStageReader:: CycleDataLockedStageReader(CycleDataLockedStageReader &&from) noexcept : - _pointer(from._cycler) + _pointer(from._pointer) { from._pointer = nullptr; } diff --git a/panda/src/pipeline/threadPosixImpl.I b/panda/src/pipeline/threadPosixImpl.I index 308dc3ede02..326868ab61e 100644 --- a/panda/src/pipeline/threadPosixImpl.I +++ b/panda/src/pipeline/threadPosixImpl.I @@ -19,7 +19,7 @@ ThreadPosixImpl(Thread *parent_obj) : _parent_obj(parent_obj) { _joinable = false; - _detached = false; + _detached = true; _status = S_new; #ifdef ANDROID _jni_env = nullptr; diff --git a/panda/src/pipeline/threadWin32Impl.I b/panda/src/pipeline/threadWin32Impl.I index ca236b78f07..809da144180 100644 --- a/panda/src/pipeline/threadWin32Impl.I +++ b/panda/src/pipeline/threadWin32Impl.I @@ -63,14 +63,6 @@ is_simple_threads() { return false; } -/** - * - */ -INLINE void ThreadWin32Impl:: -sleep(double seconds) { - Sleep((int)(seconds * 1000)); -} - /** * */ diff --git a/panda/src/pipeline/threadWin32Impl.cxx b/panda/src/pipeline/threadWin32Impl.cxx index c8653a4f5c9..e8a10b78d58 100644 --- a/panda/src/pipeline/threadWin32Impl.cxx +++ b/panda/src/pipeline/threadWin32Impl.cxx @@ -25,6 +25,10 @@ static thread_local Thread *_current_thread = nullptr; static patomic_flag _main_thread_known = ATOMIC_FLAG_INIT; +#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION +#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 +#endif + #if _WIN32_WINNT < 0x0601 // Requires Windows 7. static DWORD (__stdcall *EnableThreadProfiling)(HANDLE, DWORD, DWORD64, HANDLE *) = nullptr; @@ -78,6 +82,11 @@ ThreadWin32Impl:: } CloseHandle(_thread); + + if (_timer != nullptr) { + CloseHandle(_timer); + _timer = nullptr; + } } /** @@ -200,6 +209,27 @@ bind_thread(Thread *thread) { return thread; } + +/** + * + */ +void ThreadWin32Impl:: +sleep(double seconds) { + Thread *thread = get_current_thread(); + ThreadWin32Impl *self = &thread->_impl; + + HANDLE timer = self->_timer; + if (timer == nullptr) { + timer = CreateWaitableTimerExW(nullptr, nullptr, CREATE_WAITABLE_TIMER_MANUAL_RESET | CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); + self->_timer = timer; + } + + LARGE_INTEGER ft; + ft.QuadPart = seconds * -10000000LL; + SetWaitableTimer(timer, &ft, 0, nullptr, nullptr, 0); + WaitForSingleObject(timer, INFINITE); +} + /** * Returns the number of context switches that occurred on the current thread. * The first number is the total number of context switches reported by the OS, diff --git a/panda/src/pipeline/threadWin32Impl.h b/panda/src/pipeline/threadWin32Impl.h index 1d62320789d..a5528e55883 100644 --- a/panda/src/pipeline/threadWin32Impl.h +++ b/panda/src/pipeline/threadWin32Impl.h @@ -48,7 +48,7 @@ class EXPCL_PANDA_PIPELINE ThreadWin32Impl { INLINE static bool is_threading_supported(); INLINE static bool is_true_threads(); INLINE static bool is_simple_threads(); - INLINE static void sleep(double seconds); + static void sleep(double seconds); INLINE static void yield(); INLINE static void consider_yield(); @@ -72,6 +72,7 @@ class EXPCL_PANDA_PIPELINE ThreadWin32Impl { bool _joinable; Status _status; HANDLE _profiling; + HANDLE _timer = nullptr; }; #include "threadWin32Impl.I" diff --git a/panda/src/pstatclient/pStatClientImpl.cxx b/panda/src/pstatclient/pStatClientImpl.cxx index ed8a8d0e82c..f6db443b553 100644 --- a/panda/src/pstatclient/pStatClientImpl.cxx +++ b/panda/src/pstatclient/pStatClientImpl.cxx @@ -155,10 +155,9 @@ client_connect(std::string hostname, int port) { int thread_index = current_thread->get_pstats_index(); if (thread_index >= 0) { PStatClient *client = PStatClient::get_global_pstats(); - double start = client->get_real_time(); + client->start(_wait_sleep_pcollector.get_index(), thread_index); ThreadImpl::sleep(seconds); - double stop = client->get_real_time(); - client->start_stop(_wait_sleep_pcollector.get_index(), thread_index, start, stop); + client->stop(_wait_sleep_pcollector.get_index(), thread_index); client->add_level(_cswitch_sleep_pcollector.get_index(), thread_index, 1); } else { @@ -171,10 +170,9 @@ client_connect(std::string hostname, int port) { int thread_index = current_thread->get_pstats_index(); if (thread_index >= 0) { PStatClient *client = PStatClient::get_global_pstats(); - double start = client->get_real_time(); + client->start(_wait_yield_pcollector.get_index(), thread_index); ThreadImpl::yield(); - double stop = client->get_real_time(); - client->start_stop(_wait_yield_pcollector.get_index(), thread_index, start, stop); + client->stop(_wait_yield_pcollector.get_index(), thread_index); client->add_level(_cswitch_yield_pcollector.get_index(), thread_index, 1); } else { @@ -190,10 +188,9 @@ client_connect(std::string hostname, int port) { BOOL result; if (thread_index >= 0) { PStatClient *client = PStatClient::get_global_pstats(); - double start = client->get_real_time(); + client->start(_wait_cvar_pcollector.get_index(), thread_index); result = SleepConditionVariableSRW(cvar, lock, time, flags); - double stop = client->get_real_time(); - client->start_stop(_wait_cvar_pcollector.get_index(), thread_index, start, stop); + client->stop(_wait_cvar_pcollector.get_index(), thread_index); client->add_level(_cswitch_cvar_pcollector.get_index(), thread_index, 1); } else { @@ -211,10 +208,9 @@ client_connect(std::string hostname, int port) { int result; if (thread_index >= 0) { PStatClient *client = PStatClient::get_global_pstats(); - double start = client->get_real_time(); + client->start(_wait_cvar_pcollector.get_index(), thread_index); result = pthread_cond_wait(cvar, lock); - double stop = client->get_real_time(); - client->start_stop(_wait_cvar_pcollector.get_index(), thread_index, start, stop); + client->stop(_wait_cvar_pcollector.get_index(), thread_index); client->add_level(_cswitch_cvar_pcollector.get_index(), thread_index, 1); } else { @@ -231,10 +227,9 @@ client_connect(std::string hostname, int port) { int result; if (thread_index >= 0) { PStatClient *client = PStatClient::get_global_pstats(); - double start = client->get_real_time(); + client->start(_wait_cvar_pcollector.get_index(), thread_index); result = pthread_cond_timedwait(cvar, lock, ts); - double stop = client->get_real_time(); - client->start_stop(_wait_cvar_pcollector.get_index(), thread_index, start, stop); + client->stop(_wait_cvar_pcollector.get_index(), thread_index); client->add_level(_cswitch_cvar_pcollector.get_index(), thread_index, 1); } else { diff --git a/panda/src/pstatclient/pStatClient_ext.cxx b/panda/src/pstatclient/pStatClient_ext.cxx index 0724470cfbe..f786b07dcda 100644 --- a/panda/src/pstatclient/pStatClient_ext.cxx +++ b/panda/src/pstatclient/pStatClient_ext.cxx @@ -72,11 +72,21 @@ __declspec(noinline) make_python_frame_collector(PyFrameObject *frame, PyCodeObject *code) { #if PY_VERSION_HEX >= 0x030B0000 // 3.11 // Fetch the module name out of the frame's global scope. + const char *mod_name = ""; + PyObject *py_mod_name = nullptr; PyObject *globals = PyFrame_GetGlobals(frame); - PyObject *py_mod_name = PyDict_GetItemString(globals, "__name__"); +#if PY_VERSION_HEX >= 0x030D00A1 // 3.13 + if (PyDict_GetItemStringRef(globals, "__name__", &py_mod_name) > 0) { + mod_name = PyUnicode_AsUTF8(py_mod_name); + } +#else + py_mod_name = PyDict_GetItemString(globals, "__name__"); + if (py_mod_name != nullptr) { + mod_name = PyUnicode_AsUTF8(py_mod_name); + } +#endif Py_DECREF(globals); - const char *mod_name = py_mod_name ? PyUnicode_AsUTF8(py_mod_name) : ""; const char *meth_name = PyUnicode_AsUTF8(code->co_qualname); char buffer[1024]; size_t len = snprintf(buffer, sizeof(buffer), "%s:%s", mod_name, meth_name); @@ -85,6 +95,11 @@ make_python_frame_collector(PyFrameObject *frame, PyCodeObject *code) { buffer[i] = ':'; } } + +#if PY_VERSION_HEX >= 0x030D00A1 // 3.13 + Py_XDECREF(py_mod_name); +#endif + #else // Try to figure out the type name. There's no obvious way to do this. // It's possible that the first argument passed to this function is the @@ -179,23 +194,26 @@ make_c_function_collector(PyCFunctionObject *meth) { len = (dot - cls->tp_name) + 1; } else { // If there's no module name, we need to get it from __module__. - PyObject *py_mod_name = cls->tp_dict ? PyDict_GetItemString(cls->tp_dict, "__module__") : nullptr; + PyObject *py_mod_name = nullptr; const char *mod_name = nullptr; - if (py_mod_name != nullptr) { + if (cls->tp_dict != nullptr && + PyDict_GetItemStringRef(cls->tp_dict, "__module__", &py_mod_name) > 0) { if (PyUnicode_Check(py_mod_name)) { mod_name = PyUnicode_AsUTF8(py_mod_name); } else { // Might be a descriptor. + Py_DECREF(py_mod_name); py_mod_name = PyObject_GetAttrString(meth->m_self, "__module__"); if (py_mod_name != nullptr) { if (PyUnicode_Check(py_mod_name)) { mod_name = PyUnicode_AsUTF8(py_mod_name); } - Py_DECREF(py_mod_name); } else PyErr_Clear(); } } + else PyErr_Clear(); + if (mod_name == nullptr) { // Is it a built-in, like int or dict? PyObject *builtins = PyEval_GetBuiltins(); @@ -206,6 +224,7 @@ make_c_function_collector(PyCFunctionObject *meth) { } } len = snprintf(buffer, sizeof(buffer), "%s:%s:%s()", mod_name, cls->tp_name, meth->m_ml->ml_name) - 2; + Py_XDECREF(py_mod_name); } } else if (meth->m_self != nullptr) { diff --git a/panda/src/putil/CMakeLists.txt b/panda/src/putil/CMakeLists.txt index ecc14b9843c..c99dfac3837 100644 --- a/panda/src/putil/CMakeLists.txt +++ b/panda/src/putil/CMakeLists.txt @@ -20,6 +20,9 @@ set(P3PUTIL_HEADERS clockObject.h clockObject.I collideMask.h colorSpace.h + completable.I completable.h + completionCounter.I completionCounter.h + completionToken.I completionToken.h copyOnWriteObject.h copyOnWriteObject.I copyOnWritePointer.h copyOnWritePointer.I compareTo.I compareTo.h @@ -86,6 +89,7 @@ set(P3PUTIL_SOURCES callbackObject.cxx clockObject.cxx colorSpace.cxx + completionCounter.cxx copyOnWriteObject.cxx copyOnWritePointer.cxx config_putil.cxx configurable.cxx diff --git a/panda/src/putil/animInterface.I b/panda/src/putil/animInterface.I index 3d09f34a007..17f84946548 100644 --- a/panda/src/putil/animInterface.I +++ b/panda/src/putil/animInterface.I @@ -231,6 +231,16 @@ is_playing() const { return cdata->is_playing(); } +/** + * Returns the current play mode of the animation; whether the animation is + * playing normally, looping, posing, or in ping-pong mode. + */ +INLINE AnimInterface::PlayMode AnimInterface:: +get_play_mode() const { + CDReader cdata(_cycler); + return cdata->get_play_mode(); +} + /** * Should be called by a derived class to specify the native frame rate of the * animation. It is legal to call this after the animation has already @@ -266,6 +276,11 @@ get_frac() const { return get_full_fframe() - (double)get_full_frame(0); } +INLINE AnimInterface::PlayMode AnimInterface::CData:: +get_play_mode() const { + return _play_mode; +} + INLINE std::ostream & operator << (std::ostream &out, const AnimInterface &ai) { ai.output(out); diff --git a/panda/src/putil/animInterface.h b/panda/src/putil/animInterface.h index 80f2a3da9d5..5e29ed31401 100644 --- a/panda/src/putil/animInterface.h +++ b/panda/src/putil/animInterface.h @@ -38,6 +38,13 @@ class EXPCL_PANDA_PUTIL AnimInterface { AnimInterface(const AnimInterface ©); PUBLISHED: + enum PlayMode { + PM_pose, + PM_play, + PM_loop, + PM_pingpong, + }; + virtual ~AnimInterface(); INLINE void play(); INLINE void play(double from, double to); @@ -59,6 +66,7 @@ class EXPCL_PANDA_PUTIL AnimInterface { INLINE int get_full_frame() const; INLINE double get_full_fframe() const; INLINE bool is_playing() const; + INLINE PlayMode get_play_mode() const; virtual void output(std::ostream &out) const; @@ -73,6 +81,7 @@ class EXPCL_PANDA_PUTIL AnimInterface { MAKE_PROPERTY(full_frame, get_full_frame); MAKE_PROPERTY(full_fframe, get_full_fframe); MAKE_PROPERTY(playing, is_playing); + MAKE_PROPERTY(play_mode, get_play_mode); protected: INLINE void set_frame_rate(double frame_rate); @@ -80,13 +89,6 @@ class EXPCL_PANDA_PUTIL AnimInterface { virtual void animation_activated(); private: - enum PlayMode { - PM_pose, - PM_play, - PM_loop, - PM_pingpong, - }; - // This data is not cycled, because it is a semi-permanent part of the // interface. Also, some derivatives of AnimInterface don't even use it. int _num_frames; @@ -112,6 +114,7 @@ class EXPCL_PANDA_PUTIL AnimInterface { int get_full_frame(int increment) const; double get_full_fframe() const; bool is_playing() const; + INLINE PlayMode get_play_mode() const; virtual void output(std::ostream &out) const; diff --git a/panda/src/putil/bamReader_ext.cxx b/panda/src/putil/bamReader_ext.cxx index 308028cea3c..84c5060e1e3 100644 --- a/panda/src/putil/bamReader_ext.cxx +++ b/panda/src/putil/bamReader_ext.cxx @@ -85,7 +85,7 @@ static TypedWritable *factory_callback(const FactoryParams ¶ms){ Py_DECREF(result); } else if (DtoolInstance_TYPE(result) == &Dtool_TypedWritable && - Py_TYPE(result) != &Dtool_TypedWritable._PyType) { + !Py_IS_TYPE(result, Dtool_GetPyTypeObject(&Dtool_TypedWritable))) { // It is a custom subclass of TypedWritable, so we have to keep it // alive, and decrement it in finalize(), see typedWritable_ext.cxx. manager->register_finalize(ptr); diff --git a/panda/src/putil/bamWriter.I b/panda/src/putil/bamWriter.I index ad8b119edf4..b9e36d421f5 100644 --- a/panda/src/putil/bamWriter.I +++ b/panda/src/putil/bamWriter.I @@ -96,6 +96,9 @@ get_file_texture_mode() const { * Changes the BamTextureMode preference for the Bam file currently being * written. Texture objects written to this Bam file will be encoded * according to the specified mode. + * + * This should be called after the call to init(), or it will be overwritten + * with the default mode in the config file. */ INLINE void BamWriter:: set_file_texture_mode(BamTextureMode file_texture_mode) { diff --git a/panda/src/putil/bamWriter.h b/panda/src/putil/bamWriter.h index be07d80411b..63328de1776 100644 --- a/panda/src/putil/bamWriter.h +++ b/panda/src/putil/bamWriter.h @@ -96,7 +96,7 @@ class EXPCL_PANDA_PUTIL BamWriter : public BamEnums { MAKE_PROPERTY(file_version, get_file_version); MAKE_PROPERTY(file_endian, get_file_endian); MAKE_PROPERTY(file_stdfloat_double, get_file_stdfloat_double); - MAKE_PROPERTY(file_texture_mode, get_file_texture_mode); + MAKE_PROPERTY(file_texture_mode, get_file_texture_mode, set_file_texture_mode); MAKE_PROPERTY(root_node, get_root_node, set_root_node); public: @@ -135,7 +135,7 @@ class EXPCL_PANDA_PUTIL BamWriter : public BamEnums { // Stores the PandaNode representing the root of the node hierarchy we are // currently writing, if any, for the purpose of writing NodePaths. This is // a TypedWritable since PandaNode is defined in pgraph. - TypedWritable *_root_node; + TypedWritable *_root_node = nullptr; // This is the set of all TypeHandles already written. pset _types_written; diff --git a/panda/src/putil/bitArray_ext.cxx b/panda/src/putil/bitArray_ext.cxx index 2a489510407..b454593d1b4 100644 --- a/panda/src/putil/bitArray_ext.cxx +++ b/panda/src/putil/bitArray_ext.cxx @@ -32,7 +32,11 @@ __init__(PyObject *init_value) { _PyLong_AsByteArray((PyLongObject *)init_value, (unsigned char *)&_this->_array[0], num_words * sizeof(BitArray::WordType), - 1, 0); + 1, 0 +#if PY_VERSION_HEX >= 0x030d0000 + , 1 // with_exceptions +#endif + ); } } diff --git a/panda/src/putil/clockObject.cxx b/panda/src/putil/clockObject.cxx index 8fa128616fe..1add57a6e14 100644 --- a/panda/src/putil/clockObject.cxx +++ b/panda/src/putil/clockObject.cxx @@ -499,6 +499,8 @@ wait_until(double want_time) { double wait_interval = (want_time - _actual_frame_time) - sleep_precision; + double now = get_real_time(); + if (wait_interval > 0.0) { Thread::sleep(wait_interval); } @@ -507,6 +509,20 @@ wait_until(double want_time) { (*_start_clock_busy_wait)(); #endif + _actual_frame_time = get_real_time(); + if (_actual_frame_time > want_time) { + if (util_cat.is_debug()) { + util_cat.debug() + << "Overslept by " << (int)((_actual_frame_time - want_time) * 1000000) + << " us while waiting for next frame, consider raising sleep-precision.\n"; + } + } + else if (util_cat.is_spam()) { + util_cat.spam() + << "Busy waiting for " << (int)((want_time - _actual_frame_time) * 1000000) + << " us.\n"; + } + // Now busy-wait until the actual time elapses. while (_actual_frame_time < want_time) { _actual_frame_time = get_real_time(); diff --git a/panda/src/putil/completable.I b/panda/src/putil/completable.I new file mode 100644 index 00000000000..96d140be33c --- /dev/null +++ b/panda/src/putil/completable.I @@ -0,0 +1,75 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file completable.I + * @author rdb + * @date 2025-01-22 + */ + +#ifndef CPPPARSER +/** + * + */ +template +INLINE Completable:: +Completable(Callable callback) : + _data(new LambdaData(std::move(callback), [](Data *data, bool do_run) { + LambdaData *self = (LambdaData *)data; + if (do_run) { + std::move(self->_lambda)(); + } + delete self; + })) { +} +#endif + +/** + * + */ +INLINE Completable:: +Completable(Completable &&from) noexcept : + _data(from._data) { + from._data = nullptr; +} + +/** + * + */ +INLINE Completable &Completable:: +operator =(Completable &&from) { + Data *data = _data; + _data = from._data; + from._data = nullptr; + if (data != nullptr) { + data->_function.load(std::memory_order_relaxed)(data, false); + } + return *this; +} + +/** + * + */ +INLINE Completable:: +~Completable() { + Data *data = _data; + if (data != nullptr) { + data->_function.load(std::memory_order_relaxed)(data, false); + } +} + +/** + * + */ +INLINE void Completable:: +operator ()() { + Data *data = _data; + _data = nullptr; + if (data != nullptr) { + data->_function.load(std::memory_order_relaxed)(data, true); + } +} diff --git a/panda/src/putil/completable.h b/panda/src/putil/completable.h new file mode 100644 index 00000000000..9b0f6fdd129 --- /dev/null +++ b/panda/src/putil/completable.h @@ -0,0 +1,82 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file completable.h + * @author rdb + * @date 2025-01-22 + */ + +#ifndef COMPLETABLE_H +#define COMPLETABLE_H + +#include "pandabase.h" +#include "patomic.h" + +/** + * Stores a type-erased callable that is move-only. May only be called once. + */ +class EXPCL_PANDA_PUTIL Completable { +public: + constexpr Completable() = default; + +#ifndef CPPPARSER + template + INLINE Completable(Callable callback); +#endif + + INLINE Completable(const Completable ©) = delete; + INLINE Completable(Completable &&from) noexcept; + + INLINE Completable &operator =(const Completable ©) = delete; + INLINE Completable &operator =(Completable &&from); + + INLINE void operator ()(); + + INLINE ~Completable(); + +protected: + // There are several design approaches here: + // 1. Optimize for no data block: do not require dynamic allocation of a data + // block in the simple case where the callback data is only the size of a + // single pointer. Store two pointers, one function pointer and a data + // pointer(-sized storage), directly on the class here. + // 2. Optimize for a data block: store the function pointer on the data block, + // always requiring dynamic allocation. + // + // Right now I have opted for 2 because it allows the function pointer to be + // dynamically swapped (used in CompletionCounter), but this decision may + // change in the future. + + struct Data; + typedef void CallbackFunction(Data *, bool); + + struct Data { + patomic _function { nullptr }; + }; + + template + struct LambdaData : public Data { + // Must unfortunately be defined inline, since this struct is protected. + LambdaData(Lambda lambda, CallbackFunction *function) : + _lambda(std::move(lambda)) { + _function = function; + } + + Lambda _lambda; + }; + + Data *_data = nullptr; + + friend class AsyncFuture; + friend class CompletionCounter; + friend class CompletionToken; +}; + +#include "completable.I" + +#endif diff --git a/panda/src/putil/completionCounter.I b/panda/src/putil/completionCounter.I new file mode 100644 index 00000000000..6d591433607 --- /dev/null +++ b/panda/src/putil/completionCounter.I @@ -0,0 +1,97 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file completionCounter.I + * @author rdb + * @date 2025-01-22 + */ + +/** + * + */ +INLINE CompletionCounter:: +~CompletionCounter() { + CounterData *data = _data; + if (data != nullptr) { + // then() is not called; we still need something that destructs the data + // when done. + auto prev_function = data->_function.exchange(&abandon_callback, std::memory_order_relaxed); + if (prev_function == nullptr) { + // Was already done. + delete data; + } + } +} + +/** + * Returns a new token. May not be called after then(). + */ +INLINE CompletionToken CompletionCounter:: +make_token() { + CompletionToken token; + if (_data == nullptr) { + _data = new CounterData; + _data->_function = &initial_callback; + } + auto old_value = _data->_counter.fetch_add(1); + nassertr(old_value >= 0, token); + token._callback._data = _data; + return token; +} + +/** + * Runs the given callback immediately upon completion. If the counter is + * already done, runs it immediately. This requires an rvalue because it + * consumes the counter, use std::move() if you don't have an rvalue. + * + * The callback will either be called immediately or directly when the last + * token calls complete(), however, it may also be called if a token is + * destroyed. This may happen at unexpected times, such as when the lambda + * holding the token is destroyed prematurely. In this case, however, the + * passed success argument will always be false. + */ +template +INLINE void CompletionCounter:: +then(Callable callable) && { + // Replace the callback pointer with something that calls the given callable + // once the count reaches 0. + CounterData *data = _data; + nassertv(data != nullptr); + _data = nullptr; + if (data->_function.load(std::memory_order_acquire) == nullptr) { + // Already done. + callable((data->_counter.load(std::memory_order_relaxed) & ~0xffff) == 0); + delete data; + return; + } + + static_assert(sizeof(Callable) <= sizeof(data->_storage), + "raise storage size in completionCounter.h or reduce lambda captures"); + + new (data->_storage) Callable(std::move(callable)); + + Completable::CallbackFunction *new_function = + [] (Completable::Data *data_ptr, bool success) { + CounterData *data = (CounterData *)data_ptr; + auto prev_count = data->_counter.fetch_add((success ? 0 : 0x10000) - 1, std::memory_order_release); + if ((short)(prev_count & 0xffff) > 1) { + return; + } + + Callable *callable = (Callable *)data->_storage; + std::move(*callable)(success && (prev_count & ~0xffff) == 0); + callable->~Callable(); + delete data; + }; + + auto prev_function = data->_function.exchange(new_function, std::memory_order_acq_rel); + if (UNLIKELY(prev_function == nullptr)) { + // Last token finished in the meantime. + new_function(data, (data->_counter.load(std::memory_order_relaxed) & ~0xffff) == 0); + } +} diff --git a/panda/src/putil/completionCounter.cxx b/panda/src/putil/completionCounter.cxx new file mode 100644 index 00000000000..2540867e61f --- /dev/null +++ b/panda/src/putil/completionCounter.cxx @@ -0,0 +1,52 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file completionCounter.cxx + * @author rdb + * @date 2025-01-24 + */ + +#include "completionCounter.h" + +/** + * Called when a token is completed before then() is called. + */ +void CompletionCounter:: +initial_callback(Completable::Data *data_ptr, bool success) { + CounterData &data = *(CounterData *)data_ptr; + auto prev_count = data._counter.fetch_add((success ? 0 : 0x10000) - 1, std::memory_order_release); + if ((prev_count & 0xffff) == 1) { + // We're done early. + auto prev_callback = data._function.exchange(nullptr, std::memory_order_acq_rel); + nassertv(prev_callback != nullptr); + + // Someone called then() in the meantime. Call the new callback. The + // refcount will drop below 0 when that's called but they are designed to + // handle that. + if (prev_callback != &initial_callback) { + prev_callback(data_ptr, success && (prev_count & ~0xffff) == 0); + } + } +} + +/** + * Called when a token is completed after this object is destroyed without + * then() being called. + */ +void CompletionCounter:: +abandon_callback(Completable::Data *data_ptr, bool success) { + CounterData &data = *(CounterData *)data_ptr; + auto prev_count = data._counter.fetch_sub(1, std::memory_order_relaxed); + if ((prev_count & 0xffff) <= 1) { + // Done. + auto prev_callback = data._function.exchange(nullptr, std::memory_order_relaxed); + nassertv(prev_callback != nullptr); + nassertv(prev_callback == &abandon_callback); + delete &data; + } +} diff --git a/panda/src/putil/completionCounter.h b/panda/src/putil/completionCounter.h new file mode 100644 index 00000000000..dbb0e2dcfb4 --- /dev/null +++ b/panda/src/putil/completionCounter.h @@ -0,0 +1,58 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file completionCounter.h + * @author rdb + * @date 2025-01-22 + */ + +#ifndef COMPLETIONCOUNTER_H +#define COMPLETIONCOUNTER_H + +#include "pandabase.h" +#include "completionToken.h" + +#include + +/** + * Shared counter that generates "completion tokens" incrementing a counter, + * which will decrement the counter once they are finished. After the tokens + * are handed out, a callback may be registered using then(), which will be + * called as soon as the last token is done. + */ +class EXPCL_PANDA_PUTIL CompletionCounter { +public: + constexpr CompletionCounter() = default; + CompletionCounter(const CompletionCounter ©) = delete; + + INLINE ~CompletionCounter(); + + INLINE CompletionToken make_token(); + + template + INLINE void then(Callable callable) &&; + +private: + static void initial_callback(Completable::Data *data, bool success); + static void abandon_callback(Completable::Data *data, bool success); + +protected: + struct CounterData : public Completable::Data { + // Least significant half is counter, most significant half is error count + patomic_signed_lock_free _counter { 0 }; + + // Just raise this if the static_assert fires (or limit the size of your + // lambda captures). + alignas(std::max_align_t) unsigned char _storage[64]; + }; + CounterData *_data = nullptr; +}; + +#include "completionCounter.I" + +#endif diff --git a/panda/src/putil/completionToken.I b/panda/src/putil/completionToken.I new file mode 100644 index 00000000000..aef06a7d4eb --- /dev/null +++ b/panda/src/putil/completionToken.I @@ -0,0 +1,42 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file completionToken.I + * @author rdb + * @date 2025-01-22 + */ + +#ifndef CPPPARSER +/** + * Creates a token that calls the given callback when it's done, passing it + * true on success and false on failure or abandonment. + */ +template +INLINE CompletionToken:: +CompletionToken(Callable callback) { + // Main difference over a Completable is that this will always call the + // callback, even on failure, so that cleanup can be done. + _callback._data = new Completable::LambdaData(std::move(callback), [](Completable::Data *data, bool success) { + Completable::LambdaData *self = (Completable::LambdaData *)data; + std::move(self->_lambda)(success); + delete self; + }); +} +#endif + +/** + * + */ +INLINE void CompletionToken:: +complete(bool success) { + Completable::Data *data = _callback._data; + if (data != nullptr) { + _callback._data = nullptr; + data->_function.load(std::memory_order_relaxed)(data, success); + } +} diff --git a/panda/src/putil/completionToken.h b/panda/src/putil/completionToken.h new file mode 100644 index 00000000000..b73f4fe376b --- /dev/null +++ b/panda/src/putil/completionToken.h @@ -0,0 +1,56 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file completionToken.h + * @author rdb + * @date 2025-01-22 + */ + +#ifndef COMPLETIONTOKEN_H +#define COMPLETIONTOKEN_H + +#include "pandabase.h" +#include "pnotify.h" +#include "completable.h" + +/** + * A completion token can be created from a callback, future or + * CompletionCounter and can be passed into an asynchronous operation in order + * to receive a signal when it is done. + * + * The asynchronous operation should call complete() on it when it is done, + * with a boolean value indicating success or failure. If the token is + * destroyed prematurely, it is treated as if it called complete(false). + * + * This should be preferred over passing an AsyncFuture into a method since + * a CompletionToken provides both more flexibility in use (due to accepting + * an arbitrary callback) and more safety (since the RAII semantics guarantees + * that the callback is never silently dropped). + * + * The token may only be moved, not copied. + */ +class EXPCL_PANDA_PUTIL CompletionToken { +public: + constexpr CompletionToken() = default; + +#ifndef CPPPARSER + template + INLINE CompletionToken(Callable callback); +#endif + + void complete(bool success); + +protected: + Completable _callback; + + friend class CompletionCounter; +}; + +#include "completionToken.I" + +#endif diff --git a/panda/src/putil/config_putil.cxx b/panda/src/putil/config_putil.cxx index 93694b3d305..9849cd5b84f 100644 --- a/panda/src/putil/config_putil.cxx +++ b/panda/src/putil/config_putil.cxx @@ -129,9 +129,9 @@ get_plugin_path() { ConfigVariableDouble sleep_precision ("sleep-precision", 0.01, - PRC_DESC("This is the accuracy within which we can expect select() to " - "return precisely. That is, if we use select() to request a " - "timeout of 1.0 seconds, we can expect to actually sleep for " + PRC_DESC("This is the accuracy within which we can expect the operating " + "system sleep call to return precisely. That is, if we request " + "a timeout of 1.0 seconds, we can expect to actually sleep for " "somewhere between 1.0 and 1.0 + sleep-precision seconds.")); ConfigVariableBool preload_textures diff --git a/panda/src/putil/doubleBitMask_ext.I b/panda/src/putil/doubleBitMask_ext.I index a40b91355d5..1674cccd49c 100644 --- a/panda/src/putil/doubleBitMask_ext.I +++ b/panda/src/putil/doubleBitMask_ext.I @@ -31,7 +31,11 @@ __init__(PyObject *init_value) { if (n > 0) { size_t num_bytes = (n + 7) / 8; unsigned char *bytes = (unsigned char *)alloca(num_bytes); - _PyLong_AsByteArray((PyLongObject *)init_value, bytes, num_bytes, 1, 0); + _PyLong_AsByteArray((PyLongObject *)init_value, bytes, num_bytes, 1, 0 +#if PY_VERSION_HEX >= 0x030d0000 + , 1 // with_exceptions +#endif + ); for (size_t i = 0; i < num_bytes; ++i) { this->_this->store(bytes[i], i * 8, 8); @@ -58,7 +62,13 @@ __int__() const { if (!this->_this->_hi.is_zero()) { PyObject *lo = result; PyObject *hi = invoke_extension(&this->_this->_hi).__int__(); +#if PY_VERSION_HEX >= 0x030d0000 + PyObject *half_bits = PyLong_FromUnsignedLong(DoubleBitMask::half_bits); + PyObject *shifted = PyNumber_Lshift(hi, half_bits); + Py_DECREF(half_bits); +#else PyObject *shifted = _PyLong_Lshift(hi, DoubleBitMask::half_bits); +#endif Py_DECREF(hi); result = PyNumber_Or(shifted, lo); Py_DECREF(shifted); diff --git a/panda/src/putil/p3putil_composite1.cxx b/panda/src/putil/p3putil_composite1.cxx index f78459eff71..c464d7708c9 100644 --- a/panda/src/putil/p3putil_composite1.cxx +++ b/panda/src/putil/p3putil_composite1.cxx @@ -17,6 +17,7 @@ #include "callbackObject.cxx" #include "clockObject.cxx" #include "colorSpace.cxx" +#include "completionCounter.cxx" #include "config_putil.cxx" #include "configurable.cxx" #include "copyOnWriteObject.cxx" diff --git a/panda/src/putil/pythonCallbackObject.cxx b/panda/src/putil/pythonCallbackObject.cxx index 454c9bdaf5c..bd70b136416 100644 --- a/panda/src/putil/pythonCallbackObject.cxx +++ b/panda/src/putil/pythonCallbackObject.cxx @@ -87,7 +87,7 @@ get_function() { */ PyObject *PythonCallbackObject:: __reduce__() const { - return Py_BuildValue("O(O)", (PyObject *)&Dtool_PythonCallbackObject._PyType, _function); + return Py_BuildValue("O(O)", (PyObject *)Dtool_GetPyTypeObject(&Dtool_PythonCallbackObject), _function); } /** diff --git a/panda/src/putil/simpleHashMap.I b/panda/src/putil/simpleHashMap.I index 6c61aaeea7d..b6641205c58 100644 --- a/panda/src/putil/simpleHashMap.I +++ b/panda/src/putil/simpleHashMap.I @@ -292,8 +292,8 @@ remove(const Key &key) { // Now remove this element. size_t last = _num_entries - 1; - size_t index = (size_t)index_array[slot]; - if (index < _num_entries) { + int index = index_array[slot]; + if ((size_t)index < _num_entries) { // Find the last element in the index array. int other_slot = find_slot(_table[last]._key); nassertr(other_slot != -1, false); @@ -301,7 +301,7 @@ remove(const Key &key) { // Swap it with the last one, so that we don't get any gaps in the table // of entries. - _table[index] = std::move(_table[last]); + _table[(size_t)index] = std::move(_table[last]); index_array[(size_t)other_slot] = index; } @@ -321,13 +321,13 @@ remove(const Key &key) { // Now we have put a hole in the index array. If there was a hash conflict // in the slot after this one, we have to move it down to close the hole. slot = next_hash(slot); - while (has_slot(slot)) { - size_t index = (size_t)index_array[slot]; + index = index_array[slot]; + while (index >= 0) { size_t wants_slot = get_hash(_table[index]._key); if (wants_slot != slot) { // This one was a hash conflict; try to put it where it belongs. We // can't just put it in n, since maybe it belongs somewhere after n. - while (wants_slot != slot && has_slot(wants_slot)) { + while (wants_slot != slot && index_array[wants_slot] >= 0) { wants_slot = next_hash(wants_slot); } if (wants_slot != slot) { @@ -341,6 +341,7 @@ remove(const Key &key) { // Continue until we encounter the next unused slot. Until we do, we // can't be sure we've found all of the potential hash conflicts. slot = next_hash(slot); + index = index_array[slot]; } #ifdef _DEBUG diff --git a/panda/src/putil/sparseArray.cxx b/panda/src/putil/sparseArray.cxx index 450cc5a6b31..fdad9246a1e 100644 --- a/panda/src/putil/sparseArray.cxx +++ b/panda/src/putil/sparseArray.cxx @@ -89,12 +89,16 @@ get_num_off_bits() const { /** * Returns the index of the lowest 1 bit in the array. Returns -1 if there - * are no 1 bits or if there are an infinite number of 1 bits. + * are no 1 bits and 0 if there are an infinite number of 1 bits. */ int SparseArray:: get_lowest_on_bit() const { if (_inverse) { - return -1; + if (_subranges.empty() || _subranges[0]._begin > 0) { + return 0; + } else { + return _subranges[0]._end; + } } if (_subranges.empty()) { @@ -111,7 +115,11 @@ get_lowest_on_bit() const { int SparseArray:: get_lowest_off_bit() const { if (!_inverse) { - return -1; + if (_subranges.empty() || _subranges[0]._begin > 0) { + return 0; + } else { + return _subranges[0]._end; + } } if (_subranges.empty()) { diff --git a/panda/src/putil/typedWritable_ext.cxx b/panda/src/putil/typedWritable_ext.cxx index 699794b368a..0a328e228c8 100644 --- a/panda/src/putil/typedWritable_ext.cxx +++ b/panda/src/putil/typedWritable_ext.cxx @@ -134,10 +134,10 @@ wrap_typed_writable(void *from_this, PyTypeObject *from_type) { nassertr(from_type != nullptr, nullptr); TypedWritableProxy *to_this; - if (from_type == &Dtool_TypedWritable._PyType) { + if (from_type == Dtool_GetPyTypeObject(&Dtool_TypedWritable)) { to_this = (TypedWritableProxy *)(TypedWritable *)from_this; } - else if (from_type == (PyTypeObject *)&Dtool_TypedObject._PyType) { + else if (from_type == Dtool_GetPyTypeObject(&Dtool_TypedObject)) { to_this = (TypedWritableProxy *)(TypedObject *)from_this; } else { @@ -336,35 +336,37 @@ find_global_decode(PyObject *this_class, const char *func_name) { // Get the module in which BamWriter is defined. PyObject *module_name = PyObject_GetAttrString((PyObject *)&Dtool_BamWriter, "__module__"); if (module_name != nullptr) { - // borrowed reference - PyObject *sys_modules = PyImport_GetModuleDict(); - if (sys_modules != nullptr) { - // borrowed reference - PyObject *module = PyDict_GetItem(sys_modules, module_name); - if (module != nullptr) { - PyObject *func = PyObject_GetAttrString(module, (char *)func_name); - if (func != nullptr) { - Py_DECREF(module_name); - return func; - } + PyObject *module = PyImport_GetModule(module_name); + Py_DECREF(module_name); + if (module != nullptr) { + PyObject *func = PyObject_GetAttrString(module, (char *)func_name); + Py_DECREF(module); + if (func != nullptr) { + return func; } } - Py_DECREF(module_name); } PyObject *bases = PyObject_GetAttrString(this_class, "__bases__"); if (bases != nullptr) { - if (PySequence_Check(bases)) { - Py_ssize_t size = PySequence_Size(bases); - for (Py_ssize_t i = 0; i < size; ++i) { - PyObject *base = PySequence_GetItem(bases, i); - if (base != nullptr) { - PyObject *func = find_global_decode(base, func_name); - Py_DECREF(base); - if (func != nullptr) { - Py_DECREF(bases); - return func; - } + { + PyObject *tuple = PySequence_Tuple(bases); + Py_DECREF(bases); + if (tuple == nullptr) { + PyErr_Clear(); + return nullptr; + } + bases = tuple; + } + + Py_ssize_t size = PyTuple_GET_SIZE(bases); + for (Py_ssize_t i = 0; i < size; ++i) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + if (base != nullptr) { + PyObject *func = find_global_decode(base, func_name); + if (func != nullptr) { + Py_DECREF(bases); + return func; } } } diff --git a/panda/src/testbed/CMakeLists.txt b/panda/src/testbed/CMakeLists.txt index 3c497f42aca..12bd488136d 100644 --- a/panda/src/testbed/CMakeLists.txt +++ b/panda/src/testbed/CMakeLists.txt @@ -1,6 +1,4 @@ -if(NOT BUILD_PANDATOOL) - # It's safe to say, if the user doesn't want pandatool, they don't want pview - # either. +if(NOT BUILD_TOOLS) return() endif() diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index e656af4b45f..367736e095d 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -164,6 +164,17 @@ event_0(const Event *event, void *) { card_np.set_texture(buffer->get_texture()); } +void +event_R(const Event *event, void *) { + // shift-R(eload): reload all textures + TextureCollection collection = TexturePool::get_global_ptr()->find_all_textures("*"); + for (int i = 0; i < collection.size(); ++i) + { + nout << "Reloading texture " << collection[i]->get_filename() << std::endl; + collection[i]->reload(); + } +} + void usage() { cerr << @@ -513,6 +524,7 @@ main(int argc, char **argv) { framework.define_key("shift-f", "flatten hierarchy", event_F, nullptr); framework.define_key("alt-enter", "toggle between window/fullscreen", event_Enter, nullptr); framework.define_key("2", "split the window", event_2, nullptr); + framework.define_key("shift-r", "reload textures", event_R, nullptr); if (pview_test_hack) { framework.define_key("0", "run quick hacky test", event_0, nullptr); } diff --git a/panda/src/text/dynamicTextFont.cxx b/panda/src/text/dynamicTextFont.cxx index 4d933619b55..53cda9d62a0 100644 --- a/panda/src/text/dynamicTextFont.cxx +++ b/panda/src/text/dynamicTextFont.cxx @@ -566,7 +566,7 @@ make_glyph(int character, FT_Face face, int glyph_index) { if (_render_mode == RM_texture) { // Render the glyph if necessary. if (slot->format != ft_glyph_format_bitmap) { - FT_Render_Glyph(slot, ft_render_mode_normal); + FT_Render_Glyph(slot, _native_antialias ? ft_render_mode_normal : ft_render_mode_mono); } tex_x_size = bitmap.width; diff --git a/panda/src/text/textAssembler.I b/panda/src/text/textAssembler.I index d72d3d99bf5..3d547e1482c 100644 --- a/panda/src/text/textAssembler.I +++ b/panda/src/text/textAssembler.I @@ -168,7 +168,7 @@ get_num_characters() const { * string. If the object at this position is a graphic object instead of a * character, returns 0. */ -INLINE wchar_t TextAssembler:: +INLINE char32_t TextAssembler:: get_character(int n) const { nassertr(n >= 0 && n < (int)_text_string.size(), 0); return _text_string[n]._character; @@ -232,7 +232,7 @@ get_num_cols(int r) const { * the object at this position is a graphic object instead of a character, * returns 0. */ -INLINE wchar_t TextAssembler:: +INLINE char32_t TextAssembler:: get_character(int r, int c) const { nassertr(r >= 0 && r < (int)_text_block.size(), 0); nassertr(c >= 0 && c < (int)_text_block[r]._string.size(), 0); @@ -315,6 +315,18 @@ TextCharacter(wchar_t character, { } +/** + * + */ +INLINE TextAssembler::TextCharacter:: +TextCharacter(char32_t character, + TextAssembler::ComputedProperties *cprops) : + _character(character), + _graphic(nullptr), + _cprops(cprops) +{ +} + /** * */ diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index 64f4a7ec91d..7e18b07d032 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -44,6 +44,10 @@ using std::max; using std::min; using std::wstring; +enum ClusterFlags { + CF_small_caps = 0x200000, +}; + // This is the factor by which CT_small scales the character down. static const PN_stdfloat small_accent_scale = 0.6f; @@ -235,11 +239,16 @@ wstring TextAssembler:: get_plain_wtext() const { wstring wtext; - TextString::const_iterator si; - for (si = _text_string.begin(); si != _text_string.end(); ++si) { - const TextCharacter &tch = (*si); + for (const TextCharacter &tch : _text_string) { if (tch._graphic == nullptr) { - wtext += tch._character; + if (sizeof(wchar_t) >= 4 || (tch._character & ~0xffff) == 0) { + wtext += (wchar_t)tch._character; + } else { + // Use a surrogate pair. + char32_t v = (char32_t)tch._character - 0x10000u; + wtext += (wchar_t)((v >> 10u) | 0xd800u); + wtext += (wchar_t)((v & 0x3ffu) | 0xdc00u); + } } else { wtext.push_back(0); } @@ -269,11 +278,16 @@ get_wordwrapped_plain_wtext() const { wtext += '\n'; } - TextString::const_iterator si; - for (si = row._string.begin(); si != row._string.end(); ++si) { - const TextCharacter &tch = (*si); + for (const TextCharacter &tch : row._string) { if (tch._graphic == nullptr) { - wtext += tch._character; + if (sizeof(wchar_t) >= 4 || (tch._character & ~0xffff) == 0) { + wtext += (wchar_t)tch._character; + } else { + // Use a surrogate pair. + char32_t v = (char32_t)tch._character - 0x10000u; + wtext += (wchar_t)((v >> 10u) | 0xd800u); + wtext += (wchar_t)((v & 0x3ffu) | 0xdc00u); + } } else { wtext.push_back(0); } @@ -295,12 +309,17 @@ get_wtext() const { wstring wtext; PT(ComputedProperties) current_cprops = _initial_cprops; - TextString::const_iterator si; - for (si = _text_string.begin(); si != _text_string.end(); ++si) { - const TextCharacter &tch = (*si); + for (const TextCharacter &tch : _text_string) { current_cprops->append_delta(wtext, tch._cprops); if (tch._graphic == nullptr) { - wtext += tch._character; + if (sizeof(wchar_t) >= 4 || (tch._character & ~0xffff) == 0) { + wtext += (wchar_t)tch._character; + } else { + // Use a surrogate pair. + char32_t v = (char32_t)tch._character - 0x10000u; + wtext += (wchar_t)((v >> 10u) | 0xd800u); + wtext += (wchar_t)((v & 0x3ffu) | 0xdc00u); + } } else { wtext.push_back(text_embed_graphic_key); wtext += tch._graphic_wname; @@ -341,12 +360,17 @@ get_wordwrapped_wtext() const { wtext += '\n'; } - TextString::const_iterator si; - for (si = row._string.begin(); si != row._string.end(); ++si) { - const TextCharacter &tch = (*si); + for (const TextCharacter &tch : row._string) { current_cprops->append_delta(wtext, tch._cprops); if (tch._graphic == nullptr) { - wtext += tch._character; + if (sizeof(wchar_t) >= 4 || (tch._character & ~0xffff) == 0) { + wtext += (wchar_t)tch._character; + } else { + // Use a surrogate pair. + char32_t v = (char32_t)tch._character - 0x10000u; + wtext += (wchar_t)((v >> 10u) | 0xd800u); + wtext += (wchar_t)((v & 0x3ffu) | 0xdc00u); + } } else { wtext.push_back(text_embed_graphic_key); wtext += tch._graphic_wname; @@ -407,14 +431,14 @@ calc_r_c(int &r, int &c, int n) const { c = 0; int i = row._row_start; while (i < n - 1) { - if (_text_string[i]._character != text_soft_hyphen_key && - _text_string[i]._character != text_soft_break_key) { + if (_text_string[i]._character != (char32_t)text_soft_hyphen_key && + _text_string[i]._character != (char32_t)text_soft_break_key) { ++c; } ++i; } - if (_text_string[n - 1]._character != text_soft_hyphen_key && - _text_string[n - 1]._character != text_soft_break_key) { + if (_text_string[n - 1]._character != (char32_t)text_soft_hyphen_key && + _text_string[n - 1]._character != (char32_t)text_soft_break_key) { ++c; if (_text_string[n - 1]._character == '\n') { is_real_char = false; @@ -458,8 +482,8 @@ calc_index(int r, int c) const { // we have to scan past them to get n precisely. int n = row._row_start; while (c > 0) { - if (_text_string[n]._character != text_soft_hyphen_key && - _text_string[n]._character != text_soft_break_key) { + if (_text_string[n]._character != (char32_t)text_soft_hyphen_key && + _text_string[n]._character != (char32_t)text_soft_break_key) { --c; } ++n; @@ -624,6 +648,18 @@ assemble_text() { */ PN_stdfloat TextAssembler:: calc_width(wchar_t character, const TextProperties &properties) { + return calc_width((char32_t)character, properties); +} + +/** + * Returns the width of a single character, according to its associated font. + * This also correctly calculates the width of cheesy ligatures and accented + * characters, which may not exist in the font as such. + * + * This does not take kerning into account, however. + */ +PN_stdfloat TextAssembler:: +calc_width(char32_t character, const TextProperties &properties) { if (character == ' ') { // A space is a special case. TextFont *font = properties.get_font(); @@ -766,13 +802,13 @@ scan_wtext(TextAssembler::TextString &output_string, const wstring::const_iterator &send, TextAssembler::ComputedProperties *current_cprops) { while (si != send) { - if ((*si) == text_push_properties_key) { + if ((*si) == (wchar_t)text_push_properties_key) { // This indicates a nested properties structure. Pull off the name of // the TextProperties structure, which is everything until the next // text_push_properties_key. wstring wname; ++si; - while (si != send && (*si) != text_push_properties_key) { + while (si != send && (*si) != (wchar_t)text_push_properties_key) { wname += (*si); ++si; } @@ -803,20 +839,20 @@ scan_wtext(TextAssembler::TextString &output_string, } } - } else if ((*si) == text_pop_properties_key) { + } else if ((*si) == (wchar_t)text_pop_properties_key) { // This indicates the undoing of a previous push_properties_key. We // simply return to the previous level. ++si; return; - } else if ((*si) == text_embed_graphic_key) { + } else if ((*si) == (wchar_t)text_embed_graphic_key) { // This indicates an embedded graphic. Pull off the name of the // TextGraphic structure, which is everything until the next // text_embed_graphic_key. wstring graphic_wname; ++si; - while (si != send && (*si) != text_embed_graphic_key) { + while (si != send && (*si) != (wchar_t)text_embed_graphic_key) { graphic_wname += (*si); ++si; } @@ -847,6 +883,27 @@ scan_wtext(TextAssembler::TextString &output_string, << "Unknown TextGraphic: " << graphic_name << "\n"; } +#if WCHAR_MAX < 0x10FFFF + } else if (*si >= 0xd800 && *si < 0xdc00) { + // This is a high surrogate. Look for a subsequent low surrogate. + wchar_t ch = *si; + ++si; + if (si == send) { + text_cat.warning() + << "High surrogate at end of text.\n"; + return; + } + wchar_t ch2 = *si; + if (ch2 >= 0xdc00 && ch2 < 0xe000) { + char32_t code_point = 0x10000 + ((ch - 0xd800) << 10) + (ch2 - 0xdc00); + output_string.push_back(TextCharacter(code_point, current_cprops)); + ++si; + } else { + text_cat.warning() + << "High surrogate was not followed by low surrogate in text.\n"; + } +#endif + } else { // A normal character. Apply it. output_string.push_back(TextCharacter(*si, current_cprops)); @@ -927,7 +984,7 @@ wordwrap_text() { } if (isspacew(_text_string[q]._character) || - _text_string[q]._character == text_soft_break_key) { + _text_string[q]._character == (char32_t)text_soft_break_key) { if (!last_was_space) { any_spaces = true; // We only care about logging whether there is a soft-hyphen @@ -944,7 +1001,7 @@ wordwrap_text() { // A soft hyphen character is not printed, but marks a point at which we // might hyphenate a word if we need to. - if (_text_string[q]._character == text_soft_hyphen_key) { + if (_text_string[q]._character == (char32_t)text_soft_hyphen_key) { if (wordwrap_width > 0.0f) { // We only consider this as a possible hyphenation point if (a) it // is not the very first character, and (b) there is enough room for @@ -1051,8 +1108,8 @@ wordwrap_text() { } for (size_t pi = p; pi < q; pi++) { - if (_text_string[pi]._character != text_soft_hyphen_key && - _text_string[pi]._character != text_soft_break_key) { + if (_text_string[pi]._character != (char32_t)text_soft_hyphen_key && + _text_string[pi]._character != (char32_t)text_soft_break_key) { _text_block.back()._string.push_back(_text_string[pi]); } else { _text_block.back()._got_soft_hyphens = true; @@ -1422,15 +1479,13 @@ assemble_row(TextAssembler::TextRow &row, PN_stdfloat underscore_start = 0.0f; const TextProperties *underscore_properties = nullptr; -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) const ComputedProperties *prev_cprops = nullptr; hb_buffer_t *harfbuff = nullptr; #endif - TextString::const_iterator si; - for (si = row._string.begin(); si != row._string.end(); ++si) { - const TextCharacter &tch = (*si); - wchar_t character = tch._character; + for (const TextCharacter &tch : row._string) { + char32_t character = tch._character; const TextGraphic *graphic = tch._graphic; const TextProperties *properties = &(tch._cprops->_properties); @@ -1470,7 +1525,7 @@ assemble_row(TextAssembler::TextRow &row, line_height = max(line_height, font->get_line_height() * properties->get_glyph_scale() * properties->get_text_scale()); } -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) if (tch._cprops != prev_cprops || graphic != nullptr) { if (harfbuff != nullptr && hb_buffer_get_length(harfbuff) > 0) { // Shape the buffer accumulated so far. @@ -1487,7 +1542,20 @@ assemble_row(TextAssembler::TextRow &row, } if (graphic == nullptr && harfbuff != nullptr) { - hb_buffer_add(harfbuff, character, character); + unsigned int cluster = character; + + if (properties->get_small_caps()) { + const UnicodeLatinMap::Entry *map_entry = + UnicodeLatinMap::look_up((char32_t)character); + if (map_entry != nullptr && + map_entry->_toupper_character != (char32_t)character) { + character = map_entry->_toupper_character; + + // Set a high bit on the cluster to flag this as needing a scale. + cluster |= CF_small_caps; + } + } + hb_buffer_add(harfbuff, character, cluster); continue; } #endif @@ -1526,7 +1594,7 @@ assemble_row(TextAssembler::TextRow &row, xpos = (floor(xpos / tab_width) + 1.0f) * tab_width; prev_char = -1; - } else if (character == text_soft_hyphen_key) { + } else if (character == (char32_t)text_soft_hyphen_key) { // And so is the 'soft-hyphen' key character. } else if (graphic != nullptr) { @@ -1692,7 +1760,7 @@ assemble_row(TextAssembler::TextRow &row, } } -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) if (harfbuff != nullptr && hb_buffer_get_length(harfbuff) > 0) { shape_buffer(harfbuff, placed_glyphs, xpos, prev_cprops->_properties); } @@ -1729,7 +1797,7 @@ void TextAssembler:: shape_buffer(hb_buffer_t *buf, PlacedGlyphs &placed_glyphs, PN_stdfloat &xpos, const TextProperties &properties) { -#ifdef HAVE_HARFBUZZ +#if defined(HAVE_HARFBUZZ) && defined(HAVE_FREETYPE) // If we did not specify a text direction, harfbuzz will guess it based on // the script we are using. hb_direction_t direction = HB_DIRECTION_INVALID; @@ -1759,7 +1827,8 @@ shape_buffer(hb_buffer_t *buf, PlacedGlyphs &placed_glyphs, PN_stdfloat &xpos, hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); for (unsigned int i = 0; i < glyph_count; ++i) { - int character = glyph_info[i].cluster; + unsigned int cluster = glyph_info[i].cluster; + int character = cluster & 0x1fffff; int glyph_index = glyph_info[i].codepoint; CPT(TextGlyph) glyph; @@ -1798,6 +1867,12 @@ shape_buffer(hb_buffer_t *buf, PlacedGlyphs &placed_glyphs, PN_stdfloat &xpos, placement._ypos = properties.get_glyph_shift() + y_offset; placement._slant = properties.get_slant(); placement._properties = &properties; + + if (cluster & CF_small_caps) { + advance *= properties.get_small_caps_scale(); + placement._scale *= properties.get_small_caps_scale(); + } + placed_glyphs.push_back(placement); xpos += advance; diff --git a/panda/src/text/textAssembler.h b/panda/src/text/textAssembler.h index 20f9b2c1e5d..a4c7182ce45 100644 --- a/panda/src/text/textAssembler.h +++ b/panda/src/text/textAssembler.h @@ -78,14 +78,14 @@ class EXPCL_PANDA_TEXT TextAssembler { int calc_index(int r, int c) const; INLINE int get_num_characters() const; - INLINE wchar_t get_character(int n) const; + INLINE char32_t get_character(int n) const; INLINE const TextGraphic *get_graphic(int n) const; INLINE const TextProperties &get_properties(int n) const; INLINE PN_stdfloat get_width(int n) const; INLINE int get_num_rows() const; INLINE int get_num_cols(int r) const; - INLINE wchar_t get_character(int r, int c) const; + INLINE char32_t get_character(int r, int c) const; INLINE const TextGraphic *get_graphic(int r, int c) const; INLINE const TextProperties &get_properties(int r, int c) const; INLINE PN_stdfloat get_width(int r, int c) const; @@ -98,6 +98,7 @@ class EXPCL_PANDA_TEXT TextAssembler { INLINE const LVector2 &get_lr() const; static PN_stdfloat calc_width(wchar_t character, const TextProperties &properties); + static PN_stdfloat calc_width(char32_t character, const TextProperties &properties); static PN_stdfloat calc_width(const TextGraphic *graphic, const TextProperties &properties); static bool has_exact_character(wchar_t character, const TextProperties &properties); @@ -132,13 +133,14 @@ class EXPCL_PANDA_TEXT TextAssembler { class TextCharacter { public: INLINE TextCharacter(wchar_t character, ComputedProperties *cprops); + INLINE TextCharacter(char32_t character, ComputedProperties *cprops); INLINE TextCharacter(const TextGraphic *graphic, const std::wstring &graphic_wname, ComputedProperties *cprops); INLINE TextCharacter(const TextCharacter ©); INLINE void operator = (const TextCharacter ©); - wchar_t _character; + char32_t _character; const TextGraphic *_graphic; std::wstring _graphic_wname; PT(ComputedProperties) _cprops; diff --git a/panda/src/tinydisplay/td_light.cxx b/panda/src/tinydisplay/td_light.cxx index c570e5347cd..5e1abf47839 100644 --- a/panda/src/tinydisplay/td_light.cxx +++ b/panda/src/tinydisplay/td_light.cxx @@ -127,9 +127,13 @@ void gl_shade_vertex(GLContext *c,GLVertex *v) B+=att * lB; } - v->color.v[0]=clampf(R*v->color.v[0],0,1); - v->color.v[1]=clampf(G*v->color.v[1],0,1); - v->color.v[2]=clampf(B*v->color.v[2],0,1); - v->color.v[3]=clampf(A*v->color.v[3],0,1); + v->color.v[0]=clampf(R,0,1); + v->color.v[1]=clampf(G,0,1); + v->color.v[2]=clampf(B,0,1); + v->color.v[3]=clampf(A,0,1); + //v->color.v[0]=clampf(R*v->color.v[0],0,1); + //v->color.v[1]=clampf(G*v->color.v[1],0,1); + //v->color.v[2]=clampf(B*v->color.v[2],0,1); + //v->color.v[3]=clampf(A*v->color.v[3],0,1); } diff --git a/panda/src/tinydisplay/tinyGraphicsBuffer.cxx b/panda/src/tinydisplay/tinyGraphicsBuffer.cxx index 47c0327f1bb..0fc76e492ce 100644 --- a/panda/src/tinydisplay/tinyGraphicsBuffer.cxx +++ b/panda/src/tinydisplay/tinyGraphicsBuffer.cxx @@ -136,6 +136,8 @@ open_buffer() { return false; } + _fb_properties.set_depth_bits(ZB_Z_BITS); + tinygsg->_current_frame_buffer = _frame_buffer; tinygsg->reset_if_new(); diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index 5e723cece89..a260b23b2df 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -685,8 +685,6 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, needs_normal = false; } - bool lighting_enabled = (needs_normal && _c->lighting_enabled); - for (i = 0; i < num_used_vertices; ++i) { GLVertex *v = &_vertices[i]; const LVecBase4 &d = rvertex.get_data4(); @@ -723,12 +721,14 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, v->color = _c->current_color; - if (lighting_enabled) { - const LVecBase3 &d = rnormal.get_data3(); - _c->current_normal.v[0] = d[0]; - _c->current_normal.v[1] = d[1]; - _c->current_normal.v[2] = d[2]; - _c->current_normal.v[3] = 0.0f; + if (_c->lighting_enabled) { + if (needs_normal) { + const LVecBase3 &d = rnormal.get_data3(); + _c->current_normal.v[0] = d[0]; + _c->current_normal.v[1] = d[1]; + _c->current_normal.v[2] = d[2]; + _c->current_normal.v[3] = 0.0f; + } gl_vertex_transform(_c, v); gl_shade_vertex(_c, v); @@ -882,7 +882,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, const ShadeModelAttrib *target_shade_model = DCAST(ShadeModelAttrib, _target_rs->get_attrib_def(ShadeModelAttrib::get_class_slot())); ShadeModelAttrib::Mode shade_model = target_shade_model->get_mode(); - if (!needs_normal && !needs_color) { + if (!needs_color && !_c->lighting_enabled) { // With no per-vertex lighting, and no per-vertex colors, we might as well // use the flat shading model. shade_model = ShadeModelAttrib::M_flat; @@ -1352,7 +1352,12 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z, int xo, yo, w, h; dr->get_region_pixels_i(xo, yo, w, h); - tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, Texture::F_rgba); + Texture::Format format = Texture::F_rgba; + if (_current_properties->get_srgb_color()) { + format = Texture::F_srgb_alpha; + } + + tex->setup_2d_texture(w, h, Texture::T_unsigned_byte, format); TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); nassertr(tc != nullptr, false); @@ -1412,6 +1417,9 @@ framebuffer_copy_to_ram(Texture *tex, int view, int z, Texture::ComponentType component_type = Texture::T_unsigned_byte; Texture::Format format = Texture::F_rgba; + if (_current_properties->get_srgb_color()) { + format = Texture::F_srgb_alpha; + } if (tex->get_x_size() != w || tex->get_y_size() != h || tex->get_z_size() != z_size || diff --git a/panda/src/webgldisplay/webGLGraphicsWindow.cxx b/panda/src/webgldisplay/webGLGraphicsWindow.cxx index 700f89c1b84..dc6d8e6f97d 100644 --- a/panda/src/webgldisplay/webGLGraphicsWindow.cxx +++ b/panda/src/webgldisplay/webGLGraphicsWindow.cxx @@ -238,6 +238,16 @@ set_properties_now(WindowProperties &properties) { // though, we can't hide the cursor. properties.clear_cursor_hidden(); } + + if (properties.get_foreground()) { + EM_ASM_({ + var canvas = document.getElementById('canvas'); + if (canvas) { + canvas.focus(); + } + }); + properties.clear_foreground(); + } } /** @@ -369,6 +379,19 @@ open_window() { emscripten_set_wheel_callback(target, user_data, false, &on_wheel_event); + if (!_properties.has_foreground() || _properties.get_foreground()) { + _properties.set_foreground(EM_ASM_INT({ + var canvas = document.getElementById('canvas'); + if (canvas) { + canvas.focus(); + + return document.activeElement === canvas; + } else { + return false; + } + })); + } + return true; } @@ -472,9 +495,9 @@ on_keyboard_event(int type, const EmscriptenKeyboardEvent *event, void *user_dat // it does the right thing. We grab the first unicode code point. // Unfortunately, this doesn't seem to handle dead keys on Firefox. int keycode = 0; - EM_ASM_({ - stringToUTF32(String.fromCharCode($0), $1, 4); - }, event->charCode, &keycode); + keycode = EM_ASM_INT({ + return String.fromCharCode($0).codePointAt(0); + }, event->charCode); if (keycode != 0) { device->keystroke(keycode); diff --git a/panda/src/wgldisplay/wglGraphicsBuffer.cxx b/panda/src/wgldisplay/wglGraphicsBuffer.cxx index 61edb9643c9..3721dacb16d 100644 --- a/panda/src/wgldisplay/wglGraphicsBuffer.cxx +++ b/panda/src/wgldisplay/wglGraphicsBuffer.cxx @@ -301,9 +301,10 @@ open_buffer() { // If the old gsg has the wrong pixel format, create a new one that shares // with the old gsg. DCAST_INTO_R(wglgsg, _gsg, false); - if ((!wglgsg->get_fb_properties().subsumes(_fb_properties))|| - (!wglgsg->get_fb_properties().is_single_buffered())|| - (!wglgsg->pfnum_supports_pbuffer())) { + if (wglgsg->get_engine() != _engine || + !wglgsg->get_fb_properties().subsumes(_fb_properties) || + !wglgsg->get_fb_properties().is_single_buffered() || + !wglgsg->pfnum_supports_pbuffer()) { wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, wglgsg); wglgsg->choose_pixel_format(_fb_properties, true); _gsg = wglgsg; diff --git a/panda/src/wgldisplay/wglGraphicsPipe.cxx b/panda/src/wgldisplay/wglGraphicsPipe.cxx index 4186c35a35b..2f4d1392afd 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.cxx +++ b/panda/src/wgldisplay/wglGraphicsPipe.cxx @@ -148,6 +148,9 @@ make_output(const std::string &name, (flags & (BF_require_parasite | BF_require_window)) != 0) { return nullptr; } + if (host->get_engine() != engine) { + return nullptr; + } // Early failure - if we are sure that this buffer WONT meet specs, we can // bail out early. if ((flags & BF_fb_props_optional) == 0) { diff --git a/panda/src/wgldisplay/wglGraphicsWindow.cxx b/panda/src/wgldisplay/wglGraphicsWindow.cxx index c79ea4eb9ff..536b5ad2f6a 100644 --- a/panda/src/wgldisplay/wglGraphicsWindow.cxx +++ b/panda/src/wgldisplay/wglGraphicsWindow.cxx @@ -209,7 +209,8 @@ open_window() { // If the old gsg has the wrong pixel format, create a new one that shares // with the old gsg. DCAST_INTO_R(wglgsg, _gsg, false); - if (!wglgsg->get_fb_properties().subsumes(_fb_properties)) { + if (wglgsg->get_engine() != _engine || + !wglgsg->get_fb_properties().subsumes(_fb_properties)) { wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, wglgsg); wglgsg->choose_pixel_format(_fb_properties, false); _gsg = wglgsg; diff --git a/panda/src/windisplay/config_windisplay.cxx b/panda/src/windisplay/config_windisplay.cxx index 6d655d905b2..0e3090257c9 100644 --- a/panda/src/windisplay/config_windisplay.cxx +++ b/panda/src/windisplay/config_windisplay.cxx @@ -27,17 +27,6 @@ ConfigureFn(config_windisplay) { init_libwindisplay(); } -ConfigVariableBool responsive_minimized_fullscreen_window -("responsive-minimized-fullscreen-window",false); - -ConfigVariableBool hold_keys_across_windows -("hold-keys-across-windows", false, - PRC_DESC("Set this true to remember the current state of the keyboard while " - "the window focus is lost, or false to pretend the user is not " - "holding down any keys while the window focus is lost. In either " - "case it should accurately restore the correct keyboard state when " - "the window focus is regained.")); - ConfigVariableBool do_vidmemsize_check ("do-vidmemsize-check", true, PRC_DESC("if true, use ddraw's GetAvailVidMem to fail if driver says " @@ -76,10 +65,6 @@ ConfigVariableBool dpi_window_resize "panel. Only available in Windows 8.1 and later, and requires " "dpi-aware to be set as well.")); -ConfigVariableBool swapbuffer_framelock -("swapbuffer-framelock", false, - PRC_DESC("Set this true to enable HW swapbuffer frame-lock on 3dlabs cards")); - ConfigVariableBool paste_emit_keystrokes ("paste-emit-keystrokes", true, PRC_DESC("Handle paste events (Ctrl-V) as separate keystroke events for each " diff --git a/panda/src/windisplay/config_windisplay.h b/panda/src/windisplay/config_windisplay.h index 377b2724721..9ea1e23cc3a 100644 --- a/panda/src/windisplay/config_windisplay.h +++ b/panda/src/windisplay/config_windisplay.h @@ -21,8 +21,6 @@ NotifyCategoryDecl(windisplay, EXPCL_PANDAWIN, EXPTP_PANDAWIN); -extern ConfigVariableBool responsive_minimized_fullscreen_window; -extern ConfigVariableBool hold_keys_across_windows; extern ConfigVariableBool do_vidmemsize_check; extern ConfigVariableBool auto_cpu_data; extern ConfigVariableBool ime_hide; @@ -32,8 +30,6 @@ extern ConfigVariableBool dpi_window_resize; extern ConfigVariableBool paste_emit_keystrokes; extern ConfigVariableBool disable_message_loop; -extern EXPCL_PANDAWIN ConfigVariableBool swapbuffer_framelock; - extern EXPCL_PANDAWIN void init_libwindisplay(); #endif diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index 05b769bb3be..266722aa1bd 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -293,7 +293,9 @@ set_properties_now(WindowProperties &properties) { } if (do_fullscreen_switch(x_size, y_size)) { _properties.set_fullscreen(true); + _properties.set_size(x_size, y_size); properties.clear_size(); + properties.clear_origin(); } else { windisplay_cat.warning() << "Switching to fullscreen mode failed!\n"; @@ -1007,7 +1009,7 @@ do_fullscreen_switch(int x_size, int y_size) { SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, x_size, y_size, SWP_FRAMECHANGED | SWP_SHOWWINDOW); - handle_reshape(); + set_size_and_recalc(x_size, y_size); return true; } @@ -1366,6 +1368,11 @@ adjust_z_order() { void WinGraphicsWindow:: adjust_z_order(WindowProperties::ZOrder last_z_order, WindowProperties::ZOrder this_z_order) { + // Prevent calling this recursively. + if (_in_adjust_z_order) { + return; + } + HWND order; bool do_change = false; @@ -1395,8 +1402,10 @@ adjust_z_order(WindowProperties::ZOrder last_z_order, break; } if (do_change) { + _in_adjust_z_order = true; BOOL result = SetWindowPos(_hWnd, order, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE); + _in_adjust_z_order = false; if (!result) { windisplay_cat.warning() << "SetWindowPos failed.\n"; @@ -1506,6 +1515,26 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { WindowProperties properties; switch (msg) { + case WM_GETMINMAXINFO: + { + MINMAXINFO* minmaxinfo = (MINMAXINFO*)lparam; + + int minClientWidth = 1; // Minimum client area width + int minClientHeight = 1; // Minimum client area height + + // Adjust window for non-client area + RECT rect = { 0, 0, minClientWidth, minClientHeight }; + AdjustWindowRect(&rect, GetWindowLong(hwnd, GWL_STYLE), FALSE); + + // Calculate final size + int minWidth = rect.right - rect.left; + int minHeight = rect.bottom - rect.top; + + // Set the minimum track size in MINMAXINFO + minmaxinfo->ptMinTrackSize.x = minWidth; // Minimum window width + minmaxinfo->ptMinTrackSize.y = minHeight; // Minimum window height + } + break; case WM_MOUSEMOVE: if (!_tracking_mouse_leaving) { // need to re-call TrackMouseEvent every time mouse re-enters window @@ -1688,7 +1717,9 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if (_hWnd != nullptr) { handle_reshape(); } - adjust_z_order(); + if (!_in_adjust_z_order) { + adjust_z_order(); + } return 0; case WM_PAINT: @@ -2033,7 +2064,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // the actual value passed to WM_CHAR seems to be poorly defined. Now we // are using RegisterClassW etc., which means WM_CHAR is absolutely // supposed to be utf-16. - if (!_ime_open) { + if (!_ime_open || !ime_aware) { _input->keystroke(wparam); } break; diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index 9ce69d87a1f..d0e8f938a29 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -199,6 +199,8 @@ class EXPCL_PANDAWIN WinGraphicsWindow : public GraphicsWindow { UINT _num_touches; TOUCHINPUT _touches[MAX_TOUCHES]; + bool _in_adjust_z_order = false; + private: // We need this map to support per-window calls to window_proc(). typedef std::map WindowHandles; diff --git a/panda/src/x11display/x11GraphicsPipe.cxx b/panda/src/x11display/x11GraphicsPipe.cxx index 1f74c64fdb4..dda30ff5c10 100644 --- a/panda/src/x11display/x11GraphicsPipe.cxx +++ b/panda/src/x11display/x11GraphicsPipe.cxx @@ -409,6 +409,7 @@ x11GraphicsPipe(const std::string &display) : _net_startup_info = XInternAtom(_display, "_NET_STARTUP_INFO", false); _net_startup_info_begin = XInternAtom(_display, "_NET_STARTUP_INFO_BEGIN", false); _net_wm_bypass_compositor = XInternAtom(_display, "_NET_WM_BYPASS_COMPOSITOR", false); + _net_wm_name = XInternAtom(_display, "_NET_WM_NAME", false); _net_wm_pid = XInternAtom(_display, "_NET_WM_PID", false); _net_wm_ping = XInternAtom(_display, "_NET_WM_PING", false); _net_wm_state = XInternAtom(_display, "_NET_WM_STATE", false); diff --git a/panda/src/x11display/x11GraphicsPipe.h b/panda/src/x11display/x11GraphicsPipe.h index b0ffcf10b5b..b2b69cca5e2 100644 --- a/panda/src/x11display/x11GraphicsPipe.h +++ b/panda/src/x11display/x11GraphicsPipe.h @@ -174,6 +174,7 @@ class x11GraphicsPipe : public GraphicsPipe { Atom _net_startup_info; Atom _net_startup_info_begin; Atom _net_wm_bypass_compositor; + Atom _net_wm_name; Atom _net_wm_pid; Atom _net_wm_ping; Atom _net_wm_state; diff --git a/panda/src/x11display/x11GraphicsWindow.cxx b/panda/src/x11display/x11GraphicsWindow.cxx index 3fc30c56922..49c1e19b139 100644 --- a/panda/src/x11display/x11GraphicsWindow.cxx +++ b/panda/src/x11display/x11GraphicsWindow.cxx @@ -1321,6 +1321,15 @@ set_wm_properties(const WindowProperties &properties, bool already_mapped) { if (XStringListToTextProperty((char **)&name, 1, &window_name) != 0) { window_name_p = &window_name; } + +#ifdef X_HAVE_UTF8_STRING + XTextProperty wm_name; + if (Xutf8TextListToTextProperty(_display, (char **)&name, 1, + XUTF8StringStyle, &wm_name) == Success) { + XSetTextProperty(_display, _xwindow, &wm_name, x11_pipe->_net_wm_name); + XFree(wm_name.value); + } +#endif } // The size hints request a window of a particular size andor a particular diff --git a/pandatool/CMakeLists.txt b/pandatool/CMakeLists.txt index 3ebe06ac35d..8db045f4d5d 100644 --- a/pandatool/CMakeLists.txt +++ b/pandatool/CMakeLists.txt @@ -47,4 +47,7 @@ add_subdirectory(src/xfile) add_subdirectory(src/xfileegg) add_subdirectory(src/xfileprogs) -export_targets(Tools) +if(BUILD_TOOLS) + export_targets(Tools) +endif() +export_targets(ToolsDevel NAMESPACE "Panda3D::Tools::" COMPONENT ToolsDevel) diff --git a/pandatool/src/bam/CMakeLists.txt b/pandatool/src/bam/CMakeLists.txt index 79389b92ffd..32f5a6f55b0 100644 --- a/pandatool/src/bam/CMakeLists.txt +++ b/pandatool/src/bam/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(bam-info bamInfo.cxx bamInfo.h) target_link_libraries(bam-info p3progbase panda) install(TARGETS bam-info EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/pandatool/src/converter/CMakeLists.txt b/pandatool/src/converter/CMakeLists.txt index 2e75fed9f26..a793b718aca 100644 --- a/pandatool/src/converter/CMakeLists.txt +++ b/pandatool/src/converter/CMakeLists.txt @@ -14,5 +14,10 @@ set(P3CONVERTER_SOURCES add_library(p3converter STATIC ${P3CONVERTER_HEADERS} ${P3CONVERTER_SOURCES}) target_link_libraries(p3converter p3pandatoolbase pandaegg) -# This is only needed for binaries in the pandatool package. It is not useful -# for user applications, so it is not installed. +install(TARGETS p3converter + EXPORT ToolsDevel COMPONENT ToolsDevel + DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d + ARCHIVE COMPONENT ToolsDevel) +install(FILES ${P3CONVERTER_HEADERS} COMPONENT ToolsDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d) diff --git a/pandatool/src/daeprogs/CMakeLists.txt b/pandatool/src/daeprogs/CMakeLists.txt index 75db4c4b16c..42cd2f48fea 100644 --- a/pandatool/src/daeprogs/CMakeLists.txt +++ b/pandatool/src/daeprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(HAVE_EGG AND HAVE_FCOLLADA) add_executable(dae2egg daeToEgg.cxx daeToEgg.h) diff --git a/pandatool/src/deploy-stub/android_main.cxx b/pandatool/src/deploy-stub/android_main.cxx index 5aa24b53d22..d1e140c5f3c 100644 --- a/pandatool/src/deploy-stub/android_main.cxx +++ b/pandatool/src/deploy-stub/android_main.cxx @@ -161,8 +161,6 @@ void android_main(struct android_app *app) { std::string dtool_name = std::string(libdir) + "/libp3dtool.so"; ExecutionEnvironment::set_dtool_name(dtool_name); android_cat.info() << "Path to dtool: " << dtool_name << "\n"; - - env->ReleaseStringUTFChars(libdir_jstr, libdir); } // Get the path to the APK. @@ -184,6 +182,7 @@ void android_main(struct android_app *app) { // Map the blob to memory void *blob = map_blob(lib_path, (off_t)blobinfo.blob_offset, (size_t)blobinfo.blob_size); + env->ReleaseStringUTFChars(lib_path_jstr, lib_path); assert(blob != NULL); assert(blobinfo.num_pointers <= MAX_NUM_POINTERS); @@ -242,14 +241,16 @@ void android_main(struct android_app *app) { preconfig.utf8_mode = 1; PyStatus status = Py_PreInitialize(&preconfig); if (PyStatus_Exception(status)) { - Py_ExitStatusException(status); - return; + env->ReleaseStringUTFChars(libdir_jstr, libdir); + Py_ExitStatusException(status); + return; } // Register the android_log module. if (PyImport_AppendInittab("android_log", &PyInit_android_log) < 0) { android_cat.error() << "Failed to register android_log module.\n"; + env->ReleaseStringUTFChars(libdir_jstr, libdir); return; } @@ -259,8 +260,8 @@ void android_main(struct android_app *app) { config.buffered_stdio = 0; config.configure_c_stdio = 0; config.write_bytecode = 0; - PyConfig_SetBytesString(&config, &config.executable, lib_path); - env->ReleaseStringUTFChars(lib_path_jstr, lib_path); + PyConfig_SetBytesString(&config, &config.platlibdir, libdir); + env->ReleaseStringUTFChars(libdir_jstr, libdir); status = Py_InitializeFromConfig(&config); PyConfig_Clear(&config); @@ -297,11 +298,10 @@ void android_main(struct android_app *app) { // We still need to keep an event loop going until Android gives us leave // to end the process. - int looper_id; - int events; - struct android_poll_source *source; - while ((looper_id = ALooper_pollAll(-1, nullptr, &events, (void**)&source)) >= 0) { - // Process this event, but intercept application command events. + while (!app->destroyRequested) { + int looper_id; + struct android_poll_source *source; + auto result = ALooper_pollOnce(-1, &looper_id, nullptr, (void **)&source); if (looper_id == LOOPER_ID_MAIN) { int8_t cmd = android_app_read_cmd(app); android_app_pre_exec_cmd(app, cmd); @@ -332,4 +332,6 @@ void android_main(struct android_app *app) { // Detach the thread before exiting. activity->vm->DetachCurrentThread(); + + _exit(0); } diff --git a/pandatool/src/deploy-stub/deploy-stub.c b/pandatool/src/deploy-stub/deploy-stub.c index 7e0b22464da..6cd2c2803c8 100644 --- a/pandatool/src/deploy-stub/deploy-stub.c +++ b/pandatool/src/deploy-stub/deploy-stub.c @@ -712,7 +712,9 @@ int main(int argc, char *argv[]) { new_moddef->code = moddef->code; new_moddef->size = moddef->size < 0 ? -(moddef->size) : moddef->size; new_moddef->is_package = moddef->size < 0; +#if PY_VERSION_HEX < 0x030d0000 // 3.13 new_moddef->get_code = NULL; +#endif new_moddef++; } #endif diff --git a/pandatool/src/dxfprogs/CMakeLists.txt b/pandatool/src/dxfprogs/CMakeLists.txt index 3cd39a0baae..0a2033d15cc 100644 --- a/pandatool/src/dxfprogs/CMakeLists.txt +++ b/pandatool/src/dxfprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(dxf-points dxfPoints.cxx dxfPoints.h) target_link_libraries(dxf-points p3progbase p3dxf) install(TARGETS dxf-points EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/pandatool/src/egg-mkfont/CMakeLists.txt b/pandatool/src/egg-mkfont/CMakeLists.txt index 8b548e2e918..60f0331e0da 100644 --- a/pandatool/src/egg-mkfont/CMakeLists.txt +++ b/pandatool/src/egg-mkfont/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT HAVE_EGG OR NOT HAVE_FREETYPE) return() endif() diff --git a/pandatool/src/egg-optchar/CMakeLists.txt b/pandatool/src/egg-optchar/CMakeLists.txt index b30a070224d..379fc301788 100644 --- a/pandatool/src/egg-optchar/CMakeLists.txt +++ b/pandatool/src/egg-optchar/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT HAVE_EGG) return() endif() diff --git a/pandatool/src/egg-palettize/CMakeLists.txt b/pandatool/src/egg-palettize/CMakeLists.txt index 18576f25d60..9af1445726a 100644 --- a/pandatool/src/egg-palettize/CMakeLists.txt +++ b/pandatool/src/egg-palettize/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT HAVE_EGG) return() endif() diff --git a/pandatool/src/egg-qtess/CMakeLists.txt b/pandatool/src/egg-qtess/CMakeLists.txt index c8f4244c8a2..83e6ff1ff6d 100644 --- a/pandatool/src/egg-qtess/CMakeLists.txt +++ b/pandatool/src/egg-qtess/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT HAVE_EGG) return() endif() diff --git a/pandatool/src/eggbase/CMakeLists.txt b/pandatool/src/eggbase/CMakeLists.txt index 115ac0882cb..892e8bb8847 100644 --- a/pandatool/src/eggbase/CMakeLists.txt +++ b/pandatool/src/eggbase/CMakeLists.txt @@ -24,5 +24,10 @@ composite_sources(p3eggbase P3EGGBASE_SOURCES) add_library(p3eggbase STATIC ${P3EGGBASE_HEADERS} ${P3EGGBASE_SOURCES}) target_link_libraries(p3eggbase p3progbase p3converter) -# This is only needed for binaries in the pandatool package. It is not useful -# for user applications, so it is not installed. +install(TARGETS p3eggbase + EXPORT ToolsDevel COMPONENT ToolsDevel + DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d + ARCHIVE COMPONENT ToolsDevel) +install(FILES ${P3EGGBASE_HEADERS} COMPONENT ToolsDevel DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/panda3d) diff --git a/pandatool/src/eggprogs/CMakeLists.txt b/pandatool/src/eggprogs/CMakeLists.txt index a14d33ab80e..e845c57d0b0 100644 --- a/pandatool/src/eggprogs/CMakeLists.txt +++ b/pandatool/src/eggprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT HAVE_EGG) return() endif() diff --git a/pandatool/src/fltprogs/CMakeLists.txt b/pandatool/src/fltprogs/CMakeLists.txt index 29a04166b76..0ceebcf6343 100644 --- a/pandatool/src/fltprogs/CMakeLists.txt +++ b/pandatool/src/fltprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(flt-info fltInfo.cxx fltInfo.h) target_link_libraries(flt-info p3progbase p3flt) install(TARGETS flt-info EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/pandatool/src/gtk-stats/CMakeLists.txt b/pandatool/src/gtk-stats/CMakeLists.txt index 2305c594040..dca2f914220 100644 --- a/pandatool/src/gtk-stats/CMakeLists.txt +++ b/pandatool/src/gtk-stats/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT HAVE_GTK3 OR NOT HAVE_NET) return() endif() diff --git a/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx b/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx index 2309c4dc36e..7f0ad0a4bd9 100644 --- a/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx +++ b/pandatool/src/gtk-stats/gtkStatsChartMenu.cxx @@ -161,7 +161,7 @@ do_update() { _last_level_index = view.get_level_index(); const PStatClientData *client_data = _monitor->get_client_data(); - if (client_data->get_num_collectors() > _collector_items.size()) { + if ((size_t)client_data->get_num_collectors() > _collector_items.size()) { _collector_items.resize(client_data->get_num_collectors(), std::make_pair(nullptr, nullptr)); } @@ -226,7 +226,7 @@ add_view(GtkWidget *parent_menu, const PStatViewLevel *view_level, } else if (menu_item != nullptr && menu == nullptr) { // Unhook the signal handler, we are creating a submenu. - GtkStatsMonitor::MenuDef smd(_thread_index, collector, GtkStatsMonitor::CT_strip_chart, show_level); + GtkStatsMonitor::MenuDef smd(GtkStatsMonitor::CT_strip_chart, _thread_index, collector, -1, show_level); const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd); g_signal_handlers_disconnect_by_data(G_OBJECT(menu_item), (void *)menu_def); @@ -277,7 +277,7 @@ add_view(GtkWidget *parent_menu, const PStatViewLevel *view_level, GtkWidget *GtkStatsChartMenu:: make_menu_item(const char *label, int collector_index, ChartType chart_type, bool show_level) { - GtkStatsMonitor::MenuDef smd(_thread_index, collector_index, chart_type, show_level); + GtkStatsMonitor::MenuDef smd(chart_type, _thread_index, collector_index, -1, show_level); const GtkStatsMonitor::MenuDef *menu_def = _monitor->add_menu(smd); GtkWidget *menu_item = gtk_menu_item_new_with_label(label); diff --git a/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx b/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx index dcd14914854..ea20558b9b0 100644 --- a/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx +++ b/pandatool/src/gtk-stats/gtkStatsFlameGraph.cxx @@ -24,13 +24,16 @@ static const int default_flame_graph_height = 150; */ GtkStatsFlameGraph:: GtkStatsFlameGraph(GtkStatsMonitor *monitor, int thread_index, - int collector_index) : - PStatFlameGraph(monitor, thread_index, collector_index, 0, 0), + int collector_index, int frame_number) : + PStatFlameGraph(monitor, thread_index, collector_index, frame_number, 0, 0), GtkStatsGraph(monitor, false) { // Let's show the units on the guide bar labels. There's room. set_guide_bar_units(get_guide_bar_units() | GBU_show_units); + std::string window_title = get_title_text(); + gtk_window_set_title(GTK_WINDOW(_window), window_title.c_str()); + // Put some stuff on top of the graph. _top_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(_graph_vbox), _top_hbox, @@ -51,6 +54,13 @@ GtkStatsFlameGraph(GtkStatsMonitor *monitor, int thread_index, gtk_box_pack_start(GTK_BOX(_top_hbox), _scale_area, TRUE, TRUE, 0); gtk_box_pack_end(GTK_BOX(_top_hbox), _total_label, FALSE, FALSE, 0); + // Listen for mouse scroll and keyboard events. + gtk_widget_add_events(_window, GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK); + g_signal_connect(G_OBJECT(_window), "scroll_event", + G_CALLBACK(scroll_callback), this); + g_signal_connect(G_OBJECT(_window), "key_press_event", + G_CALLBACK(key_press_callback), this); + gtk_widget_set_size_request(_graph_window, default_flame_graph_width * monitor->get_resolution() / 96, default_flame_graph_height * monitor->get_resolution() / 96); @@ -151,7 +161,7 @@ set_time_units(int unit_mask) { */ void GtkStatsFlameGraph:: on_click_label(int collector_index) { - set_collector_index(collector_index); + push_collector_index(collector_index); } /** @@ -284,6 +294,15 @@ draw_bar(int depth, int from_x, int to_x, int collector_index, int parent_index) pango_layout_set_text(layout, def._name.c_str(), def._name.size()); } } + else if (collector_index == 0 && get_frame_number() >= 0) { + char text[32]; + sprintf(text, "Frame %d", get_frame_number()); + pango_layout_set_text(layout, text, -1); + if (pango_layout_is_ellipsized(layout)) { + // Nope, it's too long, go back. + pango_layout_set_text(layout, def._name.c_str(), def._name.size()); + } + } } int width, height; @@ -421,7 +440,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(+[] (GtkWidget *widget, gpointer data) { GtkStatsFlameGraph *self = (GtkStatsFlameGraph *)data; - self->set_collector_index(self->_popup_index); + self->push_collector_index(self->_popup_index); }), this); } @@ -429,8 +448,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - get_thread_index(), collector_index, - GtkStatsMonitor::CT_strip_chart, false, + GtkStatsMonitor::CT_strip_chart, get_thread_index(), collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -442,8 +460,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - get_thread_index(), collector_index, - GtkStatsMonitor::CT_flame_graph, + GtkStatsMonitor::CT_flame_graph, get_thread_index(), collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -460,8 +477,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, - GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -473,8 +489,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, - GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); @@ -493,7 +508,13 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { else if (double_click && button == 1) { // Double-clicking on a color bar in the graph will zoom the graph into // that collector. - set_collector_index(collector_index); + if (collector_index >= 0) { + push_collector_index(collector_index); + } else { + // Double-clicking the background goes to the top. + clear_history(); + set_collector_index(-1); + } return TRUE; } } @@ -721,3 +742,73 @@ draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data) { return TRUE; } + +/** + * + */ +gboolean GtkStatsFlameGraph:: +scroll_callback(GtkWidget *widget, GdkEventScroll *event, gpointer data) { + GtkStatsFlameGraph *self = (GtkStatsFlameGraph *)data; + bool changed = false; + switch (event->direction) { + case GDK_SCROLL_LEFT: + changed = self->prev_frame(); + break; + + case GDK_SCROLL_RIGHT: + changed = self->next_frame(); + break; + } + + if (changed) { + std::string window_title = self->get_title_text(); + gtk_window_set_title(GTK_WINDOW(self->_window), window_title.c_str()); + return TRUE; + } else { + return FALSE; + } +} + +/** + * + */ +gboolean GtkStatsFlameGraph:: +key_press_callback(GtkWidget *widget, GdkEventKey *event, gpointer data) { + GtkStatsFlameGraph *self = (GtkStatsFlameGraph *)data; + bool changed = false; + switch (event->keyval) { + case GDK_KEY_Left: + if (event->state & GDK_MOD1_MASK) { + changed = self->pop_collector_index(); + } else { + changed = self->prev_frame(); + } + break; + + case GDK_KEY_Right: + if ((event->state & GDK_MOD1_MASK) == 0) { + changed = self->next_frame(); + } + break; + + case GDK_KEY_Home: + if ((event->state & GDK_MOD1_MASK) == 0) { + changed = self->first_frame(); + } + break; + + case GDK_KEY_End: + if ((event->state & GDK_MOD1_MASK) == 0) { + changed = self->last_frame(); + } + break; + } + + if (changed) { + std::string window_title = self->get_title_text(); + gtk_window_set_title(GTK_WINDOW(self->_window), window_title.c_str()); + return TRUE; + } else { + return FALSE; + } +} diff --git a/pandatool/src/gtk-stats/gtkStatsFlameGraph.h b/pandatool/src/gtk-stats/gtkStatsFlameGraph.h index eb2eb5e5e4a..1381ca801fb 100644 --- a/pandatool/src/gtk-stats/gtkStatsFlameGraph.h +++ b/pandatool/src/gtk-stats/gtkStatsFlameGraph.h @@ -28,7 +28,7 @@ class GtkStatsLabel; class GtkStatsFlameGraph final : public PStatFlameGraph, public GtkStatsGraph { public: GtkStatsFlameGraph(GtkStatsMonitor *monitor, int thread_index, - int collector_index=-1); + int collector_index=-1, int frame_number=-1); virtual ~GtkStatsFlameGraph(); virtual void new_collector(int collector_index); @@ -76,6 +76,8 @@ class GtkStatsFlameGraph final : public PStatFlameGraph, public GtkStatsGraph { static void toggled_callback(GtkToggleButton *button, gpointer data); static gboolean draw_callback(GtkWidget *widget, cairo_t *cr, gpointer data); + static gboolean scroll_callback(GtkWidget *widget, GdkEventScroll *event, gpointer data); + static gboolean key_press_callback(GtkWidget *widget, GdkEventKey *event, gpointer data); private: std::string _net_value_text; diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.I b/pandatool/src/gtk-stats/gtkStatsMonitor.I index b3e8e55b138..867c4349fbe 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.I +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.I @@ -15,10 +15,12 @@ * */ INLINE GtkStatsMonitor::MenuDef:: -MenuDef(int thread_index, int collector_index, ChartType chart_type, bool show_level) : +MenuDef(ChartType chart_type, int thread_index, int collector_index, + int frame_number, bool show_level) : + _chart_type(chart_type), _thread_index(thread_index), _collector_index(collector_index), - _chart_type(chart_type), + _frame_number(frame_number), _show_level(show_level), _monitor(nullptr) { @@ -29,14 +31,17 @@ MenuDef(int thread_index, int collector_index, ChartType chart_type, bool show_l */ INLINE bool GtkStatsMonitor::MenuDef:: operator < (const MenuDef &other) const { + if (_chart_type != other._chart_type) { + return _chart_type < other._chart_type; + } if (_thread_index != other._thread_index) { return _thread_index < other._thread_index; } if (_collector_index != other._collector_index) { return _collector_index < other._collector_index; } - if (_chart_type != other._chart_type) { - return _chart_type < other._chart_type; + if (_frame_number != other._frame_number) { + return _frame_number < other._frame_number; } return (int)_show_level < (int)other._show_level; } diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx index 0410504457b..2be16d94349 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.cxx +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.cxx @@ -316,8 +316,8 @@ open_timeline() { * Opens a new flame graph showing the indicated data. */ PStatGraph *GtkStatsMonitor:: -open_flame_graph(int thread_index, int collector_index) { - GtkStatsFlameGraph *graph = new GtkStatsFlameGraph(this, thread_index, collector_index); +open_flame_graph(int thread_index, int collector_index, int frame_number) { + GtkStatsFlameGraph *graph = new GtkStatsFlameGraph(this, thread_index, collector_index, frame_number); add_graph(graph); return graph; } @@ -734,7 +734,7 @@ status_bar_button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) const PStatViewLevel *child_level = view_level->get_child(c); int child_collector = child_level->get_collector(); - const MenuDef *menu_def = monitor->add_menu({0, child_collector, CT_strip_chart, true}); + const MenuDef *menu_def = monitor->add_menu({CT_strip_chart, 0, child_collector, -1, true}); double value = child_level->get_net_value(); @@ -787,7 +787,8 @@ menu_activate(GtkWidget *widget, gpointer data) { case CT_flame_graph: monitor->open_flame_graph(menu_def._thread_index, - menu_def._collector_index); + menu_def._collector_index, + menu_def._frame_number); break; case CT_piano_roll: @@ -853,7 +854,7 @@ handle_status_bar_popup(int item) { const PStatViewLevel *child_level = view_level->get_child(c); int child_collector = child_level->get_collector(); - const MenuDef *menu_def = add_menu({0, child_collector, CT_strip_chart, true}); + const MenuDef *menu_def = add_menu({CT_strip_chart, 0, child_collector, -1, true}); double value = child_level->get_net_value(); diff --git a/pandatool/src/gtk-stats/gtkStatsMonitor.h b/pandatool/src/gtk-stats/gtkStatsMonitor.h index 6a6c1e091ff..3ac15abad5a 100644 --- a/pandatool/src/gtk-stats/gtkStatsMonitor.h +++ b/pandatool/src/gtk-stats/gtkStatsMonitor.h @@ -46,13 +46,14 @@ class GtkStatsMonitor : public PStatMonitor { class MenuDef { public: - INLINE MenuDef(int thread_index, int collector_index, - ChartType chart_type, bool show_level = false); + INLINE MenuDef(ChartType chart_type, int thread_index, int collector_index, + int frame_number = -1, bool show_level = false); INLINE bool operator < (const MenuDef &other) const; + ChartType _chart_type; int _thread_index; int _collector_index; - ChartType _chart_type; + int _frame_number; bool _show_level; GtkStatsMonitor *_monitor; }; @@ -84,7 +85,7 @@ class GtkStatsMonitor : public PStatMonitor { PStatGraph *open_timeline(); PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); PStatGraph *open_piano_roll(int thread_index); void choose_collector_color(int collector_index); diff --git a/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx b/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx index fbab6cb1ef5..da5e6b36946 100644 --- a/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx +++ b/pandatool/src/gtk-stats/gtkStatsPianoRoll.cxx @@ -149,7 +149,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, GtkStatsMonitor::CT_strip_chart, false, + GtkStatsMonitor::CT_strip_chart, _thread_index, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -161,7 +161,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, GtkStatsMonitor::CT_flame_graph, + GtkStatsMonitor::CT_flame_graph, _thread_index, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -178,7 +178,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -190,7 +190,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); diff --git a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx index f956cdfa9a0..0be191da40b 100644 --- a/pandatool/src/gtk-stats/gtkStatsStripChart.cxx +++ b/pandatool/src/gtk-stats/gtkStatsStripChart.cxx @@ -243,8 +243,8 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, - GtkStatsMonitor::CT_strip_chart, get_view().get_show_level(), + GtkStatsMonitor::CT_strip_chart, _thread_index, collector_index, -1, + get_view().get_show_level(), }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -256,7 +256,7 @@ on_popup_label(int collector_index) { if (!get_view().get_show_level()) { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - _thread_index, collector_index, GtkStatsMonitor::CT_flame_graph, + GtkStatsMonitor::CT_flame_graph, _thread_index, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -273,7 +273,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -285,7 +285,7 @@ on_popup_label(int collector_index) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, collector_index, GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); diff --git a/pandatool/src/gtk-stats/gtkStatsTimeline.cxx b/pandatool/src/gtk-stats/gtkStatsTimeline.cxx index a58100f637f..5010b2dabc3 100644 --- a/pandatool/src/gtk-stats/gtkStatsTimeline.cxx +++ b/pandatool/src/gtk-stats/gtkStatsTimeline.cxx @@ -409,8 +409,8 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ + GtkStatsMonitor::CT_strip_chart, bar._thread_index, bar._collector_index, - GtkStatsMonitor::CT_strip_chart, false, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Strip Chart"); @@ -422,8 +422,8 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - bar._thread_index, bar._collector_index, GtkStatsMonitor::CT_flame_graph, + bar._thread_index, bar._collector_index, bar._frame_number, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Flame Graph"); @@ -435,7 +435,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - bar._thread_index, -1, GtkStatsMonitor::CT_piano_roll, + GtkStatsMonitor::CT_piano_roll, bar._thread_index, -1, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Open Piano Roll"); @@ -452,8 +452,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, bar._collector_index, - GtkStatsMonitor::CT_choose_color, + GtkStatsMonitor::CT_choose_color, -1, bar._collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Change Color..."); @@ -465,8 +464,7 @@ handle_button_press(int graph_x, int graph_y, bool double_click, int button) { { const GtkStatsMonitor::MenuDef *menu_def = GtkStatsGraph::_monitor->add_menu({ - -1, bar._collector_index, - GtkStatsMonitor::CT_reset_color, + GtkStatsMonitor::CT_reset_color, -1, bar._collector_index, }); GtkWidget *menu_item = gtk_menu_item_new_with_label("Reset Color"); diff --git a/pandatool/src/imageprogs/CMakeLists.txt b/pandatool/src/imageprogs/CMakeLists.txt index f39b4b90fb5..e91d4c69659 100644 --- a/pandatool/src/imageprogs/CMakeLists.txt +++ b/pandatool/src/imageprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(image-fix-hidden-color imageFixHiddenColor.cxx imageFixHiddenColor.h) target_link_libraries(image-fix-hidden-color p3imagebase) install(TARGETS image-fix-hidden-color EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/pandatool/src/imageprogs/imageFixHiddenColor.cxx b/pandatool/src/imageprogs/imageFixHiddenColor.cxx index a3d176bfb4c..44d1c91aafa 100644 --- a/pandatool/src/imageprogs/imageFixHiddenColor.cxx +++ b/pandatool/src/imageprogs/imageFixHiddenColor.cxx @@ -104,7 +104,7 @@ run() { // First, get the average color of all the opaque pixels. int count = 0; - LRGBColor color(0.0, 0.0, 0.0); + LRGBColorf color(0.0, 0.0, 0.0); int xi, yi; for (yi = 0; yi < _image.get_y_size(); ++yi) { for (xi = 0; xi < _image.get_x_size(); ++xi) { diff --git a/pandatool/src/lwoprogs/CMakeLists.txt b/pandatool/src/lwoprogs/CMakeLists.txt index 0a3c1de2e52..39210c50d07 100644 --- a/pandatool/src/lwoprogs/CMakeLists.txt +++ b/pandatool/src/lwoprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(lwo-scan lwoScan.cxx lwoScan.h) target_link_libraries(lwo-scan p3progbase p3lwo) install(TARGETS lwo-scan EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/pandatool/src/mac-stats/CMakeLists.txt b/pandatool/src/mac-stats/CMakeLists.txt index bb56cd07718..23c54ef9bca 100644 --- a/pandatool/src/mac-stats/CMakeLists.txt +++ b/pandatool/src/mac-stats/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT APPLE OR NOT HAVE_NET) return() endif() diff --git a/pandatool/src/mac-stats/macStatsFlameGraph.h b/pandatool/src/mac-stats/macStatsFlameGraph.h index 25df1f96c84..a678e887ba5 100644 --- a/pandatool/src/mac-stats/macStatsFlameGraph.h +++ b/pandatool/src/mac-stats/macStatsFlameGraph.h @@ -25,7 +25,7 @@ class MacStatsFlameGraph final : public PStatFlameGraph, public MacStatsGraph { public: MacStatsFlameGraph(MacStatsMonitor *monitor, int thread_index, - int collector_index=-1); + int collector_index=-1, int frame_number=-1); virtual ~MacStatsFlameGraph(); virtual void new_collector(int collector_index); @@ -60,11 +60,14 @@ class MacStatsFlameGraph final : public PStatFlameGraph, public MacStatsGraph { virtual std::string get_graph_tooltip(int mouse_x, int mouse_y) const; virtual DragMode consider_drag_start(int graph_x, int graph_y); + virtual bool handle_key(int graph_x, int graph_y, bool pressed, + UniChar c, unsigned short key_code); virtual void handle_button_press(int graph_x, int graph_y, - bool double_click, int button); + bool double_click, int button); virtual void handle_button_release(int graph_x, int graph_y); virtual void handle_motion(int graph_x, int graph_y); virtual void handle_leave(); + virtual void handle_wheel(int graph_x, int graph_y, double dx, double dy); virtual void handle_draw_graph(CGContextRef ctx, NSRect rect); virtual void handle_back(); @@ -81,8 +84,6 @@ class MacStatsFlameGraph final : public PStatFlameGraph, public MacStatsGraph { NSToolbarItem *_total_item; MacStatsChartMenuDelegate *_menu_delegate; - - std::vector _back_stack; }; #endif diff --git a/pandatool/src/mac-stats/macStatsFlameGraph.mm b/pandatool/src/mac-stats/macStatsFlameGraph.mm index 60314147f8a..003629d474b 100644 --- a/pandatool/src/mac-stats/macStatsFlameGraph.mm +++ b/pandatool/src/mac-stats/macStatsFlameGraph.mm @@ -29,8 +29,8 @@ @interface MacStatsFlameGraphViewController : MacStatsGraphViewController */ MacStatsFlameGraph:: MacStatsFlameGraph(MacStatsMonitor *monitor, int thread_index, - int collector_index) : - PStatFlameGraph(monitor, thread_index, collector_index, 0, 0), + int collector_index, int frame_number) : + PStatFlameGraph(monitor, thread_index, collector_index, frame_number, 0, 0), MacStatsGraph(monitor, [MacStatsFlameGraphViewController alloc]) { // Used for popup menus. @@ -177,11 +177,10 @@ @interface MacStatsFlameGraphViewController : MacStatsGraphViewController on_click_label(int collector_index) { int current = get_collector_index(); if (collector_index != current) { - if (_back_stack.empty()) { + if (get_history_depth() == 0) { _graph_view_controller.backToolbarItemVisible = YES; } - _back_stack.push_back(current); - set_collector_index(collector_index); + push_collector_index(collector_index); std::string window_title = get_title_text(); if (!is_title_unknown()) { @@ -538,6 +537,43 @@ @interface MacStatsFlameGraphViewController : MacStatsGraphViewController return DM_none; } +/** + * + */ +bool MacStatsFlameGraph:: +handle_key(int graph_x, int graph_y, bool pressed, UniChar c, unsigned short key_code) { + bool changed = false; + + if (pressed) { + switch (c) { + case NSLeftArrowFunctionKey: + changed = prev_frame(); + break; + + case NSRightArrowFunctionKey: + changed = next_frame(); + break; + + case NSHomeFunctionKey: + changed = first_frame(); + break; + + case NSEndFunctionKey: + changed = last_frame(); + break; + } + } + + if (changed) { + std::string window_title = get_title_text(); + if (!is_title_unknown()) { + _window.title = [NSString stringWithUTF8String:window_title.c_str()]; + } + } + + return changed; +} + /** * Called when the mouse button is depressed within the graph window. */ @@ -552,11 +588,12 @@ @interface MacStatsFlameGraphViewController : MacStatsGraphViewController if (collector_index >= 0) { on_click_label(collector_index); } else { - if (!_back_stack.empty()) { - _back_stack.clear(); + if (get_history_depth() > 0) { + clear_history(); _graph_view_controller.backToolbarItemVisible = NO; } set_collector_index(-1); + std::string window_title = get_title_text(); if (!is_title_unknown()) { _window.title = [NSString stringWithUTF8String:window_title.c_str()]; @@ -652,6 +689,21 @@ @interface MacStatsFlameGraphViewController : MacStatsGraphViewController return; } +/** + * + */ +void MacStatsFlameGraph:: +handle_wheel(int graph_x, int graph_y, double dx, double dy) { + if (dx != 0.0) { + if ((dx > 0.0) ? prev_frame() : next_frame()) { + std::string window_title = get_title_text(); + if (!is_title_unknown()) { + _window.title = [NSString stringWithUTF8String:window_title.c_str()]; + } + } + } +} + /** * Fills in the graph window. */ @@ -674,12 +726,8 @@ @interface MacStatsFlameGraphViewController : MacStatsGraphViewController */ void MacStatsFlameGraph:: handle_back() { - if (!_back_stack.empty()) { - int collector_index = _back_stack.back(); - _back_stack.pop_back(); - set_collector_index(collector_index); - - if (_back_stack.empty()) { + if (pop_collector_index()) { + if (get_history_depth() == 0) { _graph_view_controller.backToolbarItemVisible = NO; } diff --git a/pandatool/src/mac-stats/macStatsGraphView.mm b/pandatool/src/mac-stats/macStatsGraphView.mm index 013b4241392..82b2d5d8e8e 100644 --- a/pandatool/src/mac-stats/macStatsGraphView.mm +++ b/pandatool/src/mac-stats/macStatsGraphView.mm @@ -45,15 +45,13 @@ - (BOOL)acceptsFirstResponder { } - (void)keyDown:(NSEvent *)event { - if (!event.isARepeat) { - NSPoint pos = [self convertPoint:event.locationInWindow fromView:nil]; - UniChar c = 0; - NSString *str = [event charactersIgnoringModifiers]; - if (str != nil && str.length == 1) { - c = [str characterAtIndex:0]; - } - _graph->handle_key(pos.x, pos.y, true, c, event.keyCode); + NSPoint pos = [self convertPoint:event.locationInWindow fromView:nil]; + UniChar c = 0; + NSString *str = [event charactersIgnoringModifiers]; + if (str != nil && str.length == 1) { + c = [str characterAtIndex:0]; } + _graph->handle_key(pos.x, pos.y, true, c, event.keyCode); } - (void)keyUp:(NSEvent *)event { diff --git a/pandatool/src/mac-stats/macStatsMonitor.h b/pandatool/src/mac-stats/macStatsMonitor.h index 8e12677963d..8c5d0c31640 100644 --- a/pandatool/src/mac-stats/macStatsMonitor.h +++ b/pandatool/src/mac-stats/macStatsMonitor.h @@ -57,7 +57,7 @@ class MacStatsMonitor : public PStatMonitor { PStatGraph *open_timeline(); PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); PStatGraph *open_piano_roll(int thread_index); CGColorRef get_collector_color(int collector_index, bool highlight = false); diff --git a/pandatool/src/mac-stats/macStatsMonitor.mm b/pandatool/src/mac-stats/macStatsMonitor.mm index 7d001e39a58..57245e0208e 100644 --- a/pandatool/src/mac-stats/macStatsMonitor.mm +++ b/pandatool/src/mac-stats/macStatsMonitor.mm @@ -312,9 +312,9 @@ * Opens a new flame graph showing the indicated data. */ PStatGraph *MacStatsMonitor:: -open_flame_graph(int thread_index, int collector_index) { +open_flame_graph(int thread_index, int collector_index, int frame_number) { MacStatsFlameGraph *graph = - new MacStatsFlameGraph(this, thread_index, collector_index); + new MacStatsFlameGraph(this, thread_index, collector_index, frame_number); add_graph(graph); return graph; } diff --git a/pandatool/src/mac-stats/macStatsTimeline.mm b/pandatool/src/mac-stats/macStatsTimeline.mm index 464edde12d3..85f5c89e308 100644 --- a/pandatool/src/mac-stats/macStatsTimeline.mm +++ b/pandatool/src/mac-stats/macStatsTimeline.mm @@ -819,7 +819,7 @@ @interface MacStatsTimelineViewController : MacStatsScrollableGraphViewControlle void MacStatsTimeline:: handle_open_flame_graph() { const ColorBar &bar = _popup_bar; - MacStatsGraph::_monitor->open_flame_graph(bar._thread_index, bar._collector_index); + MacStatsGraph::_monitor->open_flame_graph(bar._thread_index, bar._collector_index, bar._frame_number); } /** diff --git a/pandatool/src/maxegg/maxEgg.cxx b/pandatool/src/maxegg/maxEgg.cxx deleted file mode 100644 index 798192e26c4..00000000000 --- a/pandatool/src/maxegg/maxEgg.cxx +++ /dev/null @@ -1,860 +0,0 @@ -/** - * @file maxEgg.cxx - * @author Steven "Sauce" Osman - * @date 2003-01 - * @author Ken Strickland - * @date 2003-02-25 - * - * This file implements the classes that are used in the Panda 3D file - * exporter for 3D Studio Max. - */ - -#include "maxEgg.h" - - -const double meshVerts[252][3] = { - {0.729464, -0.919852, 0.714986}, - {0.466137, -0.594656, 0.160201}, - {-0.265897, -1.14704, 0.714986}, - {0.466137, -0.594656, 0.160201}, - {-0.177333, -0.741523, 0.160201}, - {-0.265897, -1.14704, 0.714986}, - {-0.265897, -1.14704, 0.714986}, - {-0.177333, -0.741523, 0.160201}, - {-1.06411, -0.510479, 0.714986}, - {-0.177333, -0.741523, 0.160201}, - {-0.693356, -0.330009, 0.160201}, - {-1.06411, -0.510479, 0.714986}, - {-1.06411, 0.510479, 0.714986}, - {-1.06411, -0.510479, 0.714986}, - {-0.693356, 0.330009, 0.160201}, - {-0.693356, -0.330009, 0.160201}, - {-0.693356, 0.330009, 0.160201}, - {-1.06411, -0.510479, 0.714986}, - {-0.265897, 1.14704, 0.714986}, - {-1.06411, 0.510479, 0.714986}, - {-0.177333, 0.741523, 0.160201}, - {-0.693356, 0.330009, 0.160201}, - {-0.177333, 0.741523, 0.160201}, - {-1.06411, 0.510479, 0.714986}, - {0.729464, 0.919852, 0.714986}, - {-0.265897, 1.14704, 0.714986}, - {0.466137, 0.594656, 0.160201}, - {-0.177333, 0.741523, 0.160201}, - {0.466137, 0.594656, 0.160201}, - {-0.265897, 1.14704, 0.714986}, - {1.17244, 0.0, 0.714986}, - {0.729464, 0.919852, 0.714986}, - {0.752508, 0.0, 0.160201}, - {0.466137, 0.594656, 0.160201}, - {0.752508, 0.0, 0.160201}, - {0.729464, 0.919852, 0.714986}, - {0.729464, -0.919852, 0.714986}, - {1.17244, 0.0, 0.714986}, - {0.466137, -0.594656, 0.160201}, - {0.752508, 0.0, 0.160201}, - {0.466137, -0.594656, 0.160201}, - {1.17244, 0.0, 0.714986}, - {-0.286334, -1.26822, 1.44995}, - {0.814187, -1.01703, 1.44995}, - {-0.265897, -1.14704, 0.714986}, - {0.729464, -0.919852, 0.714986}, - {-0.265897, -1.14704, 0.714986}, - {0.814187, -1.01703, 1.44995}, - {-1.16888, -0.564412, 1.44995}, - {-0.286334, -1.26822, 1.44995}, - {-1.06411, -0.510479, 0.714986}, - {-0.265897, -1.14704, 0.714986}, - {-1.06411, -0.510479, 0.714986}, - {-0.286334, -1.26822, 1.44995}, - {-1.16888, 0.564411, 1.44995}, - {-1.16888, -0.564412, 1.44995}, - {-1.06411, 0.510479, 0.714986}, - {-1.06411, -0.510479, 0.714986}, - {-1.06411, 0.510479, 0.714986}, - {-1.16888, -0.564412, 1.44995}, - {-1.16888, 0.564411, 1.44995}, - {-1.06411, 0.510479, 0.714986}, - {-0.286334, 1.26822, 1.44995}, - {-1.06411, 0.510479, 0.714986}, - {-0.265897, 1.14704, 0.714986}, - {-0.286334, 1.26822, 1.44995}, - {-0.286334, 1.26822, 1.44995}, - {-0.265897, 1.14704, 0.714986}, - {0.814187, 1.01703, 1.44995}, - {-0.265897, 1.14704, 0.714986}, - {0.729464, 0.919852, 0.714986}, - {0.814187, 1.01703, 1.44995}, - {1.30396, 0.0, 1.44995}, - {0.814187, 1.01703, 1.44995}, - {1.17244, 0.0, 0.714986}, - {0.729464, 0.919852, 0.714986}, - {1.17244, 0.0, 0.714986}, - {0.814187, 1.01703, 1.44995}, - {1.30396, 0.0, 1.44995}, - {1.17244, 0.0, 0.714986}, - {0.814187, -1.01703, 1.44995}, - {1.17244, 0.0, 0.714986}, - {0.729464, -0.919852, 0.714986}, - {0.814187, -1.01703, 1.44995}, - {-0.286334, -1.26822, 1.44995}, - {-0.227573, -1.05763, 2.16723}, - {0.814187, -1.01703, 1.44995}, - {0.814187, -1.01703, 1.44995}, - {-0.227573, -1.05763, 2.16723}, - {0.690208, -0.848157, 2.16723}, - {-1.16888, -0.564412, 1.44995}, - {-0.963577, -0.470692, 2.16723}, - {-0.286334, -1.26822, 1.44995}, - {-0.286334, -1.26822, 1.44995}, - {-0.963577, -0.470692, 2.16723}, - {-0.227573, -1.05763, 2.16723}, - {-1.16888, -0.564412, 1.44995}, - {-1.16888, 0.564411, 1.44995}, - {-0.963577, -0.470692, 2.16723}, - {-1.16888, 0.564411, 1.44995}, - {-0.963577, 0.470692, 2.16723}, - {-0.963577, -0.470692, 2.16723}, - {-1.16888, 0.564411, 1.44995}, - {-0.286334, 1.26822, 1.44995}, - {-0.963577, 0.470692, 2.16723}, - {-0.286334, 1.26822, 1.44995}, - {-0.227574, 1.05763, 2.16723}, - {-0.963577, 0.470692, 2.16723}, - {-0.286334, 1.26822, 1.44995}, - {0.814187, 1.01703, 1.44995}, - {-0.227574, 1.05763, 2.16723}, - {0.814187, 1.01703, 1.44995}, - {0.690208, 0.848157, 2.16723}, - {-0.227574, 1.05763, 2.16723}, - {0.814187, 1.01703, 1.44995}, - {1.30396, 0.0, 1.44995}, - {0.690208, 0.848157, 2.16723}, - {1.30396, 0.0, 1.44995}, - {1.09866, 0.0, 2.16723}, - {0.690208, 0.848157, 2.16723}, - {0.814187, -1.01703, 1.44995}, - {0.690208, -0.848157, 2.16723}, - {1.30396, 0.0, 1.44995}, - {1.30396, 0.0, 1.44995}, - {0.690208, -0.848157, 2.16723}, - {1.09866, 0.0, 2.16723}, - {-0.227573, -1.05763, 2.16723}, - {-0.154893, -0.759032, 2.72566}, - {0.690208, -0.848157, 2.16723}, - {0.690208, -0.848157, 2.16723}, - {-0.154893, -0.759032, 2.72566}, - {0.50377, -0.608696, 2.72566}, - {-0.963577, -0.470692, 2.16723}, - {-0.683099, -0.337801, 2.72566}, - {-0.227573, -1.05763, 2.16723}, - {-0.227573, -1.05763, 2.16723}, - {-0.683099, -0.337801, 2.72566}, - {-0.154893, -0.759032, 2.72566}, - {-0.963577, -0.470692, 2.16723}, - {-0.963577, 0.470692, 2.16723}, - {-0.683099, -0.337801, 2.72566}, - {-0.963577, 0.470692, 2.16723}, - {-0.683099, 0.337801, 2.72566}, - {-0.683099, -0.337801, 2.72566}, - {-0.963577, 0.470692, 2.16723}, - {-0.227574, 1.05763, 2.16723}, - {-0.683099, 0.337801, 2.72566}, - {-0.227574, 1.05763, 2.16723}, - {-0.154893, 0.759032, 2.72566}, - {-0.683099, 0.337801, 2.72566}, - {-0.227574, 1.05763, 2.16723}, - {0.690208, 0.848157, 2.16723}, - {-0.154893, 0.759032, 2.72566}, - {0.690208, 0.848157, 2.16723}, - {0.50377, 0.608696, 2.72566}, - {-0.154893, 0.759032, 2.72566}, - {0.690208, 0.848157, 2.16723}, - {1.09866, 0.0, 2.16723}, - {0.50377, 0.608696, 2.72566}, - {1.09866, 0.0, 2.16723}, - {0.796903, 0.0, 2.72566}, - {0.50377, 0.608696, 2.72566}, - {1.09866, 0.0, 2.16723}, - {0.690208, -0.848157, 2.16723}, - {0.796903, 0.0, 2.72566}, - {0.690208, -0.848157, 2.16723}, - {0.50377, -0.608696, 2.72566}, - {0.796903, 0.0, 2.72566}, - {0.50377, -0.608696, 2.72566}, - {-0.154893, -0.759032, 2.72566}, - {0.259722, -0.299638, 3.11175}, - {-0.154893, -0.759032, 2.72566}, - {-0.0645132, -0.373643, 3.11175}, - {0.259722, -0.299638, 3.11175}, - {-0.154893, -0.759032, 2.72566}, - {-0.683099, -0.337801, 2.72566}, - {-0.0645132, -0.373643, 3.11175}, - {-0.683099, -0.337801, 2.72566}, - {-0.324529, -0.166287, 3.11175}, - {-0.0645132, -0.373643, 3.11175}, - {-0.683099, -0.337801, 2.72566}, - {-0.683099, 0.337801, 2.72566}, - {-0.324529, -0.166287, 3.11175}, - {-0.683099, 0.337801, 2.72566}, - {-0.324529, 0.166287, 3.11175}, - {-0.324529, -0.166287, 3.11175}, - {-0.683099, 0.337801, 2.72566}, - {-0.154893, 0.759032, 2.72566}, - {-0.324529, 0.166287, 3.11175}, - {-0.154893, 0.759032, 2.72566}, - {-0.0645132, 0.373642, 3.11175}, - {-0.324529, 0.166287, 3.11175}, - {-0.154893, 0.759032, 2.72566}, - {0.50377, 0.608696, 2.72566}, - {-0.0645132, 0.373642, 3.11175}, - {0.50377, 0.608696, 2.72566}, - {0.259722, 0.299638, 3.11175}, - {-0.0645132, 0.373642, 3.11175}, - {0.50377, 0.608696, 2.72566}, - {0.796903, 0.0, 2.72566}, - {0.259722, 0.299638, 3.11175}, - {0.796903, 0.0, 2.72566}, - {0.40402, 0.0, 3.11175}, - {0.259722, 0.299638, 3.11175}, - {0.796903, 0.0, 2.72566}, - {0.50377, -0.608696, 2.72566}, - {0.40402, 0.0, 3.11175}, - {0.50377, -0.608696, 2.72566}, - {0.259722, -0.299638, 3.11175}, - {0.40402, 0.0, 3.11175}, - {-0.177333, -0.741523, 0.160201}, - {0.466137, -0.594656, 0.160201}, - {-0.00334214, 0.0, 0.00443203}, - {-0.693356, -0.330009, 0.160201}, - {-0.177333, -0.741523, 0.160201}, - {-0.00334214, 0.0, 0.00443203}, - {-0.693356, 0.330009, 0.160201}, - {-0.693356, -0.330009, 0.160201}, - {-0.00334214, 0.0, 0.00443203}, - {-0.177333, 0.741523, 0.160201}, - {-0.693356, 0.330009, 0.160201}, - {-0.00334214, 0.0, 0.00443203}, - {0.466137, 0.594656, 0.160201}, - {-0.177333, 0.741523, 0.160201}, - {-0.00334214, 0.0, 0.00443203}, - {0.752508, 0.0, 0.160201}, - {0.466137, 0.594656, 0.160201}, - {-0.00334214, 0.0, 0.00443203}, - {0.466137, -0.594656, 0.160201}, - {0.752508, 0.0, 0.160201}, - {-0.00334214, 0.0, 0.00443203}, - {0.259722, -0.299638, 3.11175}, - {-0.0645132, -0.373643, 3.11175}, - {0.0207683, 0.0, 3.20912}, - {-0.0645132, -0.373643, 3.11175}, - {-0.324529, -0.166287, 3.11175}, - {0.0207683, 0.0, 3.20912}, - {-0.324529, -0.166287, 3.11175}, - {-0.324529, 0.166287, 3.11175}, - {0.0207683, 0.0, 3.20912}, - {-0.324529, 0.166287, 3.11175}, - {-0.0645132, 0.373642, 3.11175}, - {0.0207683, 0.0, 3.20912}, - {-0.0645132, 0.373642, 3.11175}, - {0.259722, 0.299638, 3.11175}, - {0.0207683, 0.0, 3.20912}, - {0.259722, 0.299638, 3.11175}, - {0.40402, 0.0, 3.11175}, - {0.0207683, 0.0, 3.20912}, - {0.40402, 0.0, 3.11175}, - {0.259722, -0.299638, 3.11175}, - {0.0207683, 0.0, 3.20912} -}; - - -// Disable the forcing int to true or false performance warning -#pragma warning(disable: 4800) - -/* MaxEggPluginClassDesc - A class that describes 3DS Plugin support. - This basically says "Yes, I am a helper object!" -*/ - -class MaxEggPluginClassDesc : public ClassDesc -{ -public: - int IsPublic() { return TRUE; } - void *Create(BOOL loading = FALSE) { return new MaxEggPlugin(); } - const TCHAR *ClassName() { return GetString(IDS_CLASS_NAME); } - SClass_ID SuperClassID() { return HELPER_CLASS_ID; } - Class_ID ClassID() { return MaxEggPlugin_CLASS_ID; } - const TCHAR *Category() { return GetString(IDS_CATEGORY); } - // returns fixed parsable name (scripter-visible name) - const TCHAR *InternalName() { return _T("MaxEggPlugin"); } -}; - -// Our private global instance of the above class -static MaxEggPluginClassDesc MaxEggPluginDesc; - -// Called by LibClassDesc to find out what the plugin is -ClassDesc* GetMaxEggPluginDesc() { return &MaxEggPluginDesc; } - -// Initialize class-static variables -Mesh MaxEggPlugin::mesh; -short MaxEggPlugin::meshBuilt=0; -HWND MaxEggPlugin::hMaxEggParams = nullptr; -IObjParam *MaxEggPlugin::iObjParams; - -/* MaxEggPluginOptionsDlgProc() - This is the callback function for the - dialog box that appears at the beginning of the conversion process. - */ - -INT_PTR CALLBACK MaxEggPluginOptionsDlgProc( HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam ) -{ - MaxOptionsDialog *tempEgg; - int sel, res; - - // We pass in our plugin through the lParam variable. Let's convert it - // back. - MaxEggPlugin *imp = (MaxEggPlugin*)GetWindowLongPtr(hWnd,GWLP_USERDATA); - if ( !imp && message != WM_INITDIALOG ) return FALSE; - - switch(message) - { - // When we start, center the window. - case WM_INITDIALOG: - // this line is very necessary to pass the plugin as the lParam - SetWindowLongPtr(hWnd,GWLP_USERDATA,lParam); - SetDlgFont( hWnd, imp->iObjParams->GetAppHFont() ); - MaxEggPlugin::hMaxEggParams = hWnd; - return TRUE; break; - - case WM_MOUSEACTIVATE: - imp->iObjParams->RealizeParamPanel(); - return TRUE; break; - - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MOUSEMOVE: - imp->iObjParams->RollupMouseMessage(hWnd,message,wParam,lParam); - return TRUE; break; - - // A control was modified - case WM_COMMAND: - // The modified control is found in the lower word of the wParam long. - switch( LOWORD(wParam) ) { - case IDC_OVERWRITE_CHECK: - imp->autoOverwrite = - (IsDlgButtonChecked(hWnd, IDC_OVERWRITE_CHECK) == BST_CHECKED); - return TRUE; break; - case IDC_PVIEW_CHECK: - imp->pview = - (IsDlgButtonChecked(hWnd, IDC_PVIEW_CHECK) == BST_CHECKED); - return TRUE; break; - case IDC_LOGGING: - imp->logOutput = - (IsDlgButtonChecked(hWnd, IDC_LOGGING) == BST_CHECKED); - return TRUE; break; - case IDC_ADD_EGG: - tempEgg = new MaxOptionsDialog(); - tempEgg->SetMaxInterface(imp->iObjParams); - tempEgg->SetAnimRange(); - res = DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EGG_DETAILS), - hWnd, MaxOptionsDialogProc, (LPARAM)tempEgg); - if (res == TRUE) { - imp->SaveCheckState(); - imp->AddEgg(tempEgg); - imp->UpdateUI(); - } - else delete tempEgg; - return TRUE; break; - case IDC_EDIT_EGG: - sel = ListView_GetSelectionMark(GetDlgItem(hWnd, IDC_LIST_EGGS)); - if (sel != -1) { - MaxOptionsDialog *tempEgg = imp->GetEgg(sel); - if (tempEgg) { - tempEgg->SetAnimRange(); - tempEgg->CullBadNodes(); - DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EGG_DETAILS), - hWnd, MaxOptionsDialogProc, (LPARAM)tempEgg); - } - imp->SaveCheckState(); - imp->UpdateUI(); - } - return TRUE; break; - case IDC_REMOVE_EGG: - sel = ListView_GetSelectionMark(GetDlgItem(hWnd, IDC_LIST_EGGS)); - if (sel != -1) { - imp->SaveCheckState(); - imp->RemoveEgg(sel); - imp->UpdateUI(); - } - return TRUE; break; - case IDC_EXPORT: - imp->DoExport(); - return TRUE; break; - } - } - return FALSE; -} - -MaxEggPlugin::MaxEggPlugin() : -autoOverwrite(false), pview(true), logOutput(false), numEggs(0), maxEggs(5) -{ - eggList = new MaxOptionsDialog*[maxEggs]; - BuildMesh(); -} - -MaxEggPlugin::~MaxEggPlugin() { - for (int i = 0; i < numEggs; i++) delete eggList[i]; - delete [] eggList; -} - -void MaxEggPlugin::AddEgg(MaxOptionsDialog *newEgg) { - if (numEggs >= maxEggs) { - MaxOptionsDialog **newList; - maxEggs *= 2; - newList = new MaxOptionsDialog*[maxEggs]; - for (int i = 0; i < numEggs; i++) newList[i] = eggList[i]; - delete [] eggList; - eggList = newList; - } - - eggList[numEggs++] = newEgg; -} - -void MaxEggPlugin::RemoveEgg(int i) { - if (i >= 0 && i < numEggs) { - delete eggList[i]; - for (int j = i+1; j < numEggs;) eggList[i++] = eggList[j++]; - --numEggs; - } -} - -void MaxEggPlugin::BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev ) -{ - iObjParams = ip; - for (int i=0; iSetMaxInterface(ip); - } - - if ( !hMaxEggParams ) { - hMaxEggParams = ip->AddRollupPage(hInstance, - MAKEINTRESOURCE(IDD_PANEL), - MaxEggPluginOptionsDlgProc, - GetString(IDS_PARAMS), - (LPARAM)this ); - ip->RegisterDlgWnd(hMaxEggParams); - } else { - SetWindowLongPtr( hMaxEggParams, GWLP_USERDATA, (LPARAM)this ); - } - - UpdateUI(); -} - -void MaxEggPlugin::EndEditParams( IObjParam *ip, ULONG flags,Animatable *prev) -{ - SaveCheckState(); - if ( flags&END_EDIT_REMOVEUI ) { - ip->UnRegisterDlgWnd(hMaxEggParams); - ip->DeleteRollupPage(hMaxEggParams); - hMaxEggParams = nullptr; - } else { - SetWindowLongPtr( hMaxEggParams, GWLP_USERDATA, 0L ); - } -} - -void MaxEggPlugin::SaveCheckState() { - if (!hMaxEggParams) return; - HWND lv = GetDlgItem(hMaxEggParams, IDC_LIST_EGGS); - for (int i = 0; i < numEggs; i++) - eggList[i]->_checked = ListView_GetCheckState(lv, i); -} - -void MaxEggPlugin::UpdateUI() { - HWND lv = GetDlgItem(hMaxEggParams, IDC_LIST_EGGS); - LV_COLUMN pCol; - - if (ListView_GetColumnWidth(lv, 1) <= 0 || ListView_GetColumnWidth(lv, 1) > 10000) { - // Columns have not been setup, so initialize the control - ListView_SetExtendedListViewStyleEx(lv, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT, - LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT); - - pCol.fmt = LVCFMT_LEFT; - pCol.cx = 96; - pCol.pszText = _T("Filename"); - pCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; - pCol.iSubItem = 0; - ListView_InsertColumn(lv, 0, &pCol); - - pCol.cx = 44; - pCol.pszText = _T("Type"); - ListView_InsertColumn(lv, 1, &pCol); - } - - // Add the eggs to the list - ListView_DeleteAllItems(lv); - LV_ITEM Item; - Item.mask = LVIF_TEXT; - - for (int i = 0; i < numEggs; i++) { - Item.iItem = i; - Item.iSubItem = 0; - Item.pszText = eggList[i]->_short_name; - ListView_InsertItem(lv, &Item); - Item.iSubItem = 1; - switch(eggList[i]->_anim_type) { - case MaxEggOptions::AT_chan: Item.pszText = _T("Animation"); break; - case MaxEggOptions::AT_both: Item.pszText = _T("Both"); break; - case MaxEggOptions::AT_pose: Item.pszText = _T("Static"); break; - case MaxEggOptions::AT_model: Item.pszText = _T("Model"); break; - default: Item.pszText = _T("Model"); break; - } - ListView_SetItem(lv, &Item); - ListView_SetCheckState(lv, i, eggList[i]->_checked); - } - - // Set the "Overwrite Existing Files" and "Pview" checkboxes - CheckDlgButton(hMaxEggParams, IDC_OVERWRITE_CHECK, - autoOverwrite ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hMaxEggParams, IDC_PVIEW_CHECK, - pview ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hMaxEggParams, IDC_LOGGING, - logOutput ? BST_CHECKED : BST_UNCHECKED); -} - -void MaxEggPlugin::DoExport() { - int good = 0, bad = 0; - - std::basic_stringstream status; - - SaveCheckState(); - - for (int i = 0; i < numEggs; i++) { - if (eggList[i]->_checked) { - // If "auto overwrite" was not checked and the file exists, ask if - // the user wishes to overwrite the file - bool do_write = true; - - if (!autoOverwrite && GetFileAttributes(eggList[i]->_file_name) != INVALID_FILE_ATTRIBUTES) { - TCHAR msg[1024]; - _stprintf(msg, _T("Overwrite file \"%s.egg\"?"), eggList[i]->_short_name); - do_write = (MessageBox(hMaxEggParams, msg, _T("Panda3D Exporter"), MB_YESNO | MB_ICONQUESTION) == IDYES); - } - if (do_write) { - MaxToEggConverter converter; - if (converter.convert((MaxEggOptions*)eggList[i])) { - good += 1; - status << _T("Successfully created ") << eggList[i]->_short_name << _T(".egg\n"); - } else { - bad += 1; - status << _T("Could not export ") << eggList[i]->_short_name << _T(".egg\n"); - } - } else { - bad += 1; - status << _T("Skipped file ") << eggList[i]->_short_name << _T(".egg\n"); - } - } - } - - UINT mask = MB_OK; - - if (good == 0 && bad == 0) { - mask |= MB_ICONEXCLAMATION; - MessageBox(hMaxEggParams, _T("Nothing to export!"), _T("Panda3D Export results"), mask); - } else { - if (bad > 0) mask |= MB_ICONEXCLAMATION; - else mask |= MB_ICONINFORMATION; - MessageBox(hMaxEggParams, status.str().c_str(), _T("Panda3D Export results"), mask); - } - - int pviewed = 0; - if (pview && good > 0) { - for (i = 0; i < numEggs; i++) { - if (eggList[i]->_checked && eggList[i]->_successful) { - if (eggList[i]->_anim_type != MaxEggOptions::AT_chan) { - PROCESS_INFORMATION pi; - STARTUPINFO si; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - - TCHAR cmdLine[2048]; - // If we have just one model and animation file, pview - // them both - if (numEggs == 2 && eggList[i]->_anim_type == MaxEggOptions::AT_model && - eggList[1-i]->_checked && eggList[1-i]->_successful && - eggList[1-i]->_anim_type == MaxEggOptions::AT_chan) { - _stprintf(cmdLine, _T("pview \"%s\" \"%s\""), eggList[i]->_file_name, eggList[1-i]->_file_name); - } else { - _stprintf(cmdLine, _T("pview \"%s\""), eggList[i]->_file_name); - } - CreateProcess(nullptr, cmdLine, nullptr, nullptr, FALSE, CREATE_NEW_CONSOLE, - nullptr, nullptr, &si, &pi); - pviewed += 1; - } - } - } - } -} - - -void MaxEggPlugin::BuildMesh() -{ - int i; - if(meshBuilt) return; - - mesh.setNumVerts(252); - mesh.setNumFaces(84); - mesh.setSmoothFlags(0); - mesh.setNumTVerts (0); - mesh.setNumTVFaces (0); - - for (i=0; i<252; i++) - mesh.setVert(i, meshVerts[i][0]*10, meshVerts[i][1]*10, meshVerts[i][2]*10); - for (i=0; i<84; i++) { - mesh.faces[i].setEdgeVisFlags(1, 1, 0); - mesh.faces[i].setSmGroup(0); - mesh.faces[i].setVerts(i*3, i*3+1, i*3+2); - } - - mesh.InvalidateGeomCache(); - mesh.BuildStripsAndEdges(); - - meshBuilt = TRUE; -} - -// The creation callback - sets the initial position of the helper in the -// scene. - -class MaxEggPluginCreateMouseCallBack: public CreateMouseCallBack -{ -public: - int proc( ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ); -}; - -int MaxEggPluginCreateMouseCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) -{ - if (msg==MOUSE_POINT||msg==MOUSE_MOVE) { - switch(point) { - case 0: - mat.SetTrans(vpt->SnapPoint(m,m,nullptr,SNAP_IN_PLANE)); - break; - case 1: - mat.SetTrans(vpt->SnapPoint(m,m,nullptr,SNAP_IN_PLANE)); - if (msg==MOUSE_POINT) return CREATE_STOP; - break; - } - } else if (msg == MOUSE_ABORT) { - return CREATE_ABORT; - } - return CREATE_CONTINUE; -} - -static MaxEggPluginCreateMouseCallBack MaxEggCreateMouseCB; - -CreateMouseCallBack* MaxEggPlugin::GetCreateMouseCallBack() -{ return &MaxEggCreateMouseCB; } - -// Boilerplate functions for dealing with the display of the plugin - -void MaxEggPlugin::GetMat(TimeValue t, INode* inode, ViewExp* vpt, Matrix3& tm) -{ - tm = inode->GetObjectTM(t); - tm.NoScale(); - PN_stdfloat scaleFactor = vpt->NonScalingObjectSize()*vpt->GetVPWorldWidth(tm.GetTrans())/(PN_stdfloat)360.0; - tm.Scale(Point3(scaleFactor,scaleFactor,scaleFactor)); -} - -void MaxEggPlugin::GetDeformBBox(TimeValue t, Box3& box, Matrix3 *tm, BOOL useSel ) -{ - box = mesh.getBoundingBox(tm); -} - -void MaxEggPlugin::GetLocalBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box ) -{ - Matrix3 m = inode->GetObjectTM(t); - Point3 pt; - Point3 q[4]; - PN_stdfloat scaleFactor = vpt->GetVPWorldWidth(m.GetTrans())/360.0f; - box = mesh.getBoundingBox(); - box.Scale(scaleFactor); -} - -void MaxEggPlugin::GetWorldBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box ) -{ - int i, nv; Matrix3 tm; Point3 pt; - GetMat(t,inode,vpt,tm); - nv = mesh.getNumVerts(); - box.Init(); - for (i=0; igetGW(); - Material *mtl = gw->getMaterial(); - MakeHitRegion(hitRegion,type,crossing,4,p); - gw->setRndLimits(((savedLimits = gw->getRndLimits()) | GW_PICK) & ~GW_ILLUM); - GetMat(t,inode,vpt,m); - gw->setTransform(m); - gw->clearHitCode(); - if (mesh.select( gw, mtl, &hitRegion, flags & HIT_ABORTONHIT )) - return TRUE; - return FALSE; -} - -int MaxEggPlugin::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) -{ - Matrix3 m; - GraphicsWindow *gw = vpt->getGW(); - Material *mtl = gw->getMaterial(); - - GetMat(t,inode,vpt,m); - gw->setTransform(m); - DWORD rlim = gw->getRndLimits(); - gw->setRndLimits(GW_WIREFRAME|GW_BACKCULL); - if (inode->Selected()) - gw->setColor( LINE_COLOR, GetSelColor()); - else if(!inode->IsFrozen()) - gw->setColor( LINE_COLOR, GetUIColor(COLOR_TAPE_OBJ)); - mesh.render( gw, mtl, nullptr, COMP_ALL); - return 0; -} - -RefResult MaxEggPlugin::NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message ) -{ - UpdateUI(); - return REF_SUCCEED; -} - -ObjectState MaxEggPlugin::Eval(TimeValue time) -{ - return ObjectState(this); -} - -Interval MaxEggPlugin::ObjectValidity(TimeValue t) -{ - Interval ivalid; - ivalid.SetInfinite(); - return ivalid; -} - -RefTargetHandle MaxEggPlugin::Clone(RemapDir& remap) -{ - MaxEggPlugin* newob = new MaxEggPlugin(); - return(newob); -} - -// Loading and saving the plugin - -IOResult MaxEggPlugin::Save(ISave *isave) { - SaveCheckState(); - for (int i = 0; i < numEggs; i++) - eggList[i]->Save(isave); - ChunkSave(isave, CHUNK_OVERWRITE_FLAG, autoOverwrite); - ChunkSave(isave, CHUNK_PVIEW_FLAG, pview); - ChunkSave(isave, CHUNK_LOG_OUTPUT, logOutput); - - return IO_OK; -} - -IOResult MaxEggPlugin::Load(ILoad *iload) { - IOResult res = iload->OpenChunk(); - MaxOptionsDialog *temp; - - while (res == IO_OK) { - switch(iload->CurChunkID()) { - case CHUNK_OVERWRITE_FLAG: autoOverwrite = ChunkLoadBool(iload); break; - case CHUNK_PVIEW_FLAG: pview = ChunkLoadBool(iload); break; - case CHUNK_LOG_OUTPUT: logOutput = ChunkLoadBool(iload); break; - case CHUNK_EGG_EXP_OPTIONS: - temp = new MaxOptionsDialog(); - temp->SetMaxInterface(iObjParams); - temp->Load(iload); - AddEgg(temp); - break; - } - iload->CloseChunk(); - res = iload->OpenChunk(); - } - - return IO_OK; -} - -/********************************************************************** - * - * DLL Initialization - * - **********************************************************************/ - -extern ClassDesc* GetMaxEggPluginDesc(); - -HINSTANCE hInstance; -int controlsInit = FALSE; - -// This function is called by Windows when the DLL is loaded. This function -// may also be called many times during time critical operations like -// rendering. Therefore developers need to be careful what they do inside -// this function. In the code below, note how after the DLL is loaded the -// first time only a few statements are executed. - -BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) -{ - hInstance = hinstDLL; // Hang on to this DLL's instance handle. - - if (!controlsInit) { - controlsInit = TRUE; - -#if MAX_VERSION_MAJOR < 14 - // It appears that InitCustomControls is deprecated in 2012. - // I'm not sure if we can just remove it like this, but I've - // heard that it seems to work, so let's do it like this. - InitCustomControls(hInstance); // Initialize MAX's custom controls -#endif - InitCommonControls(); // Initialize Win95 controls - } - - return (TRUE); -} - -// This function returns a string that describes the DLL and where the user -// could purchase the DLL if they don't have it. -__declspec( dllexport ) const TCHAR* LibDescription() -{ - return GetString(IDS_LIBDESCRIPTION); -} - -// This function returns the number of plug-in classes this DLL operates on. -// TODO: Must change this number when adding a new class -__declspec( dllexport ) int LibNumberClasses() -{ - return 1; -} - -// This function returns the descriptions of the plug-in classes this DLL -// operates on. -__declspec( dllexport ) ClassDesc* LibClassDesc(int i) -{ - switch(i) { - case 0: return GetMaxEggPluginDesc(); - default: return nullptr; - } -} - -// This function returns a pre-defined constant indicating the version of the -// system under which it was compiled. It is used to allow the system to -// catch obsolete DLLs. -__declspec( dllexport ) ULONG LibVersion() -{ - return VERSION_3DSMAX; -} - -TCHAR *GetString(int id) -{ - static TCHAR buf[256]; - - if (hInstance) - return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : nullptr; - return nullptr; -} diff --git a/pandatool/src/maxegg/maxEgg.def b/pandatool/src/maxegg/maxEgg.def deleted file mode 100644 index b8ca255c1f5..00000000000 --- a/pandatool/src/maxegg/maxEgg.def +++ /dev/null @@ -1,8 +0,0 @@ -LIBRARY MaxEgg -EXPORTS - LibDescription @1 - LibNumberClasses @2 - LibClassDesc @3 - LibVersion @4 -SECTIONS - .data READ WRITE diff --git a/pandatool/src/maxegg/maxEgg.h b/pandatool/src/maxegg/maxEgg.h deleted file mode 100644 index 97d9b1dea41..00000000000 --- a/pandatool/src/maxegg/maxEgg.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - MaxEgg.h - Created by Steven "Sauce" Osman, Jan03 - Modified and maintained by Ken Strickland, (02/01/03)-(05/15/03) - Modified and maintained by Corey Revilla, (05/22/03)-present - Carnegie Mellon University, Entetainment Technology Center - - This file contains a 3dsMax exporter derived from discreet's own SceneExport - plug-in class; this exporter is basically a wrapper around the MaxToEgg - Panda-converter class, and just sets up the interface and environment - in which the MaxToEgg class can be "run" as if it were a standalone app. -*/ -#ifndef __MaxEgg__H -#define __MaxEgg__H - -#include "pandatoolbase.h" -#include -#include -#include -#include -#include - -using std::min; -using std::max; - -#include "eggGroup.h" -#include "eggTable.h" -#include "eggXfmSAnim.h" -#include "eggData.h" -#include "referenceCount.h" -#include "pointerTo.h" -#include "namable.h" - -#include -#include -#include - -#define WIN32_LEAN_AND_MEAN -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "eggCoordinateSystem.h" -#include "eggGroup.h" -#include "eggPolygon.h" -#include "eggTextureCollection.h" -#include "eggTexture.h" -#include "eggVertex.h" -#include "eggVertexPool.h" -#include "eggNurbsCurve.h" -#include "pandatoolbase.h" -#include "eggXfmSAnim.h" -#include "pathStore.h" - -#include "maxNodeDesc.h" -#include "maxNodeTree.h" -#include "maxOptionsDialog.h" -#include "maxResource.h" -#include "maxToEggConverter.h" - -#define MaxEggPlugin_CLASS_ID Class_ID(0x7ac0d6b7, 0x55731ef6) - -#pragma conform(forScope, off) - -/* Externed Globals - */ -extern HINSTANCE hInstance; - -/* Global Functions - */ -extern TCHAR *GetString(int id); - -/* This class defines the 3D Studio Max exporter itself. It is basically a - shell that is invoked by 3D Studio Max's export API. It then sets up - MaxToEgg instance and attempts to "fool it" into thinking that it is - actually being invoked as a standalone program. The thought behind this - is that some day MaxToEgg may well be a standalone program, provided that - a suitable interface to Max files can be connected from a standalone - program instead of a plugin. -*/ - -#if MAX_VERSION_MAJOR < 9 - #define DefaultRemapDir NoRemap -#endif - -class MaxEggPlugin : public HelperObject -{ - MaxOptionsDialog **eggList; - int numEggs; - int maxEggs; - - public: - bool autoOverwrite; - bool pview; - bool logOutput; - - // Class vars - static Mesh mesh; // This plugin generates no geometry, this mesh is not passed on to 3D Studio. - static short meshBuilt; - static HWND hMaxEggParams; - static IObjParam *iObjParams; - - // ConstructorDestructor - MaxEggPlugin(); - virtual ~MaxEggPlugin(); - - // Other class Methods - void DoExport(); - void UpdateUI(); - void SaveCheckState(); - void BuildMesh(); - - void AddEgg(MaxOptionsDialog *newEgg); - void RemoveEgg(int i); - MaxOptionsDialog *GetEgg(int i) { return (i >= 0 && i < numEggs) ? eggList[i] : nullptr; } - - // Required implimented virtual methods: inherited virtual methods for - // Reference-management - RefResult NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message ); - void GetMat(TimeValue t, INode* inod, ViewExp *vpt, Matrix3& mat); - - // From BaseObject - int HitTest(TimeValue t, INode* inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt); - int Display(TimeValue t, INode* inode, ViewExp *vpt, int flags); - CreateMouseCallBack* GetCreateMouseCallBack(); - void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev); - void EndEditParams( IObjParam *ip, ULONG flags,Animatable *next); -#if MAX_VERSION_MAJOR < 15 - TCHAR *GetObjectName() { return GetString(IDS_LIBDESCRIPTION); } -#else - const TCHAR *GetObjectName() { return GetString(IDS_LIBDESCRIPTION); } -#endif - - // From Object - ObjectState Eval(TimeValue time); - void InitNodeName(TSTR& s) { s = GetString(IDS_CLASS_NAME); } - Interval ObjectValidity(TimeValue time); - void Invalidate(); - int DoOwnSelectHilite() { return 1; } - - // From GeomObject - int IntersectRay(TimeValue t, Ray& r, PN_stdfloat& at) { return 0; } - void GetWorldBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box ); - void GetLocalBoundBox(TimeValue t, INode *mat, ViewExp *vpt, Box3& box ); - void GetDeformBBox(TimeValue t, Box3& box, Matrix3 *tm, BOOL useSel ); - - // Animatable methods - void DeleteThis() { delete this; } - Class_ID ClassID() { return MaxEggPlugin_CLASS_ID; } - void GetClassName(TSTR& s) { s = TSTR(GetString(IDS_CLASS_NAME)); } - TSTR SubAnimName(int i) { return TSTR(GetString(IDS_CLASS_NAME)); } - - // From ref - RefTargetHandle Clone(RemapDir& remap = DefaultRemapDir()); - - // IO - IOResult Save(ISave *isave); - IOResult Load(ILoad *iload); -}; - - -#endif // __MaxEgg__H diff --git a/pandatool/src/maxegg/maxEgg.rc b/pandatool/src/maxegg/maxEgg.rc deleted file mode 100644 index a0377342184..00000000000 --- a/pandatool/src/maxegg/maxEgg.rc +++ /dev/null @@ -1,200 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "maxResource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "WinResrc.h" -#define IDC_STATIC -1 -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) -#ifdef _WIN32 -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_EGG_DETAILS DIALOGEX 0, 0, 256, 203 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Export Settings" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Animation Type:",IDC_STATIC,6,5,54,8,NOT WS_GROUP - CONTROL "Model",IDC_MODEL,"Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_GROUP,65,4,38,12 - CONTROL "Animation",IDC_ANIMATION,"Button",BS_AUTORADIOBUTTON | BS_LEFT,108,4,50,12 - CONTROL "Both",IDC_BOTH,"Button",BS_AUTORADIOBUTTON | BS_LEFT,164,4,35,12 - CONTROL "Static",IDC_POSE,"Button",BS_AUTORADIOBUTTON | BS_LEFT,206,4,38,12 - LTEXT "Filename",IDC_STATIC,12,30,66,8,NOT WS_GROUP - CONTROL "Custom1",IDC_FILENAME,"CustEdit",WS_TABSTOP,12,42,180,12 - CONTROL "Browse...",IDC_BROWSE,"CustButton",WS_TABSTOP,198,42,48,12 - CONTROL "Export Entire Scene",IDC_EXPORT_ALL,"Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_GROUP,12,59,79,10 - CONTROL "Export Meshes:",IDC_EXPORT_SELECTED,"Button",BS_AUTORADIOBUTTON | BS_LEFT,12,71,66,10 - LISTBOX IDC_LIST_EXPORT,12,84,114,36,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP - CONTROL "Add...",IDC_ADD_EXPORT,"CustButton",WS_TABSTOP,12,126,54,12 - CONTROL "Remove...",IDC_REMOVE_EXPORT,"CustButton",WS_TABSTOP,72,126,54,12 - CONTROL "Export All Frames",IDC_EXP_ALL_FRAMES,"Button",BS_AUTORADIOBUTTON | BS_LEFT | WS_GROUP,144,59,72,10 - CONTROL "Use Range:",IDC_EXP_SEL_FRAMES,"Button",BS_AUTORADIOBUTTON | BS_LEFT | BS_VCENTER,144,71,53,10 - LTEXT "Start Frame",IDC_SF_LABEL,144,90,42,8,WS_DISABLED | NOT WS_GROUP - CONTROL "Custom4",IDC_SF,"CustEdit",WS_DISABLED | WS_TABSTOP,186,87,48,12 - LTEXT "End Frame",IDC_EF_LABEL,143,104,42,8,WS_DISABLED | NOT WS_GROUP - CONTROL "Custom5",IDC_EF,"CustEdit",WS_DISABLED | WS_TABSTOP,186,102,48,12 - CONTROL "Double-sided Polygons",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,144,126,102,12 - CONTROL "OK",IDC_OK,"CustButton",WS_TABSTOP,162,179,42,12 - CONTROL "Cancel",IDC_CANCEL,"CustButton",WS_TABSTOP,208,179,42,12 - LTEXT "The collision tags are now defined within each object's User Defined properties window. For more information and help please consult the panda3d manual at www.panda3d.org",IDC_STATIC,12,146,225,26 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -1 VERSIONINFO - FILEVERSION 3,0,0,0 - PRODUCTVERSION 3,0,0,0 - FILEFLAGSMASK 0x0L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "FileVersion", "4.0.0.0" - VALUE "InternalName", "MaxEgg" - VALUE "OriginalFilename", "MaxEgg.dle" - VALUE "ProductName", "3ds max" - VALUE "ProductVersion", "4.0.0.0" - VALUE "FileDescription", "Panda3D .egg exporter" - VALUE "Comments", "TECH: " - VALUE "LegalTrademarks", "3D Studio MAX, Biped, Character Studio, Heidi, Kinetix and Physique are registered trademarks and 3ds max, combustion, Discreet, DWG Unplugged, DXF, FLI and FLC are trademarks of Autodesk, Inc." - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PANEL DIALOGEX 0, 0, 108, 192 -STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_SYSMENU -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - CTEXT "Panda 3D EGG Exporter",IDC_PANEL_TITLE,6,6,96,11,WS_BORDER | NOT WS_GROUP - LTEXT "Eggs",IDC_EGGS_LABEL,6,19,62,8,NOT WS_GROUP - CONTROL "Custom1",IDC_LIST_EGGS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_TABSTOP,6,28,96,69,WS_EX_CLIENTEDGE - CONTROL "Add...",IDC_ADD_EGG,"CustButton",WS_TABSTOP,6,102,24,12 - CONTROL "Edit...",IDC_EDIT_EGG,"CustButton",WS_TABSTOP,36,102,30,12 - CONTROL "Remove",IDC_REMOVE_EGG,"CustButton",WS_TABSTOP,72,102,30,12 - CONTROL "Overwrite Existing Files",IDC_OVERWRITE_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,126,103,8,WS_EX_TRANSPARENT - CONTROL "Export Now",IDC_EXPORT,"CustButton",WS_TABSTOP,5,164,96,18 - CONTROL "Pview Output",IDC_PVIEW_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,138,103,8,WS_EX_TRANSPARENT - CONTROL "Log Output",IDC_LOGGING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,148,90,11 -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PANEL, DIALOG - BEGIN - RIGHTMARGIN, 107 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_LIBDESCRIPTION "Panda3D .egg exporter" - IDS_CATEGORY "Exporters" - IDS_CLASS_NAME "Panda3D" - IDS_PARAMS "Parameters" - IDS_SPIN "Spin" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/pandatool/src/maxegg/maxEggLoader.cxx b/pandatool/src/maxegg/maxEggLoader.cxx deleted file mode 100644 index 09970789c38..00000000000 --- a/pandatool/src/maxegg/maxEggLoader.cxx +++ /dev/null @@ -1,726 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxEggLoader.cxx - * @author jyelon - * @date 2005-07-15 - * - * This file contains the code for class MaxEggLoader. This class - * does the actual work of copying an EggData tree into the max scene. - */ - -#include "pandatoolbase.h" -#include "notifyCategoryProxy.h" - -#include "eggData.h" -#include "eggVertexPool.h" -#include "eggVertex.h" -#include "eggPolygon.h" -#include "eggPrimitive.h" -#include "eggGroupNode.h" -#include "eggPolysetMaker.h" -#include "eggBin.h" - -using std::min; -using std::max; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "maxEggLoader.h" - -using std::vector; - -class MaxEggMesh; -class MaxEggJoint; -class MaxEggTex; - -NotifyCategoryDeclNoExport(maxloader); -NotifyCategoryDef(maxloader, ""); - -class MaxEggLoader -{ -public: - bool ConvertEggData(EggData *data, bool merge, bool model, bool anim); - bool ConvertEggFile(const char *name, bool merge, bool model, bool anim); - -public: - void TraverseEggNode(EggNode *node, EggGroup *context); - MaxEggMesh *GetMesh(EggVertexPool *pool); - MaxEggJoint *FindJoint(EggGroup *joint); - MaxEggJoint *MakeJoint(EggGroup *joint, EggGroup *context); - MaxEggTex *GetTex(const Filename &fn); - void CreateSkinModifier(MaxEggMesh *M); - - typedef phash_map MeshTable; - typedef second_of_pair_iterator MeshIterator; - typedef phash_map JointTable; - typedef second_of_pair_iterator JointIterator; - typedef phash_map TexTable; - typedef second_of_pair_iterator TexIterator; - - MeshTable _mesh_tab; - JointTable _joint_tab; - TexTable _tex_tab; - int _next_tex; -}; - -Point3 MakeMaxPoint(LVector3d vec) -{ - return Point3(vec[0], vec[1], vec[2]); -} - -// MaxEggTex - -class MaxEggTex -{ -public: - Filename _path; - int _id; - StdMat *_mat; - BitmapTex *_bmt; -}; - -MaxEggTex *MaxEggLoader::GetTex(const Filename &fn) -{ - if (_tex_tab.count(fn)) - return _tex_tab[fn]; - - BitmapTex *bmt = NewDefaultBitmapTex(); -#ifdef _UNICODE - bmt->SetMapName((TCHAR*) fn.to_os_specific_w().c_str()); -#else - bmt->SetMapName((char*) fn.to_os_specific().c_str()); -#endif - - StdMat *mat = NewDefaultStdMat(); - mat->SetSubTexmap(ID_DI, bmt); - mat->SetTexmapAmt(ID_DI, 1.0, 0); - mat->EnableMap(ID_DI, TRUE); - mat->SetActiveTexmap(bmt); - GetCOREInterface()->ActivateTexture(bmt, mat); - - MaxEggTex *res = new MaxEggTex; - res->_path = fn; - res->_id = _next_tex ++; - res->_bmt = bmt; - res->_mat = mat; - - _tex_tab[fn] = res; - return res; -} - -// MaxEggJoint - -class MaxEggJoint -{ -public: - LMatrix4d _trans; - LVector3d _endpos; - LVector3d _perp; - double _thickness; - bool _inskin; - SimpleObject2 *_bone; - INode *_node; - EggGroup *_egg_joint; - MaxEggJoint *_parent; - vector _children; - -public: - void GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv); - LVector3d GetPos(void) { return _trans.get_row3(3); } - MaxEggJoint *ChooseBestChild(LVector3d dir); - void ChooseEndPos(double thickness); - void CreateMaxBone(void); -}; - -void MaxEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv) -{ - xv = _trans.get_row3(0); - yv = _trans.get_row3(1); - zv = _trans.get_row3(2); - xv.normalize(); - yv.normalize(); - zv = xv.cross(yv); - zv.normalize(); - yv = zv.cross(xv); -} - -MaxEggJoint *MaxEggLoader::FindJoint(EggGroup *joint) -{ - if (joint==0) return 0; - return _joint_tab[joint]; -} - -MaxEggJoint *MaxEggLoader::MakeJoint(EggGroup *joint, EggGroup *context) -{ - MaxEggJoint *parent = FindJoint(context); - MaxEggJoint *result = new MaxEggJoint; - LMatrix4d t = joint->get_transform3d(); - if (parent) { - result->_trans = t * parent->_trans; - } else { - result->_trans = t; - } - result->_endpos = LVector3d(0,0,0); - result->_perp = LVector3d(0,0,0); - result->_thickness = 0.0; - result->_inskin = false; - result->_bone = 0; - result->_node = 0; - result->_egg_joint = joint; - result->_parent = parent; - if (parent) parent->_children.push_back(result); - _joint_tab[joint] = result; - return result; -} - -MaxEggJoint *MaxEggJoint::ChooseBestChild(LVector3d dir) -{ - if (dir.length() < 0.001) return 0; - dir.normalize(); - double firstbest = -1000; - MaxEggJoint *firstchild = 0; - LVector3d firstpos = GetPos(); - double secondbest = 0; - for (int i=0; i<_children.size(); i++) { - MaxEggJoint *child = _children[i]; - LVector3d tryfwd = child->GetPos() - GetPos(); - if ((child->GetPos() != firstpos) && (tryfwd.length() > 0.001)) { - LVector3d trydir = tryfwd; - trydir.normalize(); - double quality = trydir.dot(dir); - if (quality > firstbest) { - secondbest = firstbest; - firstbest = quality; - firstpos = child->GetPos(); - firstchild = child; - } else if (quality > secondbest) { - secondbest = quality; - } - } - } - if (firstbest > secondbest + 0.1) - return firstchild; - return 0; -} - -void MaxEggJoint::ChooseEndPos(double thickness) -{ - LVector3d parentpos(0,0,0); - LVector3d parentendpos(0,0,1); - if (_parent) { - parentpos = _parent->GetPos(); - parentendpos = _parent->_endpos; - } - LVector3d fwd = GetPos() - parentpos; - if (fwd.length() < 0.001) { - fwd = parentendpos - parentpos; - } - fwd.normalize(); - MaxEggJoint *child = ChooseBestChild(fwd); - if (child == 0) { - _endpos = fwd * thickness * 0.8 + GetPos(); - _thickness = thickness * 0.8; - } else { - _endpos = child->GetPos(); - _thickness = (_endpos - GetPos()).length(); - if (_thickness > thickness) _thickness = thickness; - } - LVector3d orient = _endpos - GetPos(); - orient.normalize(); - LVector3d altaxis = orient.cross(LVector3d(0,-1,0)); - if (altaxis.length() < 0.001) altaxis = orient.cross(LVector3d(0,0,1)); - _perp = altaxis.cross(orient); - _perp.normalize(); -} - -void MaxEggJoint::CreateMaxBone(void) -{ - LVector3d rxv,ryv,rzv; - GetRotation(rxv, ryv, rzv); - Point3 xv(MakeMaxPoint(rxv)); - Point3 yv(MakeMaxPoint(ryv)); - Point3 zv(MakeMaxPoint(rzv)); - Point3 pos(MakeMaxPoint(GetPos())); - Point3 endpos(MakeMaxPoint(_endpos)); - Point3 tzv(MakeMaxPoint(_perp)); - - Point3 fwd = endpos - pos; - double len = fwd.Length(); - Point3 txv = fwd * ((PN_stdfloat)(1.0/len)); - Point3 tyv = tzv ^ txv; - Point3 row1 = Point3(txv % xv, txv % yv, txv % zv); - Point3 row2 = Point3(tyv % xv, tyv % yv, tyv % zv); - Point3 row3 = Point3(tzv % xv, tzv % yv, tzv % zv); - Matrix3 oomat(row1,row2,row3,Point3(0,0,0)); - Quat ooquat(oomat); - _bone = (SimpleObject2*)CreateInstance(GEOMOBJECT_CLASS_ID, BONE_OBJ_CLASSID); - _node = GetCOREInterface()->CreateObjectNode(_bone); - _node->SetNodeTM(0, Matrix3(xv, yv, zv, pos)); - IParamBlock2 *blk = _bone->pblock2; - for (int i=0; iNumParams(); i++) { - TSTR n = blk->GetLocalName(i); - if (_tcscmp(n, _T("Length")) == 0) blk->SetValue(i, 0, (PN_stdfloat) len); - else if (_tcscmp(n, _T("Width")) == 0) blk->SetValue(i, 0, (PN_stdfloat) _thickness); - else if (_tcscmp(n, _T("Height")) == 0) blk->SetValue(i, 0, (PN_stdfloat) _thickness); - } - Point3 boneColor = GetUIColor(COLOR_BONES); - _node->SetWireColor(RGB(int(boneColor.x*255.0f), int(boneColor.y*255.0f), int(boneColor.z*255.0f) )); - _node->SetBoneNodeOnOff(TRUE, 0); - _node->SetRenderable(FALSE); - -#ifdef _UNICODE - TCHAR wname[1024]; - wname[1023] = 0; - mbstowcs(wname, _egg_joint->get_name().c_str(), 1023); - _node->SetName(wname); -#else - _node->SetName((char*) _egg_joint->get_name().c_str()); -#endif - - _node->SetObjOffsetRot(ooquat); - if (_parent) { - _node->Detach(0, 1); - _parent->_node->AttachChild(_node, 1); - } -} - -// MaxEggMesh - -typedef std::pair MaxEggWeight; - -struct MaxEggVertex -{ - LVertexd _pos; - LNormald _normal; - vector _weights; - int _index; -}; - -struct MEV_Compare: public stl_hash_compare -{ - size_t operator()(const MaxEggVertex &key) const - { - return key._pos.add_hash(key._normal.get_hash()); - } - bool operator()(const MaxEggVertex &k1, const MaxEggVertex &k2) const - { - int n = k1._pos.compare_to(k2._pos); - if (n < 0) return true; - if (n > 0) return false; - n = k1._normal.compare_to(k2._normal); - if (n < 0) return true; - if (n > 0) return false; - n = k1._weights.size() - k2._weights.size(); - if (n < 0) return true; - if (n > 0) return false; - for (int i=0; i 0) return false; - EggGroup *g1 = k1._weights[i].second; - EggGroup *g2 = k2._weights[i].second; - if (g1 < g2) return true; - if (g1 > g2) return false; - } - return false; - } -}; - -typedef phash_set VertTable; -typedef phash_map TVertTable; -typedef phash_map CVertTable; - -class MaxEggMesh -{ -public: - - std::string _name; - TriObject *_obj; - Mesh *_mesh; - INode *_node; - IDerivedObject *_dobj; - Modifier *_skin_mod; - ISkin *_iskin; - ISkinImportData *_iskin_import; - int _vert_count; - int _tvert_count; - int _cvert_count; - int _face_count; - - VertTable _vert_tab; - TVertTable _tvert_tab; - CVertTable _cvert_tab; - - int GetVert(EggVertex *vert, EggGroup *context); - int GetTVert(const LTexCoordd &uv); - int GetCVert(const LColor &col); - int AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, int tex); - EggGroup *GetControlJoint(void); -}; - -#define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1))) - -int MaxEggMesh::GetVert(EggVertex *vert, EggGroup *context) -{ - MaxEggVertex vtx; - vtx._pos = vert->get_pos3(); - vtx._normal = vert->get_normal(); - vtx._index = 0; - - EggVertex::GroupRef::const_iterator gri; - for (gri = vert->gref_begin(); gri != vert->gref_end(); ++gri) { - EggGroup *egg_joint = (*gri); - double membership = egg_joint->get_vertex_membership(vert); - vtx._weights.push_back(MaxEggWeight(membership, egg_joint)); - } - if (vtx._weights.size()==0) { - if (context != 0) - vtx._weights.push_back(MaxEggWeight(1.0, context)); - } - - VertTable::const_iterator vti = _vert_tab.find(vtx); - if (vti != _vert_tab.end()) - return vti->_index; - - if (_vert_count == _mesh->numVerts) { - int nsize = _vert_count*2 + 100; - _mesh->setNumVerts(nsize, _vert_count?TRUE:FALSE); - } - vtx._index = _vert_count++; - _vert_tab.insert(vtx); - _mesh->setVert(vtx._index, MakeMaxPoint(vtx._pos)); - return vtx._index; -} - -int MaxEggMesh::GetTVert(const LTexCoordd &uv) -{ - if (_tvert_tab.count(uv)) - return _tvert_tab[uv]; - if (_tvert_count == _mesh->numTVerts) { - int nsize = _tvert_count*2 + 100; - _mesh->setNumTVerts(nsize, _tvert_count?TRUE:FALSE); - } - int idx = _tvert_count++; - _mesh->setTVert(idx, uv.get_x(), uv.get_y(), 0.0); - _tvert_tab[uv] = idx; - return idx; -} - -int MaxEggMesh::GetCVert(const LColor &col) -{ - if (_cvert_tab.count(col)) - return _cvert_tab[col]; - if (_cvert_count == _mesh->numCVerts) { - int nsize = _cvert_count*2 + 100; - _mesh->setNumVertCol(nsize, _cvert_count?TRUE:FALSE); - } - int idx = _cvert_count++; - _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), col.get_z()); - _cvert_tab[col] = idx; - return idx; -} - -MaxEggMesh *MaxEggLoader::GetMesh(EggVertexPool *pool) -{ - MaxEggMesh *result = _mesh_tab[pool]; - if (result == 0) { - std::string name = pool->get_name(); - int nsize = name.size(); - if ((nsize > 6) && (name.rfind(".verts")==(nsize-6))) - name.resize(nsize-6); - result = new MaxEggMesh; - result->_name = name; - result->_obj = CreateNewTriObject(); - result->_mesh = &result->_obj->GetMesh(); - result->_mesh->setMapSupport(0, TRUE); - result->_node = GetCOREInterface()->CreateObjectNode(result->_obj); - result->_dobj = 0; - result->_skin_mod = 0; - result->_iskin = 0; - result->_iskin_import = 0; - result->_vert_count = 0; - result->_tvert_count = 0; - result->_cvert_count = 0; - result->_face_count = 0; -#ifdef _UNICODE - TCHAR wname[1024]; - wname[1023] = 0; - mbstowcs(wname, name.c_str(), 1023); - result->_node->SetName(wname); -#else - result->_node->SetName((char*) name.c_str()); -#endif - _mesh_tab[pool] = result; - } - return result; -} - -int MaxEggMesh::AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, int tex) -{ - static int dump = 0; - if (_face_count == _mesh->numFaces) { - int nsize = _face_count*2 + 100; - BOOL keep = _mesh->numFaces ? TRUE : FALSE; - _mesh->setNumFaces(nsize, keep); - _mesh->setNumTVFaces(nsize, keep, _face_count); - _mesh->setNumVCFaces(nsize, keep, _face_count); - } - int idx = _face_count++; - _mesh->faces[idx].setVerts(v0,v1,v2); - _mesh->faces[idx].smGroup = 1; - _mesh->faces[idx].flags = EDGE_ALL | HAS_TVERTS; - _mesh->faces[idx].setMatID(tex); - _mesh->tvFace[idx].setTVerts(tv0,tv1,tv2); - _mesh->vcFace[idx].setTVerts(cv0,cv1,cv2); - return idx; -} - -EggGroup *MaxEggMesh::GetControlJoint(void) -{ - EggGroup *result; - VertTable::const_iterator vert = _vert_tab.begin(); - if (vert == _vert_tab.end()) return 0; - switch (vert->_weights.size()) { - case 0: - for (++vert; vert != _vert_tab.end(); ++vert) - if (vert->_weights.size() != 0) - return CTRLJOINT_DEFORM; - return 0; - case 1: - result = vert->_weights[0].second; - for (++vert; vert != _vert_tab.end(); ++vert) - if ((vert->_weights.size() != 1) || (vert->_weights[0].second != result)) - return CTRLJOINT_DEFORM; - return result; - default: - return CTRLJOINT_DEFORM; - } -} - -void MaxEggLoader::CreateSkinModifier(MaxEggMesh *M) -{ - vector joints; - - M->_dobj = CreateDerivedObject(M->_obj); - M->_node->SetObjectRef(M->_dobj); - M->_skin_mod = (Modifier*)CreateInstance(OSM_CLASS_ID, SKIN_CLASSID); - M->_iskin = (ISkin*)M->_skin_mod->GetInterface(I_SKIN); - M->_iskin_import = (ISkinImportData*)M->_skin_mod->GetInterface(I_SKINIMPORTDATA); - M->_dobj->SetAFlag(A_LOCK_TARGET); - M->_dobj->AddModifier(M->_skin_mod); - M->_dobj->ClearAFlag(A_LOCK_TARGET); - GetCOREInterface()->ForceCompleteRedraw(); - - VertTable::const_iterator vert; - for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { - for (int i=0; i_weights.size(); i++) { - double strength = vert->_weights[i].first; - MaxEggJoint *joint = FindJoint(vert->_weights[i].second); - if (!joint->_inskin) { - joint->_inskin = true; - joints.push_back(joint); - } - } - } - for (int i=0; i_iskin_import->AddBoneEx(joints[i]->_node, last); - joints[i]->_inskin = false; - } - - GetCOREInterface()->SetCommandPanelTaskMode(TASK_MODE_MODIFY); - GetCOREInterface()->SelectNode(M->_node); - GetCOREInterface()->ForceCompleteRedraw(); - - for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { - Tab maxJoints; - Tab maxWeights; - maxJoints.ZeroCount(); - maxWeights.ZeroCount(); - for (int i=0; i_weights.size(); i++) { - PN_stdfloat strength = (PN_stdfloat)(vert->_weights[i].first); - MaxEggJoint *joint = FindJoint(vert->_weights[i].second); - maxWeights.Append(1,&strength); - maxJoints.Append(1,&(joint->_node)); - } - M->_iskin_import->AddWeights(M->_node, vert->_index, maxJoints, maxWeights); - } -} - -// TraverseEggData We have an EggData in memory, and now we're going to copy -// that over into the max scene graph. - -void MaxEggLoader::TraverseEggNode(EggNode *node, EggGroup *context) -{ - vector vertIndices; - vector tvertIndices; - vector cvertIndices; - - if (node->is_of_type(EggPolygon::get_class_type())) { - EggPolygon *poly = DCAST(EggPolygon, node); - - int texid; - LMatrix3d uvtrans = LMatrix3d::ident_mat(); - if (poly->has_texture()) { - EggTexture *tex = poly->get_texture(0); - texid = GetTex(tex->get_fullpath())->_id; - if (tex->has_transform()) - uvtrans = tex->get_transform2d(); - } else { - texid = GetTex(Filename())->_id; - } - - EggPolygon::const_iterator ci; - MaxEggMesh *mesh = GetMesh(poly->get_pool()); - vertIndices.clear(); - tvertIndices.clear(); - cvertIndices.clear(); - for (ci = poly->begin(); ci != poly->end(); ++ci) { - EggVertex *vtx = (*ci); - EggVertexPool *pool = poly->get_pool(); - LTexCoordd uv = vtx->get_uv(); - vertIndices.push_back(mesh->GetVert(vtx, context)); - tvertIndices.push_back(mesh->GetTVert(uv * uvtrans)); - cvertIndices.push_back(mesh->GetCVert(vtx->get_color())); - } - for (int i=1; iAddFace(vertIndices[0], vertIndices[i], vertIndices[i+1], - tvertIndices[0], tvertIndices[i], tvertIndices[i+1], - cvertIndices[0], cvertIndices[i], cvertIndices[i+1], - texid); - } else if (node->is_of_type(EggGroupNode::get_class_type())) { - EggGroupNode *group = DCAST(EggGroupNode, node); - if (node->is_of_type(EggGroup::get_class_type())) { - EggGroup *group = DCAST(EggGroup, node); - if (group->is_joint()) { - MakeJoint(group, context); - context = group; - } - } - EggGroupNode::const_iterator ci; - for (ci = group->begin(); ci != group->end(); ++ci) { - TraverseEggNode(*ci, context); - } - } -} - -bool MaxEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim) -{ - if (!merge) { - maxloader_cat.error() << "Currently, only 'merge' mode is implemented.\n"; - return false; - } - - if ((anim) || (!model)) { - maxloader_cat.error() << "Currently, only model-loading is implemented.\n"; - return false; - } - - MeshIterator ci; - JointIterator ji; - TexIterator ti; - - data->set_coordinate_system(CS_zup_right); - - SuspendAnimate(); - SuspendSetKeyMode(); - AnimateOff(); - _next_tex = 0; - - TraverseEggNode(data, nullptr); - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MaxEggMesh *mesh = (*ci); - mesh->_mesh->setNumVerts(mesh->_vert_count, TRUE); - mesh->_mesh->setNumTVerts(mesh->_tvert_count, TRUE); - mesh->_mesh->setNumVertCol(mesh->_cvert_count, TRUE); - mesh->_mesh->setNumFaces(mesh->_face_count, TRUE); - mesh->_mesh->setNumTVFaces(mesh->_face_count, TRUE, mesh->_face_count); - mesh->_mesh->setNumVCFaces(mesh->_face_count, TRUE, mesh->_face_count); - mesh->_mesh->InvalidateTopologyCache(); - mesh->_mesh->InvalidateGeomCache(); - mesh->_mesh->buildNormals(); - } - - double thickness = 0.0; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - double dfo = ((*ji)->GetPos()).length(); - if (dfo > thickness) thickness = dfo; - } - thickness = thickness * 0.025; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - MaxEggJoint *joint = *ji; - joint->ChooseEndPos(thickness); - joint->CreateMaxBone(); - } - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MaxEggMesh *mesh = (*ci); - EggGroup *joint = mesh->GetControlJoint(); - if (joint) CreateSkinModifier(mesh); - } - - if (_next_tex) { - TSTR name; - MultiMtl *mtl = NewDefaultMultiMtl(); - mtl->SetNumSubMtls(_next_tex); - for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) { - MaxEggTex *tex = *ti; - mtl->SetSubMtlAndName(tex->_id, tex->_mat, name); - } - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MaxEggMesh *mesh = *ci; - mesh->_node->SetMtl(mtl); - } - } - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) delete *ci; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) delete *ji; - for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) delete *ti; - - ResumeSetKeyMode(); - ResumeAnimate(); - - maxloader_cat.info() << "Egg import successful\n"; - return true; -} - -bool MaxEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim) -{ - EggData data; - Filename datafn = Filename::from_os_specific(name); - if (!data.read(datafn)) { - maxloader_cat.error() << "Cannot read Egg file for import\n"; - return false; - } - return ConvertEggData(&data, merge, model, anim); -} - -// The two global functions that form the API of this module. - -bool MaxLoadEggData(EggData *data, bool merge, bool model, bool anim) -{ - MaxEggLoader loader; - return loader.ConvertEggData(data, merge, model, anim); -} - -bool MaxLoadEggFile(const char *name, bool merge, bool model, bool anim) -{ - MaxEggLoader loader; - return loader.ConvertEggFile(name, merge, model, anim); -} diff --git a/pandatool/src/maxegg/maxEggLoader.h b/pandatool/src/maxegg/maxEggLoader.h deleted file mode 100644 index 90fe8975852..00000000000 --- a/pandatool/src/maxegg/maxEggLoader.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxEggLoader.h - * @author jyelon - * @date 2005-07-15 - */ - -#ifndef MAXEGGLOADER_H -#define MAXEGGLOADER_H - -class EggData; - -bool MaxLoadEggData(EggData *data, bool merge, bool model, bool anim); -bool MaxLoadEggFile(const char *name, bool merge, bool model, bool anim); - -#endif diff --git a/pandatool/src/maxegg/maxNodeDesc.cxx b/pandatool/src/maxegg/maxNodeDesc.cxx deleted file mode 100644 index 7e0ed3d964f..00000000000 --- a/pandatool/src/maxegg/maxNodeDesc.cxx +++ /dev/null @@ -1,198 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxNodeDesc.cxx - * @author crevilla - * from mayaNodeDesc.cxx created by: drose (06Jun03) - */ - -#include "maxEgg.h" - -TypeHandle MaxNodeDesc::_type_handle; - -/** - * Creates a MaxNodeDesc. The name is copied from the given max node. Use - * from_INode to actually associate the desc with a given max node. - */ -MaxNodeDesc:: -MaxNodeDesc(MaxNodeDesc *parent, INode *max_node) : - _parent(parent) { - - if (max_node != nullptr) { - const TCHAR *max_name = max_node->GetName(); -#ifdef _UNICODE - char name_mb [1024]; - name_mb[1023] = 0; - wcstombs(name_mb, max_name, 1023); - set_name(name_mb); -#else - set_name(max_name); -#endif - } - - _max_node = nullptr; - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - _joint_type = JT_none; - _joint_entry = nullptr; - - // Add ourselves to our parent. - if (_parent != nullptr) { - _parent->_children.push_back(this); - } -} - -/** - * - */ -MaxNodeDesc:: -~MaxNodeDesc() {} - -/** - * Indicates an associated between the MaxNodeDesc and some Max Node instance. - */ -void MaxNodeDesc:: -from_INode(INode *max_node) { - if (_max_node == nullptr) { - _max_node = max_node; - - // This is how I decided to check to see if this max node is a joint. It - // works in all instances I've seen so far, but this may be a good - // starting place to look if joints are not being picked up correctly in - // the future. - - // Check to see if the node's controller is a biped If so treat it as a - // joint Get the node's transform control - Control *c = max_node->GetTMController(); - if (_max_node->GetBoneNodeOnOff() || - (c && //c exists and it's type is a biped - ((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) || - (c->ClassID() == BIPBODY_CONTROL_CLASS_ID) || - (c->ClassID() == FOOTPRINT_CLASS_ID)))) { - - // This node is a joint. - _joint_type = JT_node_joint; - if (_parent != nullptr) { - _parent->mark_joint_parent(); - } - } - } -} - -/** - * Returns true if a Max INode has been associated with this node, false - * otherwise. - */ -bool MaxNodeDesc:: -has_max_node() const { - return (_max_node != nullptr); -} - -/** - * Returns the INode associated with this node. It is an error to call this - * unless has_max_node() returned true. - */ -INode *MaxNodeDesc:: -get_max_node() const { - nassertr(_max_node != nullptr, _max_node); - return _max_node; -} - - -void MaxNodeDesc:: -set_joint(bool onoff) { - if (onoff) - _joint_type = JT_joint; - else - _joint_type = JT_none; -} - -/** - * Returns true if the node should be treated as a joint by the converter. - */ -bool MaxNodeDesc:: -is_joint() const { - return _joint_type == JT_joint || _joint_type == JT_pseudo_joint; -} - -/** - * Returns true if the node is the parent or ancestor of a joint. - */ -bool MaxNodeDesc:: -is_joint_parent() const { - return _joint_type == JT_joint_parent; -} - -/** - * Returns true if the node is the parent or ancestor of a joint. - */ -bool MaxNodeDesc:: -is_node_joint() const { - return _joint_type == JT_node_joint; -} - -/** - * Recursively clears the egg pointers from this node and all children. - */ -void MaxNodeDesc:: -clear_egg() { - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MaxNodeDesc *child = (*ci); - child->clear_egg(); - } -} - -/** - * Indicates that this node has at least one child that is a joint or a - * pseudo-joint. - */ -void MaxNodeDesc:: -mark_joint_parent() { - if (_joint_type == JT_none) { - _joint_type = JT_joint_parent; - if (_parent != nullptr) { - _parent->mark_joint_parent(); - } - } -} - -/** - * Walks the hierarchy, looking for non-joint nodes that are both children and - * parents of a joint. These nodes are deemed to be pseudo joints, since the - * converter must treat them as joints. - */ -void MaxNodeDesc:: -check_pseudo_joints(bool joint_above) { - if (_joint_type == JT_joint_parent && joint_above) { - // This is one such node: it is the parent of a joint (JT_joint_parent is - // set), and it is the child of a joint (joint_above is set). - _joint_type = JT_pseudo_joint; - } - - if (_joint_type == JT_joint) { - // If this node is itself a joint, then joint_above is true for all child - // nodes. - joint_above = true; - } - - // Don't bother traversing further if _joint_type is none, since that means - // this node has no joint children. - if (_joint_type != JT_none) { - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MaxNodeDesc *child = (*ci); - child->check_pseudo_joints(joint_above); - } - } -} diff --git a/pandatool/src/maxegg/maxNodeDesc.h b/pandatool/src/maxegg/maxNodeDesc.h deleted file mode 100644 index 3b45fe0793c..00000000000 --- a/pandatool/src/maxegg/maxNodeDesc.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxNodeDesc.h - * @author crevilla - * from mayaNodeDesc.h created by: drose (06Jun03) - */ - -#ifndef MAXNODEDESC_H -#define MAXNODEDESC_H - -/** - * Describes a single instance of a node in the Max scene graph, relating it - * to the corresponding egg structures (e.g. node, group, or table entry) - * that will be created. - */ -class MaxNodeDesc : public ReferenceCount, public Namable { - public: - MaxNodeDesc(MaxNodeDesc *parent = nullptr, INode *max_node = nullptr); - ~MaxNodeDesc(); - - void from_INode(INode *max_node); - bool has_max_node() const; - INode *get_max_node() const; - - void set_joint(bool onoff); - bool is_joint() const; - bool is_joint_parent() const; - bool is_node_joint() const; - - MaxNodeDesc *_parent; - MaxNodeDesc *_joint_entry; - typedef pvector< MaxNodeDesc* > Children; - Children _children; - - private: - void clear_egg(); - void mark_joint_parent(); - void check_pseudo_joints(bool joint_above); - - INode *_max_node; - - EggGroup *_egg_group; - EggTable *_egg_table; - EggXfmSAnim *_anim; - - enum JointType { - JT_none, // Not a joint. - JT_node_joint, // Node that represents a joint in the geometry - // but not the actual joint itself - JT_joint, // An actual joint in Max. - JT_pseudo_joint, // Not a joint in Max, but treated just like a - // joint for the purposes of the converter. - JT_joint_parent, // A parent or ancestor of a joint or pseudo joint. - }; - JointType _joint_type; - - - public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - ReferenceCount::init_type(); - Namable::init_type(); - register_type(_type_handle, "MaxNodeDesc", - ReferenceCount::get_class_type(), - Namable::get_class_type()); - } - - private: - static TypeHandle _type_handle; - - friend class MaxNodeTree; -}; - -#endif diff --git a/pandatool/src/maxegg/maxNodeTree.cxx b/pandatool/src/maxegg/maxNodeTree.cxx deleted file mode 100644 index bb52b887f1e..00000000000 --- a/pandatool/src/maxegg/maxNodeTree.cxx +++ /dev/null @@ -1,447 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxNodeTree.cxx - * @author crevilla - * from mayaNodeTree.cxx created by: drose (06Jun03) - */ - -#include "maxEgg.h" - -/** - * - */ -MaxNodeTree:: -MaxNodeTree() { - _root = new MaxNodeDesc; - _fps = 0.0; - _export_mesh = false; - _egg_data = nullptr; - _egg_root = nullptr; - _skeleton_node = nullptr; -} - -/** - * Returns a pointer to the node corresponding to the indicated INode object, - * creating it first if necessary. - */ -MaxNodeDesc *MaxNodeTree:: -build_node(INode *max_node) { - MaxNodeDesc *node_desc = r_build_node(max_node); - node_desc->from_INode(max_node); - - if (node_desc->is_node_joint()) { - node_desc->_joint_entry = build_joint(max_node, node_desc); - } - return node_desc; -} - -/** - * Returns a pointer to the node corresponding to the indicated INode object, - * creating it first if necessary. - */ -MaxNodeDesc *MaxNodeTree:: -build_joint(INode *max_node, MaxNodeDesc *node_joint) { - MaxNodeDesc *node_desc = r_build_joint(node_joint, max_node); - node_desc->from_INode(max_node); - node_desc->set_joint(true); - return node_desc; -} - -bool MaxNodeTree::node_in_list(ULONG handle, ULONG *list, int len) { - if (!list) return true; - for (int i = 0; i < len; i++) - if (list[i] == handle) return true; - return false; -} - -bool MaxNodeTree::is_joint(INode *node) { - Control *c = node->GetTMController(); - return (node->GetBoneNodeOnOff() || //joints - (c && //bipeds - ((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) || - (c->ClassID() == BIPBODY_CONTROL_CLASS_ID) || - (c->ClassID() == FOOTPRINT_CLASS_ID)))); -} - -bool MaxNodeTree:: -r_build_hierarchy(INode *root, ULONG *selection_list, int len) { - if (node_in_list(root->GetHandle(), selection_list, len)) - build_node(root); - // Export children - for ( int i = 0; i < root->NumberOfChildren(); i++ ) { - // *** Should probably be checking the return value of the following line - r_build_hierarchy(root->GetChildNode(i), selection_list, len); - } - return true; -} -/** - * Walks through the complete Max hierarchy and builds up the corresponding - * tree. - */ -bool MaxNodeTree:: -build_complete_hierarchy(INode *root, ULONG *selection_list, int len) { - - // Get the entire Max scene. - if (root == nullptr) { - // *** Log an error - return false; - } - - bool all_ok = true; - r_build_hierarchy(root, selection_list, len); - - if (all_ok) { - _root->check_pseudo_joints(false); - } - - return all_ok; -} - -/** - * Returns the total number of nodes in the hierarchy, not counting the root - * node. - */ -int MaxNodeTree:: -get_num_nodes() const { - return _nodes.size(); -} - -/** - * Returns the nth node in the hierarchy, in an arbitrary ordering. - */ -MaxNodeDesc *MaxNodeTree:: -get_node(int n) const { - nassertr(n >= 0 && n < (int)_nodes.size(), nullptr); - return _nodes[n]; -} - -/** - * Removes all of the references to generated egg structures from the tree, - * and prepares the tree for generating new egg structures. - */ -void MaxNodeTree:: -clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node) { - _root->clear_egg(); - _egg_data = egg_data; - _egg_root = egg_root; - _skeleton_node = skeleton_node; -} - -/** - * Returns the EggGroupNode corresponding to the group or joint for the - * indicated node. Creates the group node if it has not already been created. - */ -EggGroup *MaxNodeTree:: -get_egg_group(MaxNodeDesc *node_desc) { - nassertr(_egg_root != nullptr, nullptr); - - if (node_desc->_egg_group == nullptr) { - // We need to make a new group node. - EggGroup *egg_group; - - nassertr(node_desc->_parent != nullptr, nullptr); - egg_group = new EggGroup(node_desc->get_name()); - if (node_desc->is_joint()) { - egg_group->set_group_type(EggGroup::GT_joint); - } - if (node_desc->_parent == _root) { - // The parent is the root. Set collision properties for the root if it - // has them: - if(!_export_mesh) - { - set_collision_tags(node_desc, egg_group); - } - _egg_root->add_child(egg_group); - - } else { - // The parent is another node. if export mesh, the tag should be added - // at the second level - if(_export_mesh) - { - if(node_desc->_parent->_parent == _root) - { - set_collision_tags(node_desc, egg_group); - } - } - EggGroup *parent_egg_group = get_egg_group(node_desc->_parent); - parent_egg_group->add_child(egg_group); - } - - node_desc->_egg_group = egg_group; - } - - return node_desc->_egg_group; -} - -/** - * Returns the EggTable corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggTable *MaxNodeTree:: -get_egg_table(MaxNodeDesc *node_desc) { - nassertr(_skeleton_node != nullptr, nullptr); - nassertr(node_desc->is_joint(), nullptr); - - if (node_desc->_egg_table == nullptr) { - // We need to make a new table node. - nassertr(node_desc->_parent != nullptr, nullptr); - - EggTable *egg_table = new EggTable(node_desc->get_name()); - node_desc->_anim = new EggXfmSAnim("xform", - _egg_data->get_coordinate_system()); - node_desc->_anim->set_fps(_fps); - egg_table->add_child(node_desc->_anim); - - if (!node_desc->_parent->is_joint()) { - // The parent is not a joint; put it at the top. - _skeleton_node->add_child(egg_table); - - } else { - // The parent is another joint. - EggTable *parent_egg_table = get_egg_table(node_desc->_parent); - parent_egg_table->add_child(egg_table); - } - - node_desc->_egg_table = egg_table; - } - - return node_desc->_egg_table; -} - -/** - * Returns the anim table corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggXfmSAnim *MaxNodeTree:: -get_egg_anim(MaxNodeDesc *node_desc) { - get_egg_table(node_desc); - return node_desc->_anim; -} - -/** - * The recursive implementation of build_node(). - */ -MaxNodeDesc *MaxNodeTree:: -r_build_node(INode* max_node) { - // If we have already encountered this pathname, return the corresponding - // MaxNodeDesc immediately. - - ULONG node_handle = 0; - - if (max_node) { - node_handle = max_node->GetHandle(); - } - - NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle); - if (ni != _nodes_by_path.end()) { - return (*ni).second; - } - - // Otherwise, we have to create it. Do this recursively, so we create each - // node along the path. - MaxNodeDesc *node_desc; - - if (!max_node) { - // This is the top. - node_desc = _root; - - } else { - INode *parent_node; - - if (max_node->IsRootNode()) { - parent_node = nullptr; - } else { - parent_node = max_node->GetParentNode(); - } - - MaxNodeDesc *parent_node_desc = r_build_node(parent_node); - node_desc = new MaxNodeDesc(parent_node_desc, max_node); - _nodes.push_back(node_desc); - } - - _nodes_by_path.insert(NodesByPath::value_type(node_handle, node_desc)); - return node_desc; -} - -/** - * The recursive implementation of build_joint(). - */ -MaxNodeDesc *MaxNodeTree:: -r_build_joint(MaxNodeDesc *node_desc, INode *max_node) -{ - MaxNodeDesc *node_joint; - if (node_desc == _root) { - node_joint = new MaxNodeDesc(_root, max_node); - _nodes.push_back(node_joint); - return node_joint; - } else if (node_desc->is_node_joint() && node_desc->_joint_entry) { - node_joint = new MaxNodeDesc(node_desc->_joint_entry, max_node); - _nodes.push_back(node_joint); - return node_joint; - } else { - return r_build_joint(node_desc->_parent, max_node); - } -} - -/** - * The recursive implementation of build_node(). - */ -MaxNodeDesc *MaxNodeTree:: -find_node(INode* max_node) { - // If we have already encountered this pathname, return the corresponding - // MaxNodeDesc immediately. - - ULONG node_handle = 0; - - if (max_node) { - node_handle = max_node->GetHandle(); - } - - NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle); - if (ni != _nodes_by_path.end()) { - return (*ni).second; - } - - return nullptr; -} - -/** - * The recursive implementation of build_node(). - */ -MaxNodeDesc *MaxNodeTree:: -find_joint(INode* max_node) -{ - MaxNodeDesc *node = find_node(max_node); - if (!node || (is_joint(max_node) && !node->is_node_joint())) - node = build_node(max_node); - return node->_joint_entry; -} - -/** - * Sets the corresponding collision tag to the egg_group based on the User - * Defined Tab in the object properties panel - */ -void MaxNodeTree::set_collision_tags(MaxNodeDesc *node_desc, EggGroup *egg_group) { - // Max has huge problems passing strings and bools to Get and SetUserProp - // So instead we have to use Integers. Now we have to check for every - // collide type, then get its collide flags and do some number crunching - // to get the actual flag into the group - - int check = 1; //is the value true. This could be anything really - - // We have to check each collision type in turn to see if it's true Ugly - // but it works per object, not globaly - if (node_desc->get_max_node()->GetUserPropInt(_T("polyset"), check)) { - // we have a polyset. - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_polyset); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("plane"), check)) { - // plane - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_plane); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("polygon"), check)) { - // polygon - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_polygon); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("sphere"), check)) { - // sphere - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_sphere); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("inv-sphere"), check)) { - // invsphere - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_inv_sphere); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("invsphere"), check)) { - // invsphere (different spelling) - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_inv_sphere); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("tube"), check)) { - // tube - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_tube); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("floor-mesh"), check)) { - // floor-mesh - if (check == 1) { - egg_group->set_collision_name(node_desc->get_name()); - egg_group->set_cs_type(EggGroup::CST_floor_mesh); - } - } - - if (node_desc->get_max_node()->GetUserPropInt(_T("descend"), check)) { - if (check == 1) { - // we have the descend flag specified - egg_group->set_collide_flags(EggGroup::CF_descend); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("event"), check)) { - if (check == 1) { - // we have the event flag specified - egg_group->set_collide_flags(EggGroup::CF_event); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("keep"), check)) { - if (check == 1) { - // we have the keep flag specified - egg_group->set_collide_flags(EggGroup::CF_keep); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("solid"), check)) { - if (check == 1) { - // we have the solid flag specified - egg_group->set_collide_flags(EggGroup::CF_solid); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("center"), check)) { - if (check == 1) { - // we have the center flag specified - egg_group->set_collide_flags(EggGroup::CF_center); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("turnstile"), check)) { - if (check == 1) { - // we have the turnstile flag specified - egg_group->set_collide_flags(EggGroup::CF_turnstile); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("level"), check)) { - if (check == 1) { - // we have the level flag specified - egg_group->set_collide_flags(EggGroup::CF_level); - } - } - if (node_desc->get_max_node()->GetUserPropInt(_T("intangible"), check)) { - if (check == 1) { - // we have the intangible flag specified - egg_group->set_collide_flags(EggGroup::CF_intangible); - } - } - return; -} diff --git a/pandatool/src/maxegg/maxNodeTree.h b/pandatool/src/maxegg/maxNodeTree.h deleted file mode 100644 index 1c4201ad001..00000000000 --- a/pandatool/src/maxegg/maxNodeTree.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxNodeTree.h - * @author crevilla - * from mayaNodeTree.h created by: drose (06Jun03) - */ - -#ifndef MAXNODETREE_H -#define MAXNODETREE_H - -class EggData; -class EggGroupNode; - -/** - * Describes a complete tree of max nodes for conversion. - */ -class MaxNodeTree { -public: - MaxNodeTree(); - MaxNodeDesc *build_node(INode *max_node); - MaxNodeDesc *build_joint(INode *max_node, MaxNodeDesc *node_joint); - bool build_complete_hierarchy(INode *root, ULONG *selection_list, int len); - MaxNodeDesc *find_node(INode *max_node); - MaxNodeDesc *find_joint(INode *max_node); - - int get_num_nodes() const; - MaxNodeDesc *get_node(int n) const; - - void clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node); - EggGroup *get_egg_group(MaxNodeDesc *node_desc); - EggTable *get_egg_table(MaxNodeDesc *node_desc); - EggXfmSAnim *get_egg_anim(MaxNodeDesc *node_desc); - - MaxNodeDesc* _root; - PN_stdfloat _fps; - // the flag for the setting up collision bool _has_collision; - // EggGroup::CollideFlags _cf_type; EggGroup::CollisionSolidType _cs_type; - bool _export_mesh; - -private: - EggData *_egg_data; - EggGroupNode *_egg_root; - EggGroupNode *_skeleton_node; - - MaxNodeDesc *r_build_node(INode *max_node); - MaxNodeDesc *r_build_joint(MaxNodeDesc *node_desc, INode *max_node); - bool node_in_list(ULONG handle, ULONG *list, int len); - bool r_build_hierarchy(INode *root, ULONG *selection_list, int len); - bool is_joint(INode *node); - void set_collision_tags(MaxNodeDesc *node_desc, EggGroup *egg_group); - - typedef pmap NodesByPath; - NodesByPath _nodes_by_path; - - typedef pvector Nodes; - Nodes _nodes; -}; - -#endif diff --git a/pandatool/src/maxegg/maxOptionsDialog.cxx b/pandatool/src/maxegg/maxOptionsDialog.cxx deleted file mode 100644 index fdcd46cf3ee..00000000000 --- a/pandatool/src/maxegg/maxOptionsDialog.cxx +++ /dev/null @@ -1,701 +0,0 @@ -/* - maxEggExpOptions.cxx - Created by Phillip Saltzman, 2/15/05 - Carnegie Mellon University, Entetainment Technology Center - - This file implements the classes that are used to choose - what to export from 3D Studio max - - Updated by Fei Wang, Carnegie Mellon University Entertainment - Technology Center student, 14Aug2009: added enableAddCollisionChoices -*/ - -#include "maxEgg.h" - -// Disable the forcing int to true or false performance warning -#pragma warning(disable: 4800) - -void SetICustEdit(HWND wnd, int nIDDlgItem, TCHAR *text) -{ - ICustEdit *edit = GetICustEdit(GetDlgItem(wnd, nIDDlgItem)); - edit->SetText(text); - ReleaseICustEdit(edit); -} - -void SetICustEdit(HWND wnd, int nIDDlgItem, int n) -{ - TCHAR text[80]; - _stprintf(text, _T("%d"), n); - ICustEdit *edit = GetICustEdit(GetDlgItem(wnd, nIDDlgItem)); - edit->SetText(text); - ReleaseICustEdit(edit); -} - -TCHAR *GetICustEditT(HWND wnd) -{ - static TCHAR buffer[2084]; - ICustEdit *edit = GetICustEdit(wnd); - edit->GetText(buffer, 2084); - ReleaseICustEdit(edit); - return buffer; -} - -int GetICustEditI(HWND wnd, BOOL *valid) -{ - ICustEdit *edit = GetICustEdit(wnd); - int i = edit->GetInt(valid); - ReleaseICustEdit(edit); - return i; -} - -void ChunkSave(ISave *isave, int chunkid, int value) -{ - ULONG nb; - isave->BeginChunk(chunkid); - isave->Write(&value, sizeof(int), &nb); - isave->EndChunk(); -} - -void ChunkSave(ISave *isave, int chunkid, ULONG value) -{ - ULONG nb; - isave->BeginChunk(chunkid); - isave->Write(&value, sizeof(ULONG), &nb); - isave->EndChunk(); -} - -void ChunkSave(ISave *isave, int chunkid, bool value) -{ - ULONG nb; - isave->BeginChunk(chunkid); - isave->Write(&value, sizeof(bool), &nb); - isave->EndChunk(); -} - -void ChunkSave(ISave *isave, int chunkid, TCHAR *value) -{ - ULONG nb; - isave->BeginChunk(chunkid); - int length = _tcslen(value) + 1; - isave->Write(&length, sizeof(int), &nb); - isave->Write(value, length * sizeof(TCHAR), &nb); - isave->EndChunk(); -} - -TCHAR *ChunkLoadString(ILoad *iload, TCHAR *buffer, int maxLength) -{ - ULONG nb; - int length; - IOResult res; - res = iload->Read(&length, sizeof(int), &nb); - assert(res == IO_OK && length <= maxLength); - res = iload->Read(buffer, length * sizeof(TCHAR), &nb); - assert(res == IO_OK); - return buffer; -} - -int ChunkLoadInt(ILoad *iload) -{ - ULONG nb; - int value; - IOResult res; - res = iload->Read(&value, sizeof(int), &nb); - assert(res == IO_OK); - return value; -} - -int ChunkLoadULONG(ILoad *iload) -{ - ULONG nb, value; - IOResult res; - res = iload->Read(&value, sizeof(ULONG), &nb); - assert(res == IO_OK); - return value; -} - -bool ChunkLoadBool(ILoad *iload) -{ - ULONG nb; - bool value; - IOResult res; - res = iload->Read(&value, sizeof(bool), &nb); - assert(res == IO_OK); - return value; -} - -void showAnimControls(HWND hWnd, BOOL val) { - ShowWindow(GetDlgItem(hWnd, IDC_EF_LABEL), val); - ShowWindow(GetDlgItem(hWnd, IDC_EF), val); - ShowWindow(GetDlgItem(hWnd, IDC_SF_LABEL), val); - SetWindowText(GetDlgItem(hWnd, IDC_EXP_SEL_FRAMES), - val ? _T("Use Range:") : _T("Use Frame:")); -} - -void enableAnimControls(HWND hWnd, BOOL val) { - EnableWindow(GetDlgItem(hWnd, IDC_SF_LABEL), val); - EnableWindow(GetDlgItem(hWnd, IDC_SF), val); - EnableWindow(GetDlgItem(hWnd, IDC_EF_LABEL), val); - EnableWindow(GetDlgItem(hWnd, IDC_EF), val); -} - -void enableChooserControls(HWND hWnd, BOOL val) { - EnableWindow(GetDlgItem(hWnd, IDC_LIST_EXPORT), val); - EnableWindow(GetDlgItem(hWnd, IDC_ADD_EXPORT), val); - EnableWindow(GetDlgItem(hWnd, IDC_REMOVE_EXPORT), val); -} - - -#define ANIM_RAD_NONE 0 -#define ANIM_RAD_EXPALL 1 -#define ANIM_RAD_EXPSEL 2 -#define ANIM_RAD_ALL 3 -void enableAnimRadios(HWND hWnd, int mask) { - EnableWindow(GetDlgItem(hWnd, IDC_EXP_ALL_FRAMES), mask & ANIM_RAD_EXPALL); - EnableWindow(GetDlgItem(hWnd, IDC_EXP_SEL_FRAMES), mask & ANIM_RAD_EXPSEL); -} - -// Handles the work of actually picking the target. -class AddNodeCB : public HitByNameDlgCallback -{ -public: - MaxOptionsDialog *ph; //Pointer to the parent class - HWND hWnd; //Handle to the parent dialog - - AddNodeCB (MaxOptionsDialog *instance, HWND wnd) : - ph(instance), hWnd(wnd) {} - -#if MAX_VERSION_MAJOR < 15 - virtual TCHAR *dialogTitle() {return _T("Objects to Export");} - virtual TCHAR *buttonText() {return _T("Select");} -#else - virtual const MCHAR *dialogTitle() {return _M("Objects to Export");} - virtual const MCHAR *buttonText() {return _M("Select");} -#endif - - virtual int filter(INode *node); - virtual void proc(INodeTab &nodeTab); -}; - -// This tells what should be in the list Allow only triangular objects, nurbs, -// and joints -int AddNodeCB::filter(INode *node) { - if (!node) return 0; - - Object *obj = node->EvalWorldState(0).obj; - Control *c = node->GetTMController(); - NURBSSet getSet; - bool is_bone = (node->GetBoneNodeOnOff() || //True for bones - (c && //True for bipeds - ((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) || - (c->ClassID() == BIPBODY_CONTROL_CLASS_ID) || - (c->ClassID() == FOOTPRINT_CLASS_ID)))); - - - if (IsDlgButtonChecked(hWnd, IDC_ANIMATION) == BST_CHECKED) - return is_bone && !ph->FindNode(node->GetHandle()); - else - return ( - is_bone || ((obj->SuperClassID() == HELPER_CLASS_ID && obj->ClassID() != MaxEggPlugin_CLASS_ID)) || - ((obj->SuperClassID() == GEOMOBJECT_CLASS_ID && //Allow geometrics - obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) || - (obj->SuperClassID() == SHAPE_CLASS_ID && //Allow CV NURBS - obj->ClassID() == EDITABLE_SURF_CLASS_ID && - GetNURBSSet(obj, 0, getSet, TRUE) && - getSet.GetNURBSObject(0)->GetType() == kNCVCurve)) && - !ph->FindNode(node->GetHandle())); //Only allow items not already selected -} - -// Adds all of the selected items to the list -void AddNodeCB::proc(INodeTab &nodeTab) { - - for (int i = 0; i < nodeTab.Count(); i++) - ph->AddNode(nodeTab[i]->GetHandle()); - ph->RefreshNodeList(hWnd); -} - -// This callback class generates a list of nodes that have previously been -// selected -class RemoveNodeCB : public HitByNameDlgCallback -{ -public: - MaxOptionsDialog *ph; //Pointer to the parent class - HWND hWnd; //Handle to the parent dialog - - RemoveNodeCB (MaxOptionsDialog *instance, HWND wnd) : - ph(instance), hWnd(wnd) {} - -#if MAX_VERSION_MAJOR < 15 - virtual TCHAR *dialogTitle() {return _T("Objects to Remove");} - virtual TCHAR *buttonText() {return _T("Remove");} -#else - virtual const MCHAR *dialogTitle() {return _M("Objects to Remove");} - virtual const MCHAR *buttonText() {return _M("Remove");} -#endif - - virtual int filter(INode *node) {return (node && ph->FindNode(node->GetHandle()));} - virtual void proc(INodeTab &nodeTab); -}; - - -// Adds all of the selected items to the list -void RemoveNodeCB::proc(INodeTab &nodeTab) { - for (int i = 0; i < nodeTab.Count(); i++) - ph->RemoveNodeByHandle(nodeTab[i]->GetHandle()); - ph->RefreshNodeList(hWnd); -} - -MaxEggOptions::MaxEggOptions() { - _max_interface = nullptr; - _anim_type = MaxEggOptions::AT_model; - _start_frame = INT_MIN; - _end_frame = INT_MIN; - _double_sided = false; - - - _file_name[0]=0; - _short_name[0]=0; - _path_replace = new PathReplace; - _path_replace->_path_store = PS_relative; - _export_whole_scene = true; - _export_all_frames = true; - _successful = false; -} - -INT_PTR CALLBACK MaxOptionsDialogProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) -{ - TCHAR tempFilename[2048]; - // We pass in our plugin through the lParam variable. Let's convert it - // back. - MaxOptionsDialog *imp = (MaxOptionsDialog*)GetWindowLongPtr(hWnd,GWLP_USERDATA); - if ( !imp && message != WM_INITDIALOG ) return FALSE; - - switch(message) { - - case WM_INITDIALOG: - // this line is very necessary to pass the plugin as the lParam - SetWindowLongPtr(hWnd,GWLP_USERDATA,lParam); - ((MaxOptionsDialog*)lParam)->UpdateUI(hWnd); - - return TRUE; break; - - case WM_CLOSE: - EndDialog(hWnd, FALSE); - return TRUE; break; - - case WM_COMMAND: - // The modified control is found in the lower word of the wParam long. - switch( LOWORD(wParam) ) { - case IDC_MODEL: - if (HIWORD(wParam) == BN_CLICKED) { - SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED), - _T("Export Meshes:")); - enableAnimRadios(hWnd, ANIM_RAD_NONE); - showAnimControls(hWnd, TRUE); - enableAnimControls(hWnd, FALSE); - if (imp->_prev_type == MaxEggOptions::AT_chan) imp->ClearNodeList(hWnd); - imp->_prev_type = MaxEggOptions::AT_model; - - return TRUE; - } - break; - - case IDC_ANIMATION: - if (HIWORD(wParam) == BN_CLICKED) { - SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED), - _T("Export Bones:")); - enableAnimRadios(hWnd, ANIM_RAD_ALL); - showAnimControls(hWnd, TRUE); - enableAnimControls(hWnd, IsDlgButtonChecked(hWnd, IDC_EXP_SEL_FRAMES)); - if (imp->_prev_type != MaxEggOptions::AT_chan) imp->ClearNodeList(hWnd); - imp->_prev_type = MaxEggOptions::AT_chan; - CheckRadioButton(hWnd, IDC_EXP_ALL_FRAMES, IDC_EXP_SEL_FRAMES, IDC_EXP_ALL_FRAMES); - - return TRUE; - } - break; - case IDC_BOTH: - if (HIWORD(wParam) == BN_CLICKED) { - SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED), - _T("Export Models:")); - enableAnimRadios(hWnd, ANIM_RAD_ALL); - showAnimControls(hWnd, TRUE); - enableAnimControls(hWnd, IsDlgButtonChecked(hWnd, IDC_EXP_SEL_FRAMES)); - if (imp->_prev_type == MaxEggOptions::AT_chan) imp->ClearNodeList(hWnd); - imp->_prev_type = MaxEggOptions::AT_both; - CheckRadioButton(hWnd, IDC_EXP_ALL_FRAMES, IDC_EXP_SEL_FRAMES, IDC_EXP_ALL_FRAMES); - - return TRUE; - } - break; - case IDC_POSE: - if (HIWORD(wParam) == BN_CLICKED) { - SetWindowText(GetDlgItem(hWnd, IDC_EXPORT_SELECTED), - _T("Export Meshes:")); - enableAnimRadios(hWnd, ANIM_RAD_EXPSEL); - showAnimControls(hWnd, FALSE); - enableAnimControls(hWnd, TRUE); - CheckRadioButton(hWnd, IDC_EXP_ALL_FRAMES, IDC_EXP_SEL_FRAMES, IDC_EXP_SEL_FRAMES); - if (imp->_prev_type == MaxEggOptions::AT_chan) imp->ClearNodeList(hWnd); - imp->_prev_type = MaxEggOptions::AT_pose; - - return TRUE; - } - break; - case IDC_EXP_ALL_FRAMES: - if (HIWORD(wParam) == BN_CLICKED) { - enableAnimControls(hWnd, FALSE); - if(imp->_prev_type == MaxEggOptions::AT_chan) - { - CheckRadioButton(hWnd, IDC_MODEL, IDC_POSE, IDC_ANIMATION); - } - if(imp->_prev_type == MaxEggOptions::AT_both) - { - CheckRadioButton(hWnd, IDC_MODEL, IDC_POSE, IDC_BOTH); - } - return TRUE; - } - break; - - case IDC_EXP_SEL_FRAMES: - if (HIWORD(wParam) == BN_CLICKED) { - enableAnimControls(hWnd, TRUE); - if(imp->_prev_type == MaxEggOptions::AT_chan) - { - CheckRadioButton(hWnd, IDC_MODEL, IDC_POSE, IDC_ANIMATION); - } - if(imp->_prev_type == MaxEggOptions::AT_both) - { - CheckRadioButton(hWnd, IDC_MODEL, IDC_POSE, IDC_BOTH); - } - return TRUE; - } - break; - - case IDC_EXPORT_ALL: - if (HIWORD(wParam) == BN_CLICKED) { - enableChooserControls(hWnd, FALSE); - return TRUE; - } - break; - - case IDC_EXPORT_SELECTED: - if (HIWORD(wParam) == BN_CLICKED) { - enableChooserControls(hWnd, TRUE); - return TRUE; - } - break; - - - // deal with adding meshes - case IDC_ADD_EXPORT: - { - if (!imp->_choosing_nodes) { - AddNodeCB PickCB(imp, hWnd); - imp->_choosing_nodes = true; - imp->_max_interface->DoHitByNameDialog(&PickCB); - imp->_choosing_nodes = false; - } - } - return TRUE; break; - - case IDC_REMOVE_EXPORT: - { - if (!imp->_choosing_nodes) { - imp->_choosing_nodes = true; - RemoveNodeCB PickCB(imp, hWnd); - imp->_max_interface->DoHitByNameDialog(&PickCB); - imp->_choosing_nodes = false; - } - } - return TRUE; break; - - case IDC_OK: - if (imp->UpdateFromUI(hWnd)) EndDialog(hWnd, TRUE); - return TRUE; break; - case IDC_CANCEL: - EndDialog(hWnd, FALSE); - return TRUE; break; - case IDC_BROWSE: - OPENFILENAME ofn; - _tcscpy(tempFilename, GetICustEditT(GetDlgItem(hWnd, IDC_FILENAME))); - - memset(&ofn, 0, sizeof(ofn)); - ofn.nMaxFile = 2047; - ofn.lpstrFile = tempFilename; - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = hWnd; - ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST; - ofn.lpstrDefExt = _T("egg"); - ofn.lpstrFilter = _T("Panda3D Egg Files (*.egg)\0*.egg\0All Files (*.*)\0*.*\0"); - - SetFocus(GetDlgItem(hWnd, IDC_FILENAME)); - if (GetSaveFileName(&ofn)) - SetICustEdit(hWnd, IDC_FILENAME, ofn.lpstrFile); - // else { char buf[255]; sprintf(buf, "%d", - // CommDlgExtendedError()); MessageBox(hWnd, buf, "Error on - // GetSaveFileName", MB_OK); } - return TRUE; break; - case IDC_CHECK1: - if (IsDlgButtonChecked(hWnd, IDC_CHECK1)) - if (MessageBox(hWnd, _T("Warning: Exporting double-sided polygons can severely hurt ") - _T("performance in Panda3D.\n\nAre you sure you want to export them?"), - _T("Panda3D Exporter"), MB_YESNO | MB_ICONQUESTION) != IDYES) - CheckDlgButton(hWnd, IDC_CHECK1, BST_UNCHECKED); - return TRUE; break; - - default: - // char buf[255]; sprintf(buf, "%d", LOWORD(wParam)); - // MessageBox(hWnd, buf, "Unknown WParam", MB_OK); - break; - } - } - return FALSE; -} - -void MaxOptionsDialog::SetAnimRange() { - // Get the start and end frames and the animation frame rate from Max - Interval anim_range = _max_interface->GetAnimRange(); - _min_frame = anim_range.Start()/GetTicksPerFrame(); - _max_frame = anim_range.End()/GetTicksPerFrame(); -} - -MaxOptionsDialog::MaxOptionsDialog() : - MaxEggOptions(), - _min_frame(0), - _max_frame(0), - _checked(true), - _choosing_nodes(false), - _prev_type(AT_model) -{ -} - -MaxOptionsDialog::~MaxOptionsDialog () -{ -} - - -void MaxOptionsDialog::UpdateUI(HWND hWnd) { - int typeButton = IDC_MODEL; - int anim_exp = _export_all_frames ? IDC_EXP_ALL_FRAMES : IDC_EXP_SEL_FRAMES; - int model_exp = _export_whole_scene ? IDC_EXPORT_ALL : IDC_EXPORT_SELECTED; - - switch (_anim_type) { - case MaxEggOptions::AT_chan: typeButton = IDC_ANIMATION; break; - case MaxEggOptions::AT_both: typeButton = IDC_BOTH; break; - case MaxEggOptions::AT_pose: typeButton = IDC_POSE; break; - case MaxEggOptions::AT_model: typeButton = IDC_MODEL; break; - } - - _prev_type = _anim_type; - - CheckRadioButton(hWnd, IDC_MODEL, IDC_POSE, typeButton); - SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(typeButton, BN_CLICKED), 0); - CheckRadioButton(hWnd, IDC_EXPORT_ALL, IDC_EXPORT_SELECTED, model_exp); - SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(model_exp, BN_CLICKED), 0); - CheckRadioButton(hWnd, IDC_EXP_ALL_FRAMES, IDC_EXP_SEL_FRAMES, anim_exp); - SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(anim_exp, BN_CLICKED), 0); - - CheckDlgButton(hWnd, IDC_CHECK1, - _double_sided ? BST_CHECKED : BST_UNCHECKED); - - - SetICustEdit(hWnd, IDC_FILENAME, _file_name); - if (_start_frame != INT_MIN) { - SetICustEdit(hWnd, IDC_SF, _start_frame); - SetICustEdit(hWnd, IDC_EF, _end_frame); - } else { - SetICustEdit(hWnd, IDC_SF, _min_frame); - SetICustEdit(hWnd, IDC_EF, _max_frame); - } - - RefreshNodeList(hWnd); -} - -void MaxOptionsDialog::ClearNodeList(HWND hWnd) { - _node_list.clear(); - RefreshNodeList(hWnd); -} - -void MaxOptionsDialog::RefreshNodeList(HWND hWnd) { - // Clear and repopulate the node box - HWND nodeLB = GetDlgItem(hWnd, IDC_LIST_EXPORT); - SendMessage(nodeLB, LB_RESETCONTENT, 0, 0); - for (int i = 0; i < _node_list.size(); i++) { - INode *temp = _max_interface->GetINodeByHandle(_node_list[i]); - const TCHAR *name = _T("Unknown Node"); - if (temp) name = temp->GetName(); - SendMessage(nodeLB, LB_ADDSTRING, 0, (LPARAM)name); - } -} - -bool MaxOptionsDialog::UpdateFromUI(HWND hWnd) { - BOOL valid; - Anim_Type newAnimType; - int newSF = INT_MIN, newEF = INT_MIN; - TCHAR msg[1024]; - - if (IsDlgButtonChecked(hWnd, IDC_MODEL)) newAnimType = MaxEggOptions::AT_model; - else if (IsDlgButtonChecked(hWnd, IDC_ANIMATION)) newAnimType = MaxEggOptions::AT_chan; - else if (IsDlgButtonChecked(hWnd, IDC_BOTH)) newAnimType = MaxEggOptions::AT_both; - else newAnimType = MaxEggOptions::AT_pose; - - if (newAnimType != MaxEggOptions::AT_model && IsDlgButtonChecked(hWnd, IDC_EXP_SEL_FRAMES)) { - newSF = GetICustEditI(GetDlgItem(hWnd, IDC_SF), &valid); - if (!valid) { - MessageBox(hWnd, _T("Start Frame must be an integer"), _T("Invalid Value"), MB_OK | MB_ICONEXCLAMATION); - return false; - } - if (newSF < _min_frame) { - _stprintf(msg, _T("Start Frame must be at least %d"), _min_frame); - MessageBox(hWnd, msg, _T("Invalid Value"), MB_OK | MB_ICONEXCLAMATION); - return false; - } - if (newSF > _max_frame) { - _stprintf(msg, _T("Start Frame must be at most %d"), _max_frame); - MessageBox(hWnd, msg, _T("Invalid Value"), MB_OK | MB_ICONEXCLAMATION); - return false; - } - if (newAnimType != MaxEggOptions::AT_pose) { - newEF = GetICustEditI(GetDlgItem(hWnd, IDC_EF), &valid); - if (!valid) { - MessageBox(hWnd, _T("End Frame must be an integer"), _T("Invalid Value"), MB_OK | MB_ICONEXCLAMATION); - return false; - } - if (newEF > _max_frame) { - _stprintf(msg, _T("End Frame must be at most %d"), _max_frame); - MessageBox(hWnd, msg, _T("Invalid Value"), MB_OK | MB_ICONEXCLAMATION); - return false; - } - if (newEF < newSF) { - MessageBox(hWnd, _T("End Frame must be greater than the start frame"), _T("Invalid Value"), MB_OK | MB_ICONEXCLAMATION); - return false; - } - } - } - - TCHAR *temp = GetICustEditT(GetDlgItem(hWnd, IDC_FILENAME)); - if (!_tcslen(temp)) { - MessageBox(hWnd, _T("The filename cannot be empty"), _T("Invalid Value"), MB_OK | MB_ICONEXCLAMATION); - return false; - } - - if (_tcslen(temp) < 4 || _tcsncmp(_T(".egg"), temp+(_tcslen(temp) - 4), 4)) { - _stprintf(_file_name, _T("%s.egg"), temp); - } else { - _tcscpy(_file_name, temp); - } - - temp = _tcsrchr(_file_name, '\\'); - if (!temp) temp = _file_name; - else temp++; - - if (_tcslen(temp) > sizeof(_short_name)) - _stprintf(_short_name, _T("%.*s..."), sizeof(_short_name)-4, temp); - else { - _tcscpy(_short_name, temp); - _short_name[_tcslen(_short_name) - 4] = 0; //Cut off the .egg - } - - _start_frame = newSF; - _end_frame = newEF; - _anim_type = newAnimType; - _double_sided = IsDlgButtonChecked(hWnd, IDC_CHECK1); - - - _export_whole_scene = IsDlgButtonChecked(hWnd, IDC_EXPORT_ALL); - _export_all_frames = IsDlgButtonChecked(hWnd, IDC_EXP_ALL_FRAMES); - - return true; -} - -bool MaxOptionsDialog::FindNode(ULONG INodeHandle) { - for (int i = 0; i < _node_list.size(); i++) - if (_node_list[i] == INodeHandle) return true; - return false; -} - -void MaxOptionsDialog::AddNode(ULONG INodeHandle) { - if (FindNode(INodeHandle)) return; - _node_list.push_back(INodeHandle); -} - -void MaxOptionsDialog::CullBadNodes() { - if (!_max_interface) return; - std::vector good; - for (int i=0; i<_node_list.size(); i++) { - ULONG handle = _node_list[i]; - if (_max_interface->GetINodeByHandle(handle)) { - good.push_back(handle); - } - } - _node_list = good; -} - -void MaxOptionsDialog::RemoveNode(int i) { - if (i >= 0 && i < _node_list.size()) { - for (int j = i+1; j < _node_list.size(); j++) - _node_list[i++] = _node_list[j++]; - _node_list.pop_back(); - } -} - -void MaxOptionsDialog::RemoveNodeByHandle(ULONG INodeHandle) { - for (int i = 0; i < _node_list.size(); i++) { - if (_node_list[i] == INodeHandle) { - RemoveNode(i); - return; - } - } -} - -IOResult MaxOptionsDialog::Save(ISave *isave) { - isave->BeginChunk(CHUNK_EGG_EXP_OPTIONS); - ChunkSave(isave, CHUNK_ANIM_TYPE, _anim_type); - ChunkSave(isave, CHUNK_FILENAME, _file_name); - ChunkSave(isave, CHUNK_SHORTNAME, _short_name); - ChunkSave(isave, CHUNK_SF, _start_frame); - ChunkSave(isave, CHUNK_EF, _end_frame); - ChunkSave(isave, CHUNK_DBL_SIDED, _double_sided); - ChunkSave(isave, CHUNK_EGG_CHECKED, _checked); - ChunkSave(isave, CHUNK_ALL_FRAMES, _export_all_frames); - ChunkSave(isave, CHUNK_EXPORT_FULL, _export_whole_scene); - - isave->BeginChunk(CHUNK_NODE_LIST); - for (int i = 0; i < _node_list.size(); i++) - ChunkSave(isave, CHUNK_NODE_HANDLE, _node_list[i]); - isave->EndChunk(); - isave->EndChunk(); - return IO_OK; -} - -IOResult MaxOptionsDialog::Load(ILoad *iload) { - IOResult res = iload->OpenChunk(); - - while (res == IO_OK) { - switch(iload->CurChunkID()) { - case CHUNK_ANIM_TYPE: _anim_type = (Anim_Type)ChunkLoadInt(iload); break; - case CHUNK_FILENAME: ChunkLoadString(iload, _file_name, sizeof(_file_name)); break; - case CHUNK_SHORTNAME: ChunkLoadString(iload, _short_name, sizeof(_short_name)); break; - case CHUNK_SF: _start_frame = ChunkLoadInt(iload); break; - case CHUNK_EF: _end_frame = ChunkLoadInt(iload); break; - case CHUNK_DBL_SIDED: _double_sided = ChunkLoadBool(iload); break; - case CHUNK_EGG_CHECKED: _checked = ChunkLoadBool(iload); break; - case CHUNK_ALL_FRAMES: _export_all_frames = ChunkLoadBool(iload); break; - case CHUNK_EXPORT_FULL: _export_whole_scene = ChunkLoadBool(iload); break; - - case CHUNK_NODE_LIST: - res = iload->OpenChunk(); - while (res == IO_OK) { - if (iload->CurChunkID() == CHUNK_NODE_HANDLE) AddNode(ChunkLoadULONG(iload)); - iload->CloseChunk(); - res = iload->OpenChunk(); - } - break; - } - iload->CloseChunk(); - res = iload->OpenChunk(); - } - - if (res == IO_END) return IO_OK; - return IO_ERROR; -} diff --git a/pandatool/src/maxegg/maxOptionsDialog.h b/pandatool/src/maxegg/maxOptionsDialog.h deleted file mode 100644 index 8e0d899f778..00000000000 --- a/pandatool/src/maxegg/maxOptionsDialog.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - maxEggExpOptions.h - Created by Phillip Saltzman, 2/15/05 - Carnegie Mellon University, Entetainment Technology Center - - This file contains a class that allows users to specify - export options, and then execute the export -*/ - -#ifndef __maxEggExpOptions__H -#define __maxEggExpOptions__H - -#include "pathReplace.h" - -#pragma conform(forScope, off) - -/* Externed Globals */ -extern HINSTANCE hInstance; - -// Saveload chunk definitions -#define CHUNK_OVERWRITE_FLAG 0x1000 -#define CHUNK_PVIEW_FLAG 0x1001 -#define CHUNK_LOG_OUTPUT 0x1002 -#define CHUNK_EGG_EXP_OPTIONS 0x1100 -#define CHUNK_ANIM_TYPE 0x1101 -#define CHUNK_EGG_CHECKED 0x1102 -#define CHUNK_DBL_SIDED 0x1103 -#define CHUNK_SF 0x1104 -#define CHUNK_EF 0x1105 -#define CHUNK_FILENAME 0x1106 -#define CHUNK_SHORTNAME 0x1107 -#define CHUNK_EXPORT_FULL 0x1108 -#define CHUNK_ALL_FRAMES 0x1109 -#define CHUNK_NODE_LIST 0x1200 -#define CHUNK_NODE_HANDLE 0x1201 -// #define CHUNK_ADD_COLLISION 0x1202 #define CHUNK_CS_TYPE 0x1203 -// #define CHUNK_CF_TYPE 0x1204 - -// Global functions -void ChunkSave(ISave *isave, int chunkid, int value); -void ChunkSave(ISave *isave, int chunkid, bool value); -void ChunkSave(ISave *isave, int chunkid, char *value); -TCHAR *ChunkLoadString(ILoad *iload, TCHAR *buffer, int maxLength); -int ChunkLoadInt(ILoad *iload); -bool ChunkLoadBool(ILoad *iload); -void SetICustEdit(HWND wnd, int nIDDlgItem, TCHAR *text); -INT_PTR CALLBACK MaxOptionsDialogProc(HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam ); - -struct MaxEggOptions -{ - MaxEggOptions(); - - enum Anim_Type { - AT_none, - AT_model, - AT_chan, - AT_pose, - AT_strobe, - AT_both - }; - - - IObjParam *_max_interface; - Anim_Type _anim_type; - int _start_frame; - int _end_frame; - bool _double_sided; - bool _successful; - bool _export_whole_scene; - bool _export_all_frames; - TCHAR _file_name[2048]; - TCHAR _short_name[256]; - PT(PathReplace) _path_replace; - std::vector _node_list; -}; - -class MaxOptionsDialog : public MaxEggOptions -{ - friend class MaxEggPlugin; - - public: - int _min_frame, _max_frame; - bool _checked; - bool _choosing_nodes; - MaxEggOptions::Anim_Type _prev_type; - - MaxOptionsDialog(); - ~MaxOptionsDialog(); - - // All these List functions should probably take what list they need to - // operate on rather than just operating on a global list - void SetMaxInterface(IObjParam *iface) { _max_interface = iface; } - void UpdateUI(HWND hWnd); - bool UpdateFromUI(HWND hWnd); - void RefreshNodeList(HWND hWnd); - void SetAnimRange(); - - bool FindNode(ULONG INodeHandle); //returns true if the node is already in the list - void AddNode(ULONG INodeHandle); - void RemoveNode(int i); - void RemoveNodeByHandle(ULONG INodeHandle); - void ClearNodeList(HWND hWnd); - void CullBadNodes(); - - ULONG GetNode(int i) { return (i >= 0 && i < _node_list.size()) ? _node_list[i] : ULONG_MAX; } - - IOResult Load(ILoad *iload); - IOResult Save(ISave *isave); -}; - -#endif // __MaxEggExpOptions__H diff --git a/pandatool/src/maxegg/maxResource.h b/pandatool/src/maxegg/maxResource.h deleted file mode 100644 index 004a17b8be4..00000000000 --- a/pandatool/src/maxegg/maxResource.h +++ /dev/null @@ -1,53 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by maxEgg.rc -// -#define IDS_LIBDESCRIPTION 1 -#define IDS_CATEGORY 2 -#define IDS_CLASS_NAME 3 -#define IDS_PARAMS 4 -#define IDS_SPIN 5 -#define IDD_PANEL 101 -#define IDD_EGG_DETAILS 102 -#define IDC_EGGS_LABEL 1019 -#define IDC_ADD_EGG 1021 -#define IDC_EDIT_EGG 1022 -#define IDC_REMOVE_EGG 1023 -#define IDC_LIST_EGGS 1024 -#define IDC_OVERWRITE_CHECK 1027 -#define IDC_EXPORT 1028 -#define IDC_PANEL_TITLE 1029 -#define IDC_OVERWRITE_CHECK2 1030 -#define IDC_PVIEW_CHECK 1030 -#define IDC_MODEL 1033 -#define IDC_ANIMATION 1034 -#define IDC_BOTH 1035 -#define IDC_POSE 1036 -#define IDC_FILENAME 1038 -#define IDC_BROWSE 1039 -#define IDC_EXPORT_ALL 1040 -#define IDC_EXPORT_SELECTED 1041 -#define IDC_ADD_EXPORT 1043 -#define IDC_LIST_EXPORT 1044 -#define IDC_REMOVE_EXPORT 1046 -#define IDC_EXP_ALL_FRAMES 1049 -#define IDC_EXP_SEL_FRAMES 1050 -#define IDC_SF 1051 -#define IDC_SF_LABEL 1052 -#define IDC_EF 1053 -#define IDC_CHECK1 1054 -#define IDC_EF_LABEL 1057 -#define IDC_OK 1058 -#define IDC_CANCEL 1059 -#define IDC_LOGGING 1060 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 103 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1080 -#define _APS_NEXT_SYMED_VALUE 102 -#endif -#endif diff --git a/pandatool/src/maxegg/maxToEggConverter.cxx b/pandatool/src/maxegg/maxToEggConverter.cxx deleted file mode 100644 index 41718f66e82..00000000000 --- a/pandatool/src/maxegg/maxToEggConverter.cxx +++ /dev/null @@ -1,1416 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxToEggConverter.cxx - * @author Corey Revilla and Ken Strickland - * @date 2003-06-22 - * from mayaToEggConverter.cxx created by drose (10Nov99) - * - * Updated by Fei Wang, Carnegie Mellon University Entertainment - * Technology Center student, 29Jul2009: Fixed vertex color, - * animation hierarchy, texture swapping bugs; added collision choices to - * exporter. - * - * Updated by Andrew Gartner, Carnegie Mellon University Entertainment - * Technology Center. 27Apr2010: Collision is now done through User Defined Properties - * By default a plane without a standard material gets UV's as well - * as any object without a texture but with a standard material. - * Point objects are now supported as "locators" for a point in space - * within the egg. - */ - -#include "maxEgg.h" -#include "config_putil.h" - -using std::string; - -/** - * - */ -MaxToEggConverter:: -MaxToEggConverter() -{ - reset(); -} - -/** - * - */ -MaxToEggConverter:: -~MaxToEggConverter() -{ -} - -/** - - */ -void MaxToEggConverter::reset() { - _cur_tref = 0; - _current_frame = 0; - _textures.clear(); - _egg_data = nullptr; -} - -/** - * Fills up the egg_data structure according to the global Max model data. - * Returns true if successful, false if there is an error. If from_selection - * is true, the converted geometry is based on that which is selected; - * otherwise, it is the entire Max scene. - */ -bool MaxToEggConverter::convert(MaxEggOptions *options) { - - _options = options; - - Filename fn; -#ifdef _UNICODE - fn = Filename::from_os_specific_w(_options->_file_name); -#else - fn = Filename::from_os_specific(_options->_file_name); -#endif - - _options->_path_replace->_path_directory = fn.get_dirname(); - - _egg_data = new EggData; - if (_egg_data->get_coordinate_system() == CS_default) { - _egg_data->set_coordinate_system(CS_zup_right); - } - - // Figure out the animation parameters. - - // Get the start and end frames and the animation frame rate from Max - - Interval anim_range = _options->_max_interface->GetAnimRange(); - int start_frame = anim_range.Start()/GetTicksPerFrame(); - int end_frame = anim_range.End()/GetTicksPerFrame(); - - if (!_options->_export_all_frames) { - if (_options->_start_frame < start_frame) _options->_start_frame = start_frame; - if (_options->_start_frame > end_frame) _options->_start_frame = end_frame; - if (_options->_end_frame < start_frame) _options->_end_frame = start_frame; - if (_options->_end_frame > end_frame) _options->_end_frame = end_frame; - if (_options->_end_frame < _options->_start_frame) _options->_end_frame = _options->_start_frame; - start_frame = _options->_start_frame; - end_frame = _options->_end_frame; - } - - int frame_inc = 1; - int output_frame_rate = GetFrameRate(); - - bool all_ok = true; - - if (_options->_export_whole_scene) { - _tree._export_mesh = false; - all_ok = _tree.build_complete_hierarchy(_options->_max_interface->GetRootNode(), nullptr, 0); - } else { - _tree._export_mesh = true; - all_ok = _tree.build_complete_hierarchy(_options->_max_interface->GetRootNode(), &_options->_node_list.front(), _options->_node_list.size()); - } - - if (all_ok) { - switch (_options->_anim_type) { - case MaxEggOptions::AT_pose: - // pose: set to a specific frame, then get out the static - // geometry. sprintf(Logger::GetLogString(), "Extracting geometry - // from frame #%d.", start_frame); Logger::Log( MTEC, - // Logger::SAT_MEDIUM_LEVEL, Logger::GetLogString() ); - // Logger::Log( MTEC, Logger::SAT_MEDIUM_LEVEL, "Converting static - // model." ); - _current_frame = start_frame; - all_ok = convert_hierarchy(_egg_data); - break; - - case MaxEggOptions::AT_model: - // model: get out an animatable model with joints and vertex - // membership. - all_ok = convert_char_model(); - break; - - case MaxEggOptions::AT_chan: - // chan: get out a series of animation tables. - all_ok = convert_char_chan(start_frame, end_frame, frame_inc, - output_frame_rate); - break; - - case MaxEggOptions::AT_both: - // both: Put a model and its animation into the same egg file. - _options->_anim_type = MaxEggOptions::AT_model; - if (!convert_char_model()) { - all_ok = false; - } - _options->_anim_type = MaxEggOptions::AT_chan; - if (!convert_char_chan(start_frame, end_frame, frame_inc, - output_frame_rate)) { - all_ok = false; - } - // Set the type back to AT_both - _options->_anim_type = MaxEggOptions::AT_both; - break; - - default: - all_ok = false; - }; - - reparent_decals(_egg_data); - } - - if (all_ok) { - _egg_data->recompute_tangent_binormal_auto(); - _egg_data->remove_unused_vertices(true); - } - - _options->_successful = all_ok; - - if (all_ok) { -#ifdef _UNICODE - Filename fn = Filename::from_os_specific_w(_options->_file_name); -#else - Filename fn = Filename::from_os_specific(_options->_file_name); -#endif - return _egg_data->write_egg(fn); - } else { - return false; - } -} - -/** - * Converts the file as an animatable character model, with joints and vertex - * membership. - */ -bool MaxToEggConverter:: -convert_char_model() { - std::string character_name = "character"; - _current_frame = _options->_start_frame; - - EggGroup *char_node = new EggGroup(character_name); - _egg_data->add_child(char_node); - char_node->set_dart_type(EggGroup::DT_default); - - return convert_hierarchy(char_node); -} - -/** - * Converts the animation as a series of tables to apply to the character - * model, as retrieved earlier via AC_model. - */ -bool MaxToEggConverter:: -convert_char_chan(double start_frame, double end_frame, double frame_inc, - double output_frame_rate) { - std::string character_name = "character"; - - EggTable *root_table_node = new EggTable(); - _egg_data->add_child(root_table_node); - EggTable *bundle_node = new EggTable(character_name); - bundle_node->set_table_type(EggTable::TT_bundle); - root_table_node->add_child(bundle_node); - EggTable *skeleton_node = new EggTable(""); - bundle_node->add_child(skeleton_node); - - // Set the frame rate before we start asking for anim tables to be - // created. - _tree._fps = output_frame_rate / frame_inc; - _tree.clear_egg(_egg_data, nullptr, skeleton_node); - - // Now we can get the animation data by walking through all of the frames, - // one at a time, and getting the joint angles at each frame. - - // This is just a temporary EggGroup to receive the transform for each - // joint each frame. - EggGroup* tgroup; - - int num_nodes = _tree.get_num_nodes(); - int i; - - TimeValue frame = start_frame; - TimeValue frame_stop = end_frame; - while (frame <= frame_stop) { - _current_frame = frame; - for (i = 0; i < num_nodes; i++) { - // Find all joints in the hierarchy - MaxNodeDesc *node_desc = _tree.get_node(i); - if (node_desc->is_joint()) { - tgroup = new EggGroup(); - INode *max_node = node_desc->get_max_node(); - - if (node_desc->_parent && node_desc->_parent->is_joint()) { - // If this joint also has a joint as a parent, the - // parent's transformation has to be divided out of this - // joint's TM - get_joint_transform(max_node, node_desc->_parent->get_max_node(), - tgroup); - } else { - get_joint_transform(max_node, nullptr, tgroup); - } - - EggXfmSAnim *anim = _tree.get_egg_anim(node_desc); - if (!anim->add_data(tgroup->get_transform3d())) { - // *** log an error - } - delete tgroup; - } - } - - frame += frame_inc; - } - - // Now optimize all of the tables we just filled up, for no real good - // reason, except that it makes the resulting egg file a little easier to - // read. - for (i = 0; i < num_nodes; i++) { - MaxNodeDesc *node_desc = _tree.get_node(i); - if (node_desc->is_joint()) { - _tree.get_egg_anim(node_desc)->optimize(); - } - } - - return true; -} - -/** - * Generates egg structures for each node in the Max hierarchy. - */ -bool MaxToEggConverter:: -convert_hierarchy(EggGroupNode *egg_root) { - // int num_nodes = _tree.get_num_nodes(); - - _tree.clear_egg(_egg_data, egg_root, nullptr); - for (int i = 0; i < _tree.get_num_nodes(); i++) { - if (!process_model_node(_tree.get_node(i))) { - return false; - } - } - - return true; -} - -/** - * Converts the indicated Max node to the corresponding Egg structure. - * Returns true if successful, false if an error was encountered. - */ -bool MaxToEggConverter:: -process_model_node(MaxNodeDesc *node_desc) { - if (!node_desc->has_max_node()) { - // If the node has no Max equivalent, never mind. - return true; - } - - // Skip all nodes that represent joints in the geometry, but aren't the - // actual joints themselves - if (node_desc->is_node_joint()) { - return true; - } - - TimeValue time = 0; - INode *max_node = node_desc->get_max_node(); - - ObjectState state; - state = max_node->EvalWorldState(_current_frame * GetTicksPerFrame()); - - if (node_desc->is_joint()) { - EggGroup *egg_group = _tree.get_egg_group(node_desc); - // Don't bother with joints unless we're getting an animatable model. - if (_options->_anim_type == MaxEggOptions::AT_model) { - get_joint_transform(max_node, egg_group); - } - } else { - if (state.obj) { - EggGroup *egg_group = nullptr; - TriObject *myMaxTriObject; - Mesh max_mesh; - // Call the correct exporter based on what type of object this is. - switch( state.obj->SuperClassID() ){ - - case GEOMOBJECT_CLASS_ID: - egg_group = _tree.get_egg_group(node_desc); - get_transform(max_node, egg_group); - - // Try converting this geometric object to a mesh we can use. - if (!state.obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) { - return false; - } - // Convert our state object to a TriObject. - myMaxTriObject = (TriObject *) state.obj->ConvertToType(time, Class_ID(TRIOBJ_CLASS_ID, 0 )); - // *** Want to figure this problem out If actual conversion - // was required, then we want to delete this new mesh later to - // avoid mem leaks. **BROKEN. doesnt delete - - // Now, get the mesh. - max_mesh = myMaxTriObject->GetMesh(); - make_polyset(max_node, &max_mesh, egg_group); - - if (myMaxTriObject != state.obj) - delete myMaxTriObject; - break; - - case SHAPE_CLASS_ID: - if (state.obj->ClassID() == EDITABLE_SURF_CLASS_ID) { - NURBSSet getSet; - if (GetNURBSSet(state.obj, time, getSet, TRUE)) { - NURBSObject *nObj = getSet.GetNURBSObject(0); - if (nObj->GetType() == kNCVCurve) { - // It's a CV Curve, process it - egg_group = _tree.get_egg_group(node_desc); - get_transform(max_node, egg_group); - make_nurbs_curve(max_node, (NURBSCVCurve *)nObj, - time, egg_group); - } - } - } - break; - - case CAMERA_CLASS_ID: - break; - - case LIGHT_CLASS_ID: - break; - - case HELPER_CLASS_ID: - // we should export Point objects to give Max the equivalent of - // Maya locators - if (state.obj->ClassID() == Class_ID(POINTHELP_CLASS_ID, 0)) { - - egg_group = _tree.get_egg_group(node_desc); - get_transform(max_node, egg_group); - - } else { - - break; - - } - - - - - } - } - } - - return true; -} - -/** - * Extracts the transform on the indicated Maya node, and applies it to the - * corresponding Egg node. - */ -void MaxToEggConverter:: -get_transform(INode *max_node, EggGroup *egg_group) { - if (_options->_anim_type == MaxEggOptions::AT_model) { - // When we're getting an animated model, we only get transforms for - // joints. - return; - } - - if ( !egg_group ) { - return; - } - - // Gets the TM for this node, a matrix which encapsulates all - // transformations it takes to get to the current node, including parent - // transformations. - Matrix3 pivot = max_node->GetNodeTM(_current_frame * GetTicksPerFrame()); - - // This is the Panda-flava-flav-style matrix we'll be exporting to. - Point3 row0 = pivot.GetRow(0); - Point3 row1 = pivot.GetRow(1); - Point3 row2 = pivot.GetRow(2); - Point3 row3 = pivot.GetRow(3); - - LMatrix4d m4d(row0.x, row0.y, row0.z, 0.0f, - row1.x, row1.y, row1.z, 0.0f, - row2.x, row2.y, row2.z, 0.0f, - row3.x, row3.y, row3.z, 1.0f ); - - // Now here's the tricky part. I believe this command strips out the node - // "frame" which is the sum of all transformations enacted by the parent - // of this node. This should reduce to the transformation relative to - // this node's parent - m4d = m4d * egg_group->get_node_frame_inv(); - if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) { - egg_group->add_matrix4(m4d); - } -} - -/** - * Extracts the transform on the indicated Maya node, and applies it to the - * corresponding Egg node. - */ -LMatrix4d MaxToEggConverter:: -get_object_transform(INode *max_node) { - - // Gets the TM for this node, a matrix which encapsulates all - // transformations it takes to get to the current node, including parent - // transformations. - Matrix3 pivot = max_node->GetObjectTM(_current_frame * GetTicksPerFrame()); - - Point3 row0 = pivot.GetRow(0); - Point3 row1 = pivot.GetRow(1); - Point3 row2 = pivot.GetRow(2); - Point3 row3 = pivot.GetRow(3); - - LMatrix4d m4d(row0.x, row0.y, row0.z, 0.0f, - row1.x, row1.y, row1.z, 0.0f, - row2.x, row2.y, row2.z, 0.0f, - row3.x, row3.y, row3.z, 1.0f ); - return m4d; -} - -/** - * Extracts the transform on the indicated Maya node, as appropriate for a - * joint in an animated character, and applies it to the indicated node. This - * is different from get_transform() in that it does not respect the - * _transform_type flag, and it does not consider the relative transforms - * within the egg file. - */ -void MaxToEggConverter:: -get_joint_transform(INode *max_node, EggGroup *egg_group) { - - if ( !egg_group ) { - return; - } - - // Gets the TM for this node, a matrix which encapsulates all - // transformations it takes to get to the current node, including parent - // transformations. - Matrix3 pivot = max_node->GetNodeTM(_current_frame * GetTicksPerFrame()); - Point3 row0 = pivot.GetRow(0); - Point3 row1 = pivot.GetRow(1); - Point3 row2 = pivot.GetRow(2); - Point3 row3 = pivot.GetRow(3); - - LMatrix4d m4d(row0.x, row0.y, row0.z, 0.0f, - row1.x, row1.y, row1.z, 0.0f, - row2.x, row2.y, row2.z, 0.0f, - row3.x, row3.y, row3.z, 1.0f ); - - // Now here's the tricky part. I believe this command strips out the node - // "frame" which is the sum of all transformations enacted by the parent - // of this node. This should reduce to the transformation relative to - // this node's parent - m4d = m4d * egg_group->get_node_frame_inv(); - if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) { - egg_group->add_matrix4(m4d); - } -} - -/** - * Extracts the transform on the indicated Maya node, as appropriate for a - * joint in an animated character, and applies it to the indicated node. This - * is different from get_transform() in that it does not respect the - * _transform_type flag, and it does not consider the relative transforms - * within the egg file. - */ -void MaxToEggConverter:: -get_joint_transform(INode *max_node, INode *parent_node, EggGroup *egg_group) { - - if ( !egg_group ) { - return; - } - - // Gets the TM for this node, a matrix which encapsulates all - // transformations it takes to get to the current node, including parent - // transformations. - Matrix3 pivot = max_node->GetNodeTM(_current_frame * GetTicksPerFrame()); - Point3 row0 = pivot.GetRow(0); - Point3 row1 = pivot.GetRow(1); - Point3 row2 = pivot.GetRow(2); - Point3 row3 = pivot.GetRow(3); - - LMatrix4d m4d(row0.x, row0.y, row0.z, 0.0f, - row1.x, row1.y, row1.z, 0.0f, - row2.x, row2.y, row2.z, 0.0f, - row3.x, row3.y, row3.z, 1.0f ); - - if (parent_node) { - Matrix3 parent_pivot = parent_node->GetNodeTM(_current_frame * GetTicksPerFrame()); - // parent_pivot.Invert(); - row0 = parent_pivot.GetRow(0); - row1 = parent_pivot.GetRow(1); - row2 = parent_pivot.GetRow(2); - row3 = parent_pivot.GetRow(3); - - LMatrix4d pi_m4d(row0.x, row0.y, row0.z, 0.0f, - row1.x, row1.y, row1.z, 0.0f, - row2.x, row2.y, row2.z, 0.0f, - row3.x, row3.y, row3.z, 1.0f ); - - // Now here's the tricky part. I believe this command strips out the - // node "frame" which is the sum of all transformations enacted by the - // parent of this node. This should reduce to the transformation - // relative to this node's parent - pi_m4d.invert_in_place(); - m4d = m4d * pi_m4d; - } - if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) { - egg_group->add_matrix4(m4d); - } -} - -/** - * Converts the indicated Maya NURBS curve (a standalone curve, not a trim - * curve) to a corresponding egg structure and attaches it to the indicated - * egg group. - */ -bool MaxToEggConverter:: -make_nurbs_curve(INode *max_node, NURBSCVCurve *curve, - TimeValue time, EggGroup *egg_group) -{ - int degree = curve->GetOrder(); - int cvs = curve->GetNumCVs(); - int knots = curve->GetNumKnots(); - int i; - - if (knots != cvs + degree) { - return false; - } - -#ifdef _UNICODE - char mbname[1024]; - mbname[1023] = 0; - wcstombs(mbname, max_node->GetName(), 1023); - string name(mbname); -#else - string name = max_node->GetName(); -#endif - - string vpool_name = name + ".cvs"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - egg_group->add_child(vpool); - - EggNurbsCurve *egg_curve = new EggNurbsCurve(name); - egg_group->add_child(egg_curve); - egg_curve->setup(degree, knots); - - for (i = 0; i < knots; i++) - egg_curve->set_knot(i, curve->GetKnot(i)); - - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - for (i = 0; i < cvs; i++) { - NURBSControlVertex *cv = curve->GetCV(i); - if (!cv) { - char buf[1024]; - sprintf(buf, "Error getting CV %d", i); - return false; - } else { - EggVertex vert; - LPoint4d p4d(0, 0, 0, 1.0); - cv->GetPosition(time, p4d[0], p4d[1], p4d[2]); - p4d = p4d * vertex_frame_inv; - vert.set_pos(p4d); - egg_curve->add_vertex(vpool->create_unique_vertex(vert)); - } - } - - return true; -} - -/** - * Converts the indicated Maya polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void MaxToEggConverter:: -make_polyset(INode *max_node, Mesh *mesh, - EggGroup *egg_group, Shader *default_shader) { - - mesh->buildNormals(); - - if (mesh->getNumFaces() == 0) { - return; - } - - // One way to convert the mesh would be to first get out all the vertices - // in the mesh and add them into the vpool, then when we traverse the - // polygons we would only have to index them into the vpool according to - // their Maya vertex index. - - // Unfortunately, since Maya may store multiple normals andor colors for - // each vertex according to which polygon it is in, that approach won't - // necessarily work. In egg, those split-property vertices have to become - // separate vertices. So instead of adding all the vertices up front, - // we'll start with an empty vpool, and add vertices to it on the fly. - -#ifdef _UNICODE - char mbname[1024]; - mbname[1023] = 0; - wcstombs(mbname, max_node->GetName(), 1023); - string node_name(mbname); -#else - string node_name = max_node->GetName(); -#endif - - string vpool_name = node_name + ".verts"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - egg_group->add_child(vpool); - - // We will need to transform all vertices from world coordinate space into - // the vertex space appropriate to this node. Usually, this is the same - // thing as world coordinate space, and this matrix will be identity; but - // if the node is under an instance (particularly, for instance, a - // billboard) then the vertex space will be different from world space. - LMatrix4d vertex_frame = get_object_transform(max_node) * - egg_group->get_vertex_frame_inv(); - - - for ( int iFace=0; iFace < mesh->getNumFaces(); iFace++ ) { - EggPolygon *egg_poly = new EggPolygon; - egg_group->add_child(egg_poly); - - egg_poly->set_bface_flag(_options->_double_sided); - - Face face = mesh->faces[iFace]; - - const PandaMaterial &pmat = get_panda_material(max_node->GetMtl(), face.getMatID()); - - // Get the vertices for the polygon. - for ( int iVertex=0; iVertex < 3; iVertex++ ) { - EggVertex vert; - - // Get the vertex position - Point3 vertex = mesh->getVert(face.v[iVertex]); - LPoint3d p3d(vertex.x, vertex.y, vertex.z); - p3d = p3d * vertex_frame; - vert.set_pos(p3d); - - // Get the vertex normal - Point3 normal = get_max_vertex_normal(mesh, iFace, iVertex); - LVector3d n3d(normal.x, normal.y, normal.z); - // *** Not quite sure if this transform should be applied, but it - // may explain why normals were weird previously - n3d = n3d * vertex_frame; - vert.set_normal(n3d); - - // Get the vertex color - if(mesh->vcFace) // if has vcFace, has used vertex color - { - VertColor vertexColor = get_max_vertex_color(mesh, iFace, iVertex); - LColor pVC(vertexColor.x, vertexColor.y, vertexColor.z, 1); - vert.set_color(pVC); - } - // Get the UVs for this vertex - - // first check if we returned nothing in the channels slot we need - // UV's even in this case because the user may not have put a - // material on the object at all - if (pmat._map_channels.size() == 0) { - // since the channel will always be one because there's no other - // textures then don't bother with the name - UVVert uvw = get_max_vertex_texcoord(mesh, iFace, iVertex, 1); - vert.set_uv( LTexCoordd(uvw.x, uvw.y)); - } - // otherwise go through and generate the maps per channel this - // will also generate default UV's as long as the user applies a - // standard material to the object - for (int iChan=0; iChanadd_vertex(vpool->create_unique_vertex(vert)); - } - - // Max uses normals, not winding, to determine which way a polygon - // faces. Make sure the winding and that normal agree - - EggVertex *verts[3]; - LPoint3d points[3]; - - for (int i = 0; i < 3; i++) { - verts[i] = egg_poly->get_vertex(i); - points[i] = verts[i]->get_pos3(); - } - - LVector3d realNorm = ((points[1] - points[0]).cross(points[2] - points[0])); - Point3 maxNormTemp = mesh->getFaceNormal(iFace); - LVector3d maxNorm = (LVector3d(maxNormTemp.x, maxNormTemp.y, maxNormTemp.z) * - vertex_frame); - - if (realNorm.dot(maxNorm) < 0.0) { - egg_poly->set_vertex(0, verts[2]); - egg_poly->set_vertex(2, verts[0]); - } - - for (int i=0; iadd_texture(pmat._texture_list[i]); - } - egg_poly->set_color(pmat._color); - - - } - - // Now that we've added all the polygons (and created all the vertices), - // go back through the vertex pool and set up the appropriate joint - // membership for each of the vertices. - - if (_options->_anim_type == MaxEggOptions::AT_model) { - get_vertex_weights(max_node, vpool); - } -} - -UVVert MaxToEggConverter::get_max_vertex_texcoord(Mesh *mesh, int faceNo, int vertNo, int channel) { - - // extract the texture coordinate - UVVert uvVert(0,0,0); - if(mesh->mapSupport(channel)) { - TVFace *pTVFace = mesh->mapFaces(channel); - UVVert *pUVVert = mesh->mapVerts(channel); - uvVert = pUVVert[pTVFace[faceNo].t[vertNo]]; - } else if(mesh->numTVerts > 0) { - uvVert = mesh->tVerts[mesh->tvFace[faceNo].t[vertNo]]; - } - return uvVert; -} - -VertColor MaxToEggConverter::get_max_vertex_color(Mesh *mesh,int FaceNo,int VertexNo, int channel) { - - VertColor vc(0,0,0); - if(mesh->mapSupport(channel)) - { - // We get the color from vcFace - TVFace& _vcface = mesh->vcFace[FaceNo]; - // Get its index into the vertCol array - int VertexColorIndex = _vcface.t[VertexNo]; - // Get its color - vc =mesh->vertCol[VertexColorIndex]; - } - else - { - TVFace *pTVFace = mesh->mapFaces(channel); - vc = mesh->vertCol[pTVFace[FaceNo].t[VertexNo]]; - } - return vc; -} - -VertColor MaxToEggConverter::get_max_vertex_color(Mesh *mesh,int FaceNo,int VertexNo) -{ - VertColor vc(0,0,0); - // We get the color from vcFace - TVFace& _vcface = mesh->vcFace[FaceNo]; - // Get its index into the vertCol array - int VertexColorIndex = _vcface.t[VertexNo]; - // Get its color - vc =mesh->vertCol[VertexColorIndex]; - return vc; -} - -Point3 MaxToEggConverter::get_max_vertex_normal(Mesh *mesh, int faceNo, int vertNo) -{ - Face f = mesh->faces[faceNo]; - DWORD smGroup = f.smGroup; - int vert = f.getVert(vertNo); - RVertex *rv = mesh->getRVertPtr(vert); - - int numNormals; - Point3 vertexNormal; - - // Is normal specified SPCIFIED is not currently used, but may be used in - // future versions. - if (rv->rFlags & SPECIFIED_NORMAL) { - vertexNormal = rv->rn.getNormal(); - } - // If normal is not specified it's only available if the face belongs to a - // smoothing group - else if ((numNormals = rv->rFlags & NORCT_MASK) && smGroup) { - // If there is only one vertex is found in the rn member. - if (numNormals == 1) { - vertexNormal = rv->rn.getNormal(); - } - else { - // If two or more vertices are there you need to step through them - // and find the vertex with the same smoothing group as the - // current face. You will find multiple normals in the ern - // member. - for (int i = 0; i < numNormals; i++) { - if (rv->ern[i].getSmGroup() & smGroup) { - vertexNormal = rv->ern[i].getNormal(); - } - } - } - } - else { - // Get the normal from the Face if no smoothing groups are there - vertexNormal = mesh->getFaceNormal(faceNo); - } - - return vertexNormal; -} - -/** - * - */ -void MaxToEggConverter:: -get_vertex_weights(INode *max_node, EggVertexPool *vpool) { - // Try to get the weights out of a physique if one exists - Modifier *mod = FindSkinModifier(max_node, PHYSIQUE_CLASSID); - EggVertexPool::iterator vi; - - if (mod) { - // create a physique export interface - IPhysiqueExport *pPhysiqueExport = (IPhysiqueExport *)mod->GetInterface(I_PHYINTERFACE); - if (pPhysiqueExport) { - // create a context export interface - IPhyContextExport *pContextExport = - (IPhyContextExport *)pPhysiqueExport->GetContextInterface(max_node); - if (pContextExport) { - // set the flags in the context export interface - pContextExport->ConvertToRigid(TRUE); - pContextExport->AllowBlending(TRUE); - - for (vi = vpool->begin(); vi != vpool->end(); ++vi) { - EggVertex *vert = (*vi); - int max_vi = vert->get_external_index(); - - // get the vertex export interface - IPhyVertexExport *pVertexExport = - (IPhyVertexExport *)pContextExport->GetVertexInterface(max_vi); - if (pVertexExport) { - int vertexType = pVertexExport->GetVertexType(); - - // handle the specific vertex type - if(vertexType == RIGID_TYPE) { - // typecast to rigid vertex - IPhyRigidVertex *pTypeVertex = (IPhyRigidVertex *)pVertexExport; - INode *bone_node = pTypeVertex->GetNode(); - MaxNodeDesc *joint_node_desc = _tree.find_joint(bone_node); - if (joint_node_desc){ - EggGroup *joint = _tree.get_egg_group(joint_node_desc); - if (joint != nullptr) - joint->ref_vertex(vert, 1.0f); - } - } - else if(vertexType == RIGID_BLENDED_TYPE) { - // typecast to blended vertex - IPhyBlendedRigidVertex *pTypeVertex = (IPhyBlendedRigidVertex *)pVertexExport; - - for (int ji = 0; ji < pTypeVertex->GetNumberNodes(); ++ji) { - PN_stdfloat weight = pTypeVertex->GetWeight(ji); - if (weight > 0.0f) { - INode *bone_node = pTypeVertex->GetNode(ji); - MaxNodeDesc *joint_node_desc = _tree.find_joint(bone_node); - if (joint_node_desc){ - EggGroup *joint = _tree.get_egg_group(joint_node_desc); - if (joint != nullptr) - joint->ref_vertex(vert, weight); - } - } - } - } - // Release the vertex interface - pContextExport->ReleaseVertexInterface(pVertexExport); - } - } - // Release the context interface - pPhysiqueExport->ReleaseContextInterface(pContextExport); - } - // Release the physique export interface - mod->ReleaseInterface(I_PHYINTERFACE, pPhysiqueExport); - } - } - else { - // No physique, try to find a skin - mod = FindSkinModifier(max_node, SKIN_CLASSID); - if (mod) { - ISkin *skin = (ISkin*)mod->GetInterface(I_SKIN); - if (skin) { - ISkinContextData *skinMC = skin->GetContextInterface(max_node); - if (skinMC) { - for (vi = vpool->begin(); vi != vpool->end(); ++vi) { - EggVertex *vert = (*vi); - int max_vi = vert->get_external_index(); - - for (int ji = 0; ji < skinMC->GetNumAssignedBones(max_vi); ++ji) { - PN_stdfloat weight = skinMC->GetBoneWeight(max_vi, ji); - if (weight > 0.0f) { - INode *bone_node = skin->GetBone(skinMC->GetAssignedBone(max_vi, ji)); - MaxNodeDesc *joint_node_desc = _tree.find_joint(bone_node); - if (joint_node_desc){ - EggGroup *joint = _tree.get_egg_group(joint_node_desc); - if (joint != nullptr) { - joint->ref_vertex(vert, weight); - } - } - } - } - } - } - } - } - } -} - - -/** - * Converts a Max material into a set of Panda textures and a primitive color. - */ -const MaxToEggConverter::PandaMaterial &MaxToEggConverter:: -get_panda_material(Mtl *mtl, MtlID matID) { - - MaterialMap::iterator it = _material_map.find(mtl); - if (it != _material_map.end()) { - return (*it).second; - } - - PandaMaterial &pandaMat = _material_map[mtl]; - pandaMat._color = LColor(1,1,1,1); - pandaMat._any_diffuse = false; - pandaMat._any_opacity = false; - pandaMat._any_gloss = false; - pandaMat._any_normal = false; - - - - - // If it's a multi-material, dig down. - - while (( mtl != 0) && (mtl->ClassID() == Class_ID(MULTI_CLASS_ID, 0 ))) { - if (matID < mtl->NumSubMtls()) { - mtl = mtl->GetSubMtl(matID); - } else { - mtl = 0; - } - } - - // If it's a standard material, we're good. - - if ((mtl != 0) && (mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0 ))) { - StdMat *maxMaterial = (StdMat*)mtl; - analyze_diffuse_maps(pandaMat, maxMaterial->GetSubTexmap(ID_DI)); - analyze_opacity_maps(pandaMat, maxMaterial->GetSubTexmap(ID_OP)); - analyze_gloss_maps(pandaMat, maxMaterial->GetSubTexmap(ID_SP)); - if (!pandaMat._any_gloss) - analyze_gloss_maps(pandaMat, maxMaterial->GetSubTexmap(ID_SS)); - if (!pandaMat._any_gloss) - analyze_gloss_maps(pandaMat, maxMaterial->GetSubTexmap(ID_SH)); - analyze_glow_maps(pandaMat, maxMaterial->GetSubTexmap(ID_SI)); - analyze_normal_maps(pandaMat, maxMaterial->GetSubTexmap(ID_BU)); - for (int i=0; iGetDiffuse(0)); - pandaMat._color[0] = diffuseColor.x; - pandaMat._color[1] = diffuseColor.y; - pandaMat._color[2] = diffuseColor.z; - } - if (!pandaMat._any_opacity) { - pandaMat._color[3] = (maxMaterial->GetOpacity(_current_frame * GetTicksPerFrame())); - } - if (pandaMat._texture_list.size() < 1) { - // if we don't have any maps whatsoever, give the material a dummy - // channel so that UV's get created - pandaMat._map_channels.push_back(1); - } - return pandaMat; - } - - // Otherwise, it's unrecognizable. Leave result blank. - return pandaMat; -} -/** - * - */ -void MaxToEggConverter::analyze_diffuse_maps(PandaMaterial &pandaMat, Texmap *mat) { - if (mat == 0) return; - - if (mat->ClassID() == Class_ID(RGBMULT_CLASS_ID, 0)) { - for (int i=0; iNumSubTexmaps(); i++) { - analyze_diffuse_maps(pandaMat, mat->GetSubTexmap(i)); - } - return; - } - - if (mat->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) { - pandaMat._any_diffuse = true; - PT(EggTexture) tex = new EggTexture(generate_tex_name(), ""); - - BitmapTex *diffuseTex = (BitmapTex *)mat; - - Filename fullpath, outpath; -#ifdef _UNICODE - Filename filename = Filename::from_os_specific_w(diffuseTex->GetMapName()); -#else - Filename filename = Filename::from_os_specific(diffuseTex->GetMapName()); -#endif - _options->_path_replace->full_convert_path(filename, get_model_path(), - fullpath, outpath); - tex->set_filename(outpath); - tex->set_fullpath(fullpath); - - apply_texture_properties(*tex, diffuseTex->GetMapChannel()); - add_map_channel(pandaMat, diffuseTex->GetMapChannel()); - - Bitmap *diffuseBitmap = diffuseTex->GetBitmap(0); - if ( diffuseBitmap && diffuseBitmap->HasAlpha()) { - tex->set_format(EggTexture::F_rgba); - } else { - tex->set_format(EggTexture::F_rgb); - } - tex->set_env_type(EggTexture::ET_modulate); - - pandaMat._texture_list.push_back(tex); - } -} - -/** - * - */ -void MaxToEggConverter::analyze_opacity_maps(PandaMaterial &pandaMat, Texmap *mat) { - if (mat == 0) return; - - if (mat->ClassID() == Class_ID(RGBMULT_CLASS_ID, 0)) { - for (int i=0; iNumSubTexmaps(); i++) { - analyze_opacity_maps(pandaMat, mat->GetSubTexmap(i)); - } - return; - } - - if (mat->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) { - pandaMat._any_opacity = true; - BitmapTex *transTex = (BitmapTex *)mat; - - Filename fullpath, outpath; -#ifdef _UNICODE - Filename filename = Filename::from_os_specific_w(transTex->GetMapName()); -#else - Filename filename = Filename::from_os_specific(transTex->GetMapName()); -#endif - _options->_path_replace->full_convert_path(filename, get_model_path(), - fullpath, outpath); - - // See if this opacity map already showed up. - for (int i=0; iget_env_type()==EggTexture::ET_modulate)&&(tex->get_fullpath() == fullpath)) { - tex->set_format(EggTexture::F_rgba); - return; - } - } - - // Try to find a diffuse map to pair this with as an alpha-texture. - std::string uvname = get_uv_name(transTex->GetMapChannel()); - for (int i=0; iget_env_type()==EggTexture::ET_modulate)&& - (tex->get_format() == EggTexture::F_rgb)&& - (tex->get_uv_name() == uvname)) { - tex->set_format(EggTexture::F_rgba); - tex->set_alpha_filename(outpath); - tex->set_alpha_fullpath(fullpath); - return; - } - } - - // Otherwise, just create it as an alpha-texture. - PT(EggTexture) tex = new EggTexture(generate_tex_name(), ""); - tex->set_filename(outpath); - tex->set_fullpath(fullpath); - - apply_texture_properties(*tex, transTex->GetMapChannel()); - add_map_channel(pandaMat, transTex->GetMapChannel()); - tex->set_format(EggTexture::F_alpha); - - pandaMat._texture_list.push_back(tex); - } -} - -/** - * - */ -void MaxToEggConverter::analyze_glow_maps(PandaMaterial &pandaMat, Texmap *mat) { - if (mat == 0) return; - - if (mat->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) { - BitmapTex *gtex = (BitmapTex *)mat; - - Filename fullpath, outpath; -#ifdef _UNICODE - Filename filename = Filename::from_os_specific_w(gtex->GetMapName()); -#else - Filename filename = Filename::from_os_specific(gtex->GetMapName()); -#endif - _options->_path_replace->full_convert_path(filename, get_model_path(), - fullpath, outpath); - - // Try to find a diffuse map to pair this with as an alpha-texture. - std::string uvname = get_uv_name(gtex->GetMapChannel()); - for (int i=0; iget_env_type()==EggTexture::ET_modulate)&& - (tex->get_format() == EggTexture::F_rgb)&& - (tex->get_uv_name() == uvname)) { - tex->set_env_type(EggTexture::ET_modulate_glow); - tex->set_format(EggTexture::F_rgba); - tex->set_alpha_filename(outpath); - tex->set_alpha_fullpath(fullpath); - return; - } - } - - // Otherwise, just create it as a separate glow-texture. - PT(EggTexture) tex = new EggTexture(generate_tex_name(), ""); - tex->set_env_type(EggTexture::ET_glow); - tex->set_filename(outpath); - tex->set_fullpath(fullpath); - apply_texture_properties(*tex, gtex->GetMapChannel()); - add_map_channel(pandaMat, gtex->GetMapChannel()); - tex->set_format(EggTexture::F_alpha); - - pandaMat._texture_list.push_back(tex); - } -} - -/** - * - */ -void MaxToEggConverter::analyze_gloss_maps(PandaMaterial &pandaMat, Texmap *mat) { - if (mat == 0) return; - - if (mat->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) { - pandaMat._any_gloss = true; - BitmapTex *gtex = (BitmapTex *)mat; - - Filename fullpath, outpath; -#ifdef _UNICODE - Filename filename = Filename::from_os_specific_w(gtex->GetMapName()); -#else - Filename filename = Filename::from_os_specific(gtex->GetMapName()); -#endif - _options->_path_replace->full_convert_path(filename, get_model_path(), - fullpath, outpath); - - // Try to find a diffuse map to pair this with as an alpha-texture. - std::string uvname = get_uv_name(gtex->GetMapChannel()); - for (int i=0; iget_env_type()==EggTexture::ET_modulate)&& - (tex->get_format() == EggTexture::F_rgb)&& - (tex->get_uv_name() == uvname)) { - tex->set_env_type(EggTexture::ET_modulate_gloss); - tex->set_format(EggTexture::F_rgba); - tex->set_alpha_filename(outpath); - tex->set_alpha_fullpath(fullpath); - return; - } - } - - // Otherwise, just create it as a separate gloss-texture. - PT(EggTexture) tex = new EggTexture(generate_tex_name(), ""); - tex->set_env_type(EggTexture::ET_gloss); - tex->set_filename(outpath); - tex->set_fullpath(fullpath); - apply_texture_properties(*tex, gtex->GetMapChannel()); - add_map_channel(pandaMat, gtex->GetMapChannel()); - tex->set_format(EggTexture::F_alpha); - - pandaMat._texture_list.push_back(tex); - } -} - -/** - * - */ -void MaxToEggConverter::analyze_normal_maps(PandaMaterial &pandaMat, Texmap *mat) { - if (mat == 0) return; - - if (mat->ClassID() == Class_ID(BMTEX_CLASS_ID, 0)) { - pandaMat._any_normal = true; - BitmapTex *ntex = (BitmapTex *)mat; - - Filename fullpath, outpath; -#ifdef _UNICODE - Filename filename = Filename::from_os_specific_w(ntex->GetMapName()); -#else - Filename filename = Filename::from_os_specific(ntex->GetMapName()); -#endif - _options->_path_replace->full_convert_path(filename, get_model_path(), - fullpath, outpath); - - PT(EggTexture) tex = new EggTexture(generate_tex_name(), ""); - tex->set_env_type(EggTexture::ET_normal); - tex->set_filename(outpath); - tex->set_fullpath(fullpath); - apply_texture_properties(*tex, ntex->GetMapChannel()); - add_map_channel(pandaMat, ntex->GetMapChannel()); - tex->set_format(EggTexture::F_rgb); - - pandaMat._texture_list.push_back(tex); - } -} - -/** - * Adds the specified map channel to the map channel list, if it's not already - * there. - */ -void MaxToEggConverter::add_map_channel(PandaMaterial &pandaMat, int chan) { - for (int i=0; i decal_children; - - EggGroupNode::iterator ci; - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroup::get_class_type())) { - EggGroup *child_group = (EggGroup *) child; - if (child_group->has_object_type("decalbase")) { - if (decal_base != nullptr) { - // error - okflag = false; - } - child_group->remove_object_type("decalbase"); - decal_base = child_group; - - } else if (child_group->has_object_type("decal")) { - child_group->remove_object_type("decal"); - decal_children.push_back(child_group); - } - } - } - - if (decal_base == nullptr) { - if (!decal_children.empty()) { - // warning - } - - } else { - if (decal_children.empty()) { - // warning - - } else { - // All the decal children get moved to be a child of decal base. - // This usually will not affect the vertex positions, but it could - // if the decal base has a transform and the decal child is an - // instance node. So don't do that. - pvector::iterator di; - for (di = decal_children.begin(); di != decal_children.end(); ++di) { - EggGroup *child_group = (*di); - decal_base->add_child(child_group); - } - - // Also set the decal state on the base. - decal_base->set_decal_flag(true); - } - } - - // Now recurse on each of the child nodes. - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroupNode::get_class_type())) { - EggGroupNode *child_group = (EggGroupNode *) child; - if (!reparent_decals(child_group)) { - okflag = false; - } - } - } - - return okflag; -} - -Modifier* MaxToEggConverter::FindSkinModifier (INode* node, const Class_ID &type) -{ - // Get object from node. Abort if no object. - Object* pObj = node->GetObjectRef(); - if (!pObj) return nullptr; - - // Is derived object ? - while (pObj->SuperClassID() == GEN_DERIVOB_CLASS_ID) { - // Yes -> Cast. - IDerivedObject* pDerObj = static_cast(pObj); - - // Iterate over all entries of the modifier stack. - for (int stackId = 0; stackId < pDerObj->NumModifiers(); ++stackId) { - // Get current modifier. - Modifier* mod = pDerObj->GetModifier(stackId); - - // Is this what we are looking for? - if (mod->ClassID() == type ) - return mod; - } - - // continue with next derived object - pObj = pDerObj->GetObjRef(); - } - - // Not found. - return nullptr; -} diff --git a/pandatool/src/maxegg/maxToEggConverter.h b/pandatool/src/maxegg/maxToEggConverter.h deleted file mode 100644 index 86cb2303c11..00000000000 --- a/pandatool/src/maxegg/maxToEggConverter.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxToEggConverter.h - * @author Corey Revilla and Ken Strickland - * @date 2003-06-22 - * from mayaToEggConverter.cxx created by drose (10Nov99) - */ - -#ifndef __maxToEggConverter__H -#define __maxToEggConverter__H - -#pragma conform(forScope, off) - -/* Error-Reporting Includes - */ -#define MTEC Logger::ST_MAP_ME_TO_APP_SPECIFIC_SYSTEM4 - -/* Helpful Defintions and Casts - */ -#define null 0 -#define PHYSIQUE_CLASSID Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B) - -/* External Helper Functions for UI - */ -// *** Figure out why this is causing link errors DWORD WINAPI -// ProgressBarFunction(LPVOID arg); - -/** - * This class supervises the construction of an EggData structure from a Max - * model - */ -class MaxToEggConverter { - public: - MaxToEggConverter(); - ~MaxToEggConverter(); - - bool convert(MaxEggOptions *options); - - private: - struct PandaMaterial { - std::vector _texture_list; - LColor _color; - std::vector _map_channels; - bool _any_diffuse; - bool _any_opacity; - bool _any_gloss; - bool _any_normal; - }; - typedef std::map MaterialMap; - MaxEggOptions *_options; - int _current_frame; - PT(EggData) _egg_data; - std::string _program_name; - MaxNodeTree _tree; - int _cur_tref; - EggTextureCollection _textures; - MaterialMap _material_map; - - void reset(); - - bool convert_char_model(); - bool convert_char_chan(double start_frame, double end_frame, - double frame_inc, double output_frame_rate); - bool convert_hierarchy(EggGroupNode *egg_root); - bool process_model_node(MaxNodeDesc *node_desc); - - void get_transform(INode *max_node, EggGroup *egg_group); - LMatrix4d get_object_transform(INode *max_node); - void get_joint_transform(INode *max_node, EggGroup *egg_group); - void get_joint_transform(INode *max_node, INode *parent_node, - EggGroup *egg_group); - - bool make_nurbs_curve(INode *max_node, NURBSCVCurve *curve, - TimeValue time, EggGroup *egg_group); - void make_polyset(INode *max_node, - Mesh *mesh, - EggGroup *egg_group, - Shader *default_shader = nullptr); - - Point3 get_max_vertex_normal(Mesh *mesh, int faceNo, int vertNo); - VertColor get_max_vertex_color(Mesh *mesh, int FaceNo, int VertexNo); - VertColor get_max_vertex_color(Mesh *mesh,int FaceNo,int VertexNo, int channel); - UVVert get_max_vertex_texcoord(Mesh *mesh, int faceNo, int vertNo, int channel); - - void get_vertex_weights(INode *max_node, EggVertexPool *vpool); - - const PandaMaterial &get_panda_material(Mtl *mtl, MtlID id); - void analyze_diffuse_maps(PandaMaterial &pandaMat, Texmap *m); - void analyze_opacity_maps(PandaMaterial &pandaMat, Texmap *m); - void analyze_gloss_maps(PandaMaterial &pandaMat, Texmap *m); - void analyze_glow_maps(PandaMaterial &pandaMat, Texmap *m); - void analyze_normal_maps(PandaMaterial &pandaMat, Texmap *m); - void add_map_channel(PandaMaterial &pandaMat, int channel); - void apply_texture_properties(EggTexture &tex, int channel); - std::string generate_tex_name(); - std::string get_uv_name(int n); - bool reparent_decals(EggGroupNode *egg_parent); - - public: - - Modifier* FindSkinModifier (INode* node, const Class_ID &type); -}; - - -#endif diff --git a/pandatool/src/maxegg/p3maxegg_composite1.cxx b/pandatool/src/maxegg/p3maxegg_composite1.cxx deleted file mode 100644 index 553a2193af1..00000000000 --- a/pandatool/src/maxegg/p3maxegg_composite1.cxx +++ /dev/null @@ -1,6 +0,0 @@ - -#include "maxNodeDesc.cxx" -#include "maxNodeTree.cxx" -#include "maxOptionsDialog.cxx" -#include "maxToEggConverter.cxx" -#include "maxEgg.cxx" diff --git a/pandatool/src/maxprogs/maxEggImport.cxx b/pandatool/src/maxprogs/maxEggImport.cxx deleted file mode 100644 index 3776da2097a..00000000000 --- a/pandatool/src/maxprogs/maxEggImport.cxx +++ /dev/null @@ -1,277 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maxEggImport.cxx - * @author jyelon - * @date 2005-07-15 - * - * This is the wrapper code for the max importer plugin. - * It includes: - * - * - user interface dialogs and popups - * - plugin initialization/registration - * - * It does not include the actual code to traverse the EggData. - */ - -// Include this before everything -#include "pandatoolbase.h" - -using std::min; -using std::max; - -// local includes -#include "maxEggLoader.h" -#include "maxImportRes.h" - -// MAX includes -#include -#include - -// panda includes. -#include "notifyCategoryProxy.h" - -#include -#include - -class MaxEggImporter : public SceneImport -{ -public: - // GUI-related methods - MaxEggImporter(); - ~MaxEggImporter(); - int ExtCount(); // Number of extensions supported - const TCHAR * Ext(int n); // Extension #n (i.e. "EGG") - const TCHAR * LongDesc(); // Long ASCII description (i.e. "Egg Importer") - const TCHAR * ShortDesc(); // Short ASCII description (i.e. "Egg") - const TCHAR * AuthorName(); // ASCII Author name - const TCHAR * CopyrightMessage();// ASCII Copyright message - const TCHAR * OtherMessage1(); // Other message #1 - const TCHAR * OtherMessage2(); // Other message #2 - unsigned int Version(); // Version number * 100 (i.e. v3.01 = 301) - void ShowAbout(HWND hWnd); // Show DLL's "About..." box - int DoImport(const TCHAR *name,ImpInterface *ei,Interface *i, BOOL suppressPrompts); - -public: - // GUI-related fields - static BOOL _merge; - static BOOL _importmodel; - static BOOL _importanim; -}; - -BOOL MaxEggImporter::_merge = TRUE; -BOOL MaxEggImporter::_importmodel = TRUE; -BOOL MaxEggImporter::_importanim = FALSE; - -MaxEggImporter::MaxEggImporter() -{ -} - -MaxEggImporter::~MaxEggImporter() -{ -} - -int MaxEggImporter::ExtCount() -{ - // Number of different extensions handled by this importer. - return 1; -} - -const TCHAR * MaxEggImporter::Ext(int n) -{ - // Fetch the extensions handled by this importer. - switch(n) { - case 0: return _T("egg"); - default: return _T(""); - } -} - -const TCHAR * MaxEggImporter::LongDesc() -{ - return _T("Panda3D Egg Importer"); -} - -const TCHAR * MaxEggImporter::ShortDesc() -{ - return _T("Panda3D Egg"); -} - -const TCHAR * MaxEggImporter::AuthorName() -{ - return _T("Joshua Yelon"); -} - -const TCHAR * MaxEggImporter::CopyrightMessage() -{ - return _T("Copyight (c) 2005 Josh Yelon"); -} - -const TCHAR * MaxEggImporter::OtherMessage1() -{ - return _T(""); -} - -const TCHAR * MaxEggImporter::OtherMessage2() -{ - return _T(""); -} - -unsigned int MaxEggImporter::Version() -{ - return 100; -} - -static INT_PTR CALLBACK AboutBoxDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - CenterWindow(hWnd, GetParent(hWnd)); - break; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDOK: - EndDialog(hWnd, 1); - break; - } - break; - default: - return FALSE; - } - return TRUE; -} - -void MaxEggImporter::ShowAbout(HWND hWnd) -{ - DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX), - hWnd, AboutBoxDlgProc, 0); -} - - -static INT_PTR CALLBACK ImportDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - MaxEggImporter *imp = (MaxEggImporter*) GetWindowLongPtr(hWnd, GWLP_USERDATA); - switch (msg) { - case WM_INITDIALOG: - imp = (MaxEggImporter*)lParam; - SetWindowLongPtr(hWnd, GWLP_USERDATA, lParam); - CenterWindow(hWnd, GetParent(hWnd)); - CheckDlgButton(hWnd, IDC_MERGE, imp->_merge); - CheckDlgButton(hWnd, IDC_IMPORTMODEL, imp->_importmodel); - CheckDlgButton(hWnd, IDC_IMPORTANIM, imp->_importanim); - break; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDOK: - imp->_merge = IsDlgButtonChecked(hWnd, IDC_MERGE); - imp->_importmodel = IsDlgButtonChecked(hWnd, IDC_IMPORTMODEL); - imp->_importanim = IsDlgButtonChecked(hWnd, IDC_IMPORTANIM); - EndDialog(hWnd, 1); - break; - case IDCANCEL: - EndDialog(hWnd, 0); - break; - } - break; - default: - return FALSE; - } - return TRUE; -} - -int MaxEggImporter:: -DoImport(const TCHAR *name, ImpInterface *ii, Interface *i, BOOL suppressPrompts) { - // Prompt the user with our dialogbox. - if (!DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_IMPORT_DLG), - i->GetMAXHWnd(), ImportDlgProc, (LPARAM)this)) { - return 1; - } - - std::ostringstream log; - Notify::ptr()->set_ostream_ptr(&log, false); - -#ifdef _UNICODE - char sname[2048]; - sname[2047] = 0; - wcstombs(sname, name, 2047); - bool ok = MaxLoadEggFile(sname, _merge ? true:false, _importmodel ? true:false, _importanim ? true:false); -#else - bool ok = MaxLoadEggFile(name, _merge ? true:false, _importmodel ? true:false, _importanim ? true:false); -#endif - - std::string txt = log.str(); - if (txt != "") { - MessageBoxA(nullptr, txt.c_str(), "Panda3D Importer", MB_OK); - } else if (!ok) { - MessageBoxA(nullptr, "Import Failed, unknown reason\n", "Panda3D Importer", MB_OK); - } - - Notify::ptr()->set_ostream_ptr(nullptr, false); - return 1; -} - -// Plugin Initialization The following code enables Max to load this DLL, get -// a list of the classes defined in this DLL, and provides a means for Max to -// create instances of those classes. - -HINSTANCE hInstance; - -BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) { - static int controlsInit = FALSE; - hInstance = hinstDLL; - - if (!controlsInit) { - controlsInit = TRUE; - // It appears that InitCustomControls is deprecated in 2012. I'm not sure - // if we can just remove it like this, but I've heard that it seems to - // work, so let's do it like this. -#if MAX_VERSION_MAJOR < 14 - InitCustomControls(hInstance); -#endif - InitCommonControls(); - } - - return (TRUE); -} - -#define PANDAEGGIMP_CLASS_ID1 0x377193ab -#define PANDAEGGIMP_CLASS_ID2 0x897afe12 - -class MaxEggImporterClassDesc: public ClassDesc { -public: - int IsPublic() {return 1;} - void *Create(BOOL loading = FALSE) {return new MaxEggImporter;} - const TCHAR *ClassName() {return _T("MaxEggImporter");} - SClass_ID SuperClassID() {return SCENE_IMPORT_CLASS_ID;} - Class_ID ClassID() {return Class_ID(PANDAEGGIMP_CLASS_ID1,PANDAEGGIMP_CLASS_ID2);} - const TCHAR *Category() {return _T("Chrutilities");} -}; - -static MaxEggImporterClassDesc MaxEggImporterDesc; - -__declspec( dllexport ) const TCHAR* LibDescription() -{ - return _T("Panda3D Egg Importer"); -} - -__declspec( dllexport ) int LibNumberClasses() -{ - return 1; -} - -__declspec( dllexport ) ClassDesc* LibClassDesc(int i) -{ - switch(i) { - case 0: return &MaxEggImporterDesc; - default: return 0; - } -} - -__declspec( dllexport ) ULONG LibVersion() -{ - return VERSION_3DSMAX; -} diff --git a/pandatool/src/maxprogs/maxEggImport.def b/pandatool/src/maxprogs/maxEggImport.def deleted file mode 100644 index 9ee10cf3306..00000000000 --- a/pandatool/src/maxprogs/maxEggImport.def +++ /dev/null @@ -1,7 +0,0 @@ -EXPORTS - LibDescription @1 - LibNumberClasses @2 - LibClassDesc @3 - LibVersion @4 -SECTIONS - .data READ WRITE diff --git a/pandatool/src/maxprogs/maxImportRes.h b/pandatool/src/maxprogs/maxImportRes.h deleted file mode 100644 index 6b36a01954b..00000000000 --- a/pandatool/src/maxprogs/maxImportRes.h +++ /dev/null @@ -1,21 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by maxImportRes.rc -// -#define IDD_PANEL 101 -#define IDD_ABOUTBOX 102 -#define IDD_IMPORT_DLG 103 -#define IDC_MERGE 1002 -#define IDC_IMPORTMODEL 1003 -#define IDC_IMPORTANIM 1004 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1020 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/pandatool/src/maxprogs/maxImportRes.rc b/pandatool/src/maxprogs/maxImportRes.rc deleted file mode 100644 index b4f2e778e9e..00000000000 --- a/pandatool/src/maxprogs/maxImportRes.rc +++ /dev/null @@ -1,122 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "maxImportRes.h" - -#define APSTUDIO_READONLY_SYMBOLS -//////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "WinResrc.h" -#define IDC_STATIC -1 -//////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -//////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -//////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ABOUTBOX, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 176 - TOPMARGIN, 7 - BOTTOMMARGIN, 60 - END - - IDD_IMPORT_DLG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 187 - TOPMARGIN, 7 - BOTTOMMARGIN, 71 - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -//////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "maxImportRes.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -//////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUTBOX DIALOGEX 0, 0, 183, 67 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "About Panda3D Egg Importer" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "OK",IDOK,66,45,50,14 - CTEXT "Panda3D Egg Importer\n\nCarnegie Mellon\nEntertainment Technology Center", - IDC_STATIC,7,7,169,36 -END - -IDD_IMPORT_DLG DIALOGEX 0, 0, 194, 78 -STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Panda3D Egg Import" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "OK",IDOK,137,10,50,14 - PUSHBUTTON "Cancel",IDCANCEL,137,30,50,14 - CONTROL "Merge with Current Scene",IDC_MERGE,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,15,20,106,10 - GROUPBOX "Input Options",IDC_STATIC,5,7,126,64 - CONTROL "Import Model",IDC_IMPORTMODEL,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,15,41,73,10 - CONTROL "Import Animation",IDC_IMPORTANIM,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,15,54,73,10 -END - -#endif // English (U.S.) resources -//////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -//////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -//////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/pandatool/src/maya/config_maya.cxx b/pandatool/src/maya/config_maya.cxx deleted file mode 100644 index 2608243f9d5..00000000000 --- a/pandatool/src/maya/config_maya.cxx +++ /dev/null @@ -1,48 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_maya.cxx - * @author drose - * @date 2002-04-15 - */ - -#include "config_maya.h" - -#include "dconfig.h" - -Configure(config_maya); -NotifyCategoryDef(maya, ""); - -ConfigureFn(config_maya) { - init_libmaya(); -} - -ConfigVariableInt init_maya_repeat_count -("init-maya-repeat-count", 5, - PRC_DESC("The number of times to attempt to initialize Maya and acquire the " - "Maya license before giving up.")); - -ConfigVariableDouble init_maya_timeout -("init-maya-timeout", 5.0, - PRC_DESC("The number of seconds to wait between attempts to acquire the " - "Maya license.")); - -/** - * Initializes the library. This must be called at least once before any of - * the functions or classes in this library can be used. Normally it will be - * called by the static initializers and need not be called explicitly, but - * special cases exist. - */ -void -init_libmaya() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; -} diff --git a/pandatool/src/maya/config_maya.h b/pandatool/src/maya/config_maya.h deleted file mode 100644 index 256f4842e3a..00000000000 --- a/pandatool/src/maya/config_maya.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_maya.h - * @author drose - * @date 2002-04-15 - */ - -#ifndef CONFIG_MAYA_H -#define CONFIG_MAYA_H - -#include "pandatoolbase.h" -#include "notifyCategoryProxy.h" -#include "configVariableInt.h" -#include "configVariableDouble.h" - -NotifyCategoryDeclNoExport(maya); - -extern ConfigVariableInt init_maya_repeat_count; -extern ConfigVariableDouble init_maya_timeout; - -extern void init_libmaya(); - -#endif diff --git a/pandatool/src/maya/eggObjectFlags.mel b/pandatool/src/maya/eggObjectFlags.mel deleted file mode 100644 index 7ad070d7fd3..00000000000 --- a/pandatool/src/maya/eggObjectFlags.mel +++ /dev/null @@ -1,49 +0,0 @@ -// -// This is a sample mel script to flag a Maya node with at least -// one eggObjectTypes* attribute. These attributes are used to tag -// geometry with special meaning to Panda. There are a handful of -// attribute values that are predefined within Panda, but you can also -// make up your own attribute values, and define an arbitrary egg -// syntax to associate with each one. -// -// Each type you invoke this script to add an attribute to a node, it -// adds a new pull-down menu on the node attributes list, giving all -// of the values listed in $eggFlags, below. You can then select one -// of these values to assign to the node. If you need to assign -// multiple different values to the same node, run this script -// multiple times. -// -// The maya2egg converter will look for eggObjectTypes* attributes and -// insert the line " { value }" for each one found, where -// "value" is the particular value you have selected from the -// pull-down menu. Eventually, when the egg loader loads the egg file -// into Panda (either by loading the egg file interactively into a -// Panda session, or via an egg2bam command), the line -// will be replaced with arbitrary egg syntax defined by your -// Config.prc file with a line like this: -// -// egg-object-type-value [your egg syntax here] -// -// See panda/src/configfiles/panda.prc.pp and -// direct/src/configfiles/direct.prc.pp for examples of this. -// - -global proc eggObjectFlags() { - string $sel[] =`ls -sl`; - - // Modify this line as needed to add your own object types. - string $eggFlags = "none:portal:polylight:seq24:seq12:indexed:model:dcs:barrier:sphere:tube:trigger:trigger-sphere:bubble:ghost:keep-all-uvsets"; - - for ($i in $sel) { - string $attrName = "eggObjectTypes"; - string $object = ($i + "." + $attrName); - - int $num = 1; - - while (`objExists ($object + $num)`) { - $num++; - } - - addAttr -ln ($attrName + $num) -k 1 -at "enum" -en ($eggFlags) $i; - } -} diff --git a/pandatool/src/maya/mayaApi.cxx b/pandatool/src/maya/mayaApi.cxx deleted file mode 100644 index ce24e72d681..00000000000 --- a/pandatool/src/maya/mayaApi.cxx +++ /dev/null @@ -1,428 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaApi.cxx - * @author drose - * @date 2002-04-15 - */ - -#include "mayaApi.h" -#include "config_maya.h" -#include "string_utils.h" -#include "thread.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -#ifdef _WIN32 -#include // for chdir() -#endif - -using std::string; - -PT(MayaApi) MayaApi::_global_api = nullptr; - -// We need this bogus object just to force the application to link with -// OpenMayaAnim.lib; otherwise, Maya will complain (when compiled on Windows) -// that it is unable to find source plug 'ikRPsolver.msg'. -static MFnAnimCurve force_link_with_OpenMayaAnim; - -/** - * Don't attempt to create this object directly; instead, use the open_api() - * method. - */ -MayaApi:: -MayaApi(const string &program_name, bool view_license, bool revert_dir) { - if (program_name == "plug-in") { - // In this special case, we are invoking the code from within a plug-in, - // so we need not (and should not) call MLibrary::initialize(). - _plug_in = true; - _is_valid = true; - return; - } - - // Otherwise, if program_name is any other name, we are invoking the code - // from a standalone application and we do need to call - // MLibrary::initialize(). - _plug_in = false; - - // Beginning with Maya4.5, the call to initialize seems to change the - // current directory! Yikes! - - // Furthermore, the current directory may change during the call to any Maya - // function! Egad! - _cwd = ExecutionEnvironment::get_cwd(); - MStatus stat = MLibrary::initialize(false, (char *)program_name.c_str(), view_license); - - int error_count = init_maya_repeat_count; - while (!stat && error_count > 1) { - stat.perror("MLibrary::initialize"); - Thread::sleep(init_maya_timeout); - stat = MLibrary::initialize(false, (char *)program_name.c_str(), view_license); - --error_count; - } - - // Restore the current directory. Ever since Maya 2010, there seems to be - // some bad mojo when you do this. - if( revert_dir ){ - string dirname = _cwd.to_os_specific(); - if (chdir(dirname.c_str()) < 0) { - maya_cat.warning() - << "Unable to restore current directory to " << _cwd - << " after initializing Maya.\n"; - } else { - if (maya_cat.is_debug()) { - maya_cat.debug() - << "Restored current directory to " << _cwd << "\n"; - } - } - } - - - if (!stat) { - stat.perror("MLibrary::initialize"); - _is_valid = false; - } else { - _is_valid = true; - } -} - -/** - * Don't attempt to copy MayaApi objects. There should be only one of these - * in the world at a time. - */ -MayaApi:: -MayaApi(const MayaApi ©) { - nassertv(false); -} - -/** - * Don't attempt to copy MayaApi objects. There should be only one of these - * in the world at a time. - */ -void MayaApi:: -operator = (const MayaApi ©) { - nassertv(false); -} - -/** - * - */ -MayaApi:: -~MayaApi() { - nassertv(_global_api == this); - if (_is_valid && !_plug_in) { - // Caution! Calling this function seems to call exit() somewhere within - // Maya code. - MLibrary::cleanup(); - } - _global_api = nullptr; -} - -/** - * Opens the Maya API, if it is not already open, and returns a pointer - * representing this connection. When you are done using the Maya API, let - * the pointer destruct. - * - * If program_name is supplied, it is passed to Maya as the name of the - * currently-executing program. Otherwise, the current program name is - * extracted from the execution environment, if possible. The special - * program_name "plug-in" is used for code that is intended to be invoked as a - * plug-in only; in this case, the maya library is not re-initialized. - */ -PT(MayaApi) MayaApi:: -open_api(string program_name, bool view_license, bool revertdir) { - if (_global_api == nullptr) { - // We need to create a new MayaApi object. - if (program_name.empty()) { - program_name = ExecutionEnvironment::get_binary_name(); - if (program_name.empty()) { - program_name = "Panda"; - } - } - - _global_api = new MayaApi(program_name, view_license, revertdir); - - // Try to compare the string-formatted runtime version number with the - // numeric compile-time version number, so we can sanity check our runtime - // environment. (Sure would be nice if Maya provided an apples-to-apples - // comparison for us.) - - // According to the Maya specs, the numeric value is derived by taking the - // Maya version number and deleting the '.' characters, while also - // ignoring everything after the second dot (and, for some reason, - // appending a 0). - - string runtime_version = MGlobal::mayaVersion().asChar(); - string simple_runtime_version = runtime_version; - runtime_version = trim(runtime_version); - - // If the version number contains a space, stop there (that would be - // "service pack 1" or whatever). - size_t space = runtime_version.find(' '); - if (space != string::npos) { - runtime_version = runtime_version.substr(0, space); - } - - int rtver_a, rtver_b; - size_t dot1 = runtime_version.find('.'); - if (dot1 == string::npos) { - string_to_int(runtime_version, rtver_a); - rtver_b = 0; - - } else { - string_to_int(runtime_version.substr(0, dot1), rtver_a); - - size_t dot2 = runtime_version.find('.', dot1 + 1); - if (dot2 == string::npos) { - string_to_int(runtime_version.substr(dot1 + 1), rtver_b); - - } else { - string_to_int(runtime_version.substr(dot1 + 1, dot2 - dot1 - 1), rtver_b); - simple_runtime_version = runtime_version.substr(0, dot2); - } - } - - int runtime_version_int = rtver_a * 100 + rtver_b * 10; - - if (maya_cat.is_debug()) { - maya_cat.debug() - << "Compiled with Maya library version " - << (MAYA_API_VERSION / 100) << "." << (MAYA_API_VERSION / 10) % 10 - << " (" << MAYA_API_VERSION << "); running with library version " - << runtime_version << ".\n"; - } - - if (MAYA_API_VERSION / 10 != runtime_version_int / 10) { - maya_cat.warning() - << "This program was compiled using Maya version " - << (MAYA_API_VERSION / 100) << "." << (MAYA_API_VERSION / 10) % 10 - << ", but you are now running it with Maya version " - << simple_runtime_version - << ". The program may crash or produce incorrect results.\n\n"; - } - } - - return _global_api; -} - -/** - * Returns true if the global API has been successfully opened and may be used, or - * false if the API has not created yet or if there is some problem. - */ -bool MayaApi:: -is_api_valid() { - return _global_api != nullptr && _global_api->is_valid(); -} - -/** - * Returns true if the API has been successfully opened and may be used, or - * false if there is some problem. - */ -bool MayaApi:: -is_valid() const { - return _is_valid; -} - -#ifdef _WIN32 -static string -back_to_front_slash(const string &str) { - string result = str; - string::iterator si; - for (si = result.begin(); si != result.end(); ++si) { - if ((*si) == '\\') { - (*si) = '/'; - } - } - - return result; -} -#endif // WIN32 - -/** - * Reads the indicated maya file into the global model space. Returns true if - * successful, false otherwise. - */ -bool MayaApi:: -read(const Filename &filename) { - MFileIO::newFile(true); - - maya_cat.info() << "Reading " << filename << "\n"; - - // Load the file into Maya. Maya seems to want forward slashes, even on - // Windows. - string os_filename = filename.to_os_generic(); - - string dirname = _cwd.to_os_specific(); - if (maya_cat.is_debug()) { - maya_cat.debug() << "cwd(read:before): " << dirname.c_str() << std::endl; - } - - MFileIO::newFile(true); - MStatus stat = MFileIO::open(os_filename.c_str()); - // Beginning with Maya2008, the call to read seem to change the current - // directory specially if there is a refrence file! Yikes! - - // Furthermore, the current directory may change during the call to any Maya - // function! Egad! - if (chdir(dirname.c_str()) < 0) { - maya_cat.warning() - << "Unable to restore current directory after ::read to " << _cwd - << " after initializing Maya.\n"; - } else { - if (maya_cat.is_debug()) { - maya_cat.debug() - << "Restored current directory after ::read to " << _cwd << "\n"; - } - } - if (!stat) { - stat.perror(os_filename.c_str()); - return false; - } - return true; -} - -/** - * Writes the global model space to the indicated file. Returns true if - * successful, false otherwise. - */ -bool MayaApi:: -write(const Filename &filename) { - maya_cat.info() << "Writing " << filename << "\n"; - string os_filename = filename.to_os_generic(); - - string dirname = _cwd.to_os_specific(); - if (maya_cat.is_debug()) { - maya_cat.debug() << "cwd(write:before): " << dirname.c_str() << std::endl; - } - - const char *type = "mayaBinary"; - string extension = filename.get_extension(); - if (extension == "ma") { - type = "mayaAscii"; - } - - MStatus stat = MFileIO::saveAs(os_filename.c_str(), type, true); - if (!stat) { - stat.perror(os_filename.c_str()); - return false; - } - // Beginning with Maya2008, the call to read seem to change the current - // directory specially if there is a refrence file! Yikes! - - // Furthermore, the current directory may change during the call to any Maya - // function! Egad! - if (chdir(dirname.c_str()) < 0) { - maya_cat.warning() - << "Unable to restore current directory after ::write to " << _cwd - << " after initializing Maya.\n"; - } else { - if (maya_cat.is_debug()) { - maya_cat.debug() - << "Restored current directory after ::write to " << _cwd << "\n"; - } - } - return true; -} - -/** - * Resets the global model space to the empty state, for instance in - * preparation for building a new file. Returns true if successful, false - * otherwise. - */ -bool MayaApi:: -clear() { - MStatus stat = MFileIO::newFile(true); - if (!stat) { - stat.perror("clear"); - return false; - } - return true; -} - -/** - * Returns Maya's internal units in effect. - */ -DistanceUnit MayaApi:: -get_units() { - switch (MDistance::internalUnit()) { - case MDistance::kInches: - return DU_inches; - case MDistance::kFeet: - return DU_feet; - case MDistance::kYards: - return DU_yards; - case MDistance::kMiles: - return DU_statute_miles; - case MDistance::kMillimeters: - return DU_millimeters; - case MDistance::kCentimeters: - return DU_centimeters; - case MDistance::kKilometers: - return DU_kilometers; - case MDistance::kMeters: - return DU_meters; - - default: - return DU_invalid; - } -} - -/** - * Set Maya's UI units. - */ -void MayaApi:: -set_units(DistanceUnit unit) { - switch (unit) { - case DU_inches: - MDistance::setUIUnit(MDistance::kInches); - break; - case DU_feet: - MDistance::setUIUnit(MDistance::kFeet); - break; - case DU_yards: - MDistance::setUIUnit(MDistance::kYards); - break; - case DU_statute_miles: - MDistance::setUIUnit(MDistance::kMiles); - break; - case DU_millimeters: - MDistance::setUIUnit(MDistance::kMillimeters); - break; - case DU_centimeters: - MDistance::setUIUnit(MDistance::kCentimeters); - break; - case DU_kilometers: - MDistance::setUIUnit(MDistance::kKilometers); - break; - case DU_meters: - MDistance::setUIUnit(MDistance::kMeters); - break; - - default: - ; - } -} - -/** - * Returns Maya's internal coordinate system in effect. - */ -CoordinateSystem MayaApi:: -get_coordinate_system() { - if (MGlobal::isYAxisUp()) { - return CS_yup_right; - } else { - return CS_zup_right; - } -} diff --git a/pandatool/src/maya/mayaApi.h b/pandatool/src/maya/mayaApi.h deleted file mode 100644 index f4e19e45da9..00000000000 --- a/pandatool/src/maya/mayaApi.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaApi.h - * @author drose - * @date 2002-04-15 - */ - -#ifndef MAYAAPI_H -#define MAYAAPI_H - -#include "pandatoolbase.h" -#include "distanceUnit.h" -#include "coordinateSystem.h" -#include "referenceCount.h" -#include "pointerTo.h" - -class Filename; - -/** - * This class presents a wrapper around the global Maya interface. While the - * reference count is held, it keeps the Maya interface open, and closes the - * interface when the object destructs. - */ -class MayaApi : public ReferenceCount { -protected: - MayaApi(const std::string &program_name, bool view_license = false, bool revertdir = true); - MayaApi(const MayaApi ©); - void operator = (const MayaApi ©); - -public: - ~MayaApi(); - - static PT(MayaApi) open_api(std::string program_name = "", bool view_license = false, bool revertdir = true); - static bool is_api_valid(); - bool is_valid() const; - - bool read(const Filename &filename); - bool write(const Filename &filename); - bool clear(); - - DistanceUnit get_units(); - void set_units(DistanceUnit unit); - CoordinateSystem get_coordinate_system(); - -private: - bool _is_valid; - bool _plug_in; - Filename _cwd; - static PT(MayaApi) _global_api; -}; - -#endif diff --git a/pandatool/src/maya/mayaShader.cxx b/pandatool/src/maya/mayaShader.cxx deleted file mode 100644 index 9be62a60d34..00000000000 --- a/pandatool/src/maya/mayaShader.cxx +++ /dev/null @@ -1,517 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaShader.cxx - * @author drose - * @date 2000-02-01 - * Modified 19Mar10 by ETC PandaSE team (see - * header comment for mayaToEgg.cxx for details) - */ - -#include "mayaShader.h" -#include "maya_funcs.h" -#include "config_maya.h" -#include "string_utils.h" -#include "pnmImageHeader.h" // for lumin_red, etc. -#include "pset.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -using std::endl; -using std::string; - -/** - * Reads the Maya "shading engine" to determine the relevant shader - * properties. - */ -MayaShader:: -MayaShader(MObject engine, bool legacy_shader) { - MFnDependencyNode engine_fn(engine); - - set_name(engine_fn.name().asChar()); - - if (maya_cat.is_debug()) { - maya_cat.debug() - << "Reading shading engine " << get_name() << "\n"; - } - _legacy_mode = false; - _flat_color.set(1,1,1,1); - - MPlug shader_plug = engine_fn.findPlug("surfaceShader"); - bool found_shader = false; - if (!shader_plug.isNull()) { - MPlugArray shader_pa; - shader_plug.connectedTo(shader_pa, true, false); - maya_cat.spam() << "shader plug connected to: " << shader_pa.length() << endl; - for (size_t i = 0; i < shader_pa.length() && !found_shader; i++) { - MObject shader = shader_pa[0].node(); - if (shader.hasFn(MFn::kPhong)) { - if (legacy_shader) { - found_shader = find_textures_legacy(shader); - } else { - found_shader = find_textures_modern(shader); - } - } else if (shader.hasFn(MFn::kLambert)) { - found_shader = find_textures_legacy(shader); - if (found_shader) { - _legacy_mode = true; - } - } else if (shader.hasFn(MFn::kSurfaceShader)) { - found_shader = find_textures_legacy(shader); - if (found_shader) { - _legacy_mode = true; - } - } else { - maya_cat.warning() << - "Unrecognized shader type: only lambert and phong supported (lambert deprecated).\n"; - } - } - } -} - -/** - * - */ -MayaShader:: -~MayaShader() { -} - -/** - * - */ -void MayaShader:: -output(std::ostream &out) const { - out << "Shader " << get_name(); -} - -/** - * - */ -void MayaShader:: -write(std::ostream &out) const { - out << "Shader " << get_name() << "\n"; -} - -/** - * This is part of the deprecated codepath. return the color def i.e. - * texture at idx - */ -MayaShaderColorDef *MayaShader:: -get_color_def(size_t idx) const { - if (_color.size() > 0) - return _color[idx]; - else - return nullptr; -} -/** - * Returns the overall color of the shader as a single-precision rgba value, - * where the alpha component represents transparency according to the Panda - * convention. If no overall color is specified (_has_flat_color is not - * true), this returns white. - * - * Normally, Maya makes texture color override the flat color, so if a texture - * is also applied (_has_texture is true), this value is not used by Maya. - */ -LColor MayaShader:: -get_rgba(size_t idx) const { - LColor rgba(1.0f, 1.0f, 1.0f, 1.0f); - - if (_color.size() && _color[idx]->_has_flat_color) { - rgba[0] = (PN_stdfloat)_color[idx]->_flat_color[0]; - rgba[1] = (PN_stdfloat)_color[idx]->_flat_color[1]; - rgba[2] = (PN_stdfloat)_color[idx]->_flat_color[2]; - } - - if (_transparency._has_flat_color) { - // Maya supports colored transparency, but we only support grayscale - // transparency. Use the pnmimage constants to convert color to - // grayscale. - double trans = - _transparency._flat_color[0] * lumin_red + - _transparency._flat_color[1] * lumin_grn + - _transparency._flat_color[2] * lumin_blu; - rgba[3] = 1.0f - (PN_stdfloat)trans; - } - - return rgba; -} - -/** - * Recalculates the all_maps list. - */ -void MayaShader:: -collect_maps() { - _all_maps.clear(); - - for (size_t i=0; i<_color_maps.size(); i++) { - _all_maps.push_back(_color_maps[i]); - } - for (size_t i=0; i<_trans_maps.size(); i++) { - _all_maps.push_back(_trans_maps[i]); - } - for (size_t i=0; i<_normal_maps.size(); i++) { - _all_maps.push_back(_normal_maps[i]); - } - for (size_t i=0; i<_glow_maps.size(); i++) { - _all_maps.push_back(_glow_maps[i]); - } - for (size_t i=0; i<_gloss_maps.size(); i++) { - _all_maps.push_back(_gloss_maps[i]); - } - for (size_t i=0; i<_height_maps.size(); i++) { - _all_maps.push_back(_height_maps[i]); - } - - for (size_t i=0; i<_color.size(); i++) { - if (_color[i]->_has_texture) { - _all_maps.push_back(_color[i]); - } - } - if (_transparency._has_texture) { - _all_maps.push_back(&_transparency); - } -} - -/** - * Locates all file textures leading into the given shader. - */ -bool MayaShader:: -find_textures_modern(MObject shader) { - if (!shader.hasFn(MFn::kPhong)) { - maya_cat.warning() - << "The new codepath expects to see phong shaders only.\n"; - return false; - } - MStatus status; - MFnPhongShader phong_fn(shader); - MFnDependencyNode shader_fn(shader); - - if (maya_cat.is_spam()) { - maya_cat.spam() - << " Reading modern surface shader " << shader_fn.name().asChar() << "\n"; - } - - string n = shader_fn.name().asChar(); - - MayaShaderColorDef::find_textures_modern(n, _color_maps, shader_fn.findPlug("color"), false); - if (_color_maps.size() == 0) { - MayaShaderColorDef::find_textures_modern(n, _color_maps, shader_fn.findPlug("colorR"), false); - } - MayaShaderColorDef::find_textures_modern(n, _trans_maps, shader_fn.findPlug("transparency"), true); - if (_trans_maps.size() == 0) { - MayaShaderColorDef::find_textures_modern(n, _trans_maps, shader_fn.findPlug("transparencyR"), true); - } - MayaShaderColorDef::find_textures_modern(n, _normal_maps, shader_fn.findPlug("normalCamera"), false); - if (_normal_maps.size() == 0) { - MayaShaderColorDef::find_textures_modern(n, _normal_maps, shader_fn.findPlug("normalCameraR"), false); - } - MayaShaderColorDef::find_textures_modern(n, _gloss_maps, shader_fn.findPlug("specularColor"), true); - if (_gloss_maps.size() == 0) { - MayaShaderColorDef::find_textures_modern(n, _gloss_maps, shader_fn.findPlug("specularColorR"), true); - } - MayaShaderColorDef::find_textures_modern(n, _glow_maps, shader_fn.findPlug("incandescence"), true); - if (_glow_maps.size() == 0) { - MayaShaderColorDef::find_textures_modern(n, _glow_maps, shader_fn.findPlug("incandescenceR"), true); - } - MayaShaderColorDef::find_textures_modern(n, _height_maps, shader_fn.findPlug("surfaceThickness"), true); - if (_height_maps.size() == 0) { - MayaShaderColorDef::find_textures_modern(n, _height_maps, shader_fn.findPlug("surfaceThicknessR"), true); - } - - collect_maps(); - - MColor color = phong_fn.color(&status); - if (status) { - _flat_color.set(color.r, color.g, color.b, color.a); - } - - color = phong_fn.transparency(&status); - if (status) { - _flat_color[3] = 1.0 - ((color[0] + color[1] + color[2]) * (1.0/3.0)); - } - return true; -} - -/** - * Assigns the uvset_name of each MayaShaderColorDef using the given file-to- - * uvset map. - */ -void MayaShader:: -bind_uvsets(MayaFileToUVSetMap &map) { - for (size_t i=0; i<_all_maps.size(); i++) { - MayaShaderColorDef *def = _all_maps[i]; - MayaFileToUVSetMap::iterator p = map.find(def->_texture_name); - if (p == map.end()) { - def->_uvset_name = "map1"; - } else { - def->_uvset_name = (*p).second; - } - } - - calculate_pairings(); -} - -/** - * For each Alpha texture, try to find an RGB texture that has the same - * properties. Attempt to make it so that the alpha texture isn't a separate - * texture, but rather, an Alpha-Filename associated with an existing texture. - */ -void MayaShader:: -calculate_pairings() { - - if (_legacy_mode) { - return; - } - - for (size_t i=0; i<_all_maps.size(); i++) { - _all_maps[i]->_opposite = 0; - } - - bool using_transparency = (_trans_maps.size() > 0); - - for (int retry=0; retry<2; retry++) { - bool perfect=(retry==0); - for (size_t i=0; i<_color_maps.size(); i++) { - if ((_color_maps[i]->_blend_type == MayaShaderColorDef::BT_modulate)|| - (_color_maps[i]->_blend_type == MayaShaderColorDef::BT_unspecified)) { - for (size_t j=0; j<_trans_maps.size(); j++) { - try_pair(_color_maps[i], _trans_maps[j], perfect); - } - } - } - } - - if (!using_transparency) { - for (int retry=0; retry<2; retry++) { - bool perfect=(retry==0); - for (size_t i=0; i<_color_maps.size(); i++) { - for (size_t j=0; j<_glow_maps.size(); j++) { - try_pair(_color_maps[i], _glow_maps[j], perfect); - } - for (size_t j=0; j<_gloss_maps.size(); j++) { - try_pair(_color_maps[i], _gloss_maps[j], perfect); - } - } - } - } - - for (int retry=0; retry<2; retry++) { - bool perfect=(retry==0); - for (size_t i=0; i<_normal_maps.size(); i++) { - for (size_t j=0; j<_height_maps.size(); j++) { - try_pair(_normal_maps[i], _height_maps[j], perfect); - } - } - } - - for (size_t i=0; i<_normal_maps.size(); i++) { - _normal_maps[i]->_blend_type = MayaShaderColorDef::BT_normal; - } - for (size_t i=0; i<_glow_maps.size(); i++) { - if (_glow_maps[i]->_opposite) { - _glow_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; - _glow_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate_glow; - } else { - _glow_maps[i]->_blend_type = MayaShaderColorDef::BT_glow; - } - } - for (size_t i=0; i<_gloss_maps.size(); i++) { - if (_gloss_maps[i]->_opposite) { - _gloss_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; - _gloss_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate_gloss; - } else { - _gloss_maps[i]->_blend_type = MayaShaderColorDef::BT_gloss; - } - } - for (size_t i=0; i<_height_maps.size(); i++) { - if (_height_maps[i]->_opposite) { - _height_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; - _height_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_normal_height; - } else { - _height_maps[i]->_blend_type = MayaShaderColorDef::BT_height; - } - } - for (size_t i=0; i<_trans_maps.size(); i++) { - if (_trans_maps[i]->_opposite) { - _trans_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; - _trans_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate; - } else { - _trans_maps[i]->_blend_type = MayaShaderColorDef::BT_modulate; - } - } -} - -/** - * Try to associate an RGB tex with an Alpha tex. - */ -bool MayaShader::try_pair(MayaShaderColorDef *map1, - MayaShaderColorDef *map2, - bool perfect) { - if ((map1->_opposite)||(map2->_opposite)) { - // one of the maps is already paired - return false; - } - if (perfect) { - if (map1->_texture_filename != map2->_texture_filename) { - // perfect mode requires a filename match. - return false; - } - } else { - string pre1 = get_file_prefix(map1->_texture_filename); - string pre2 = get_file_prefix(map2->_texture_filename); - if (pre1 != pre2) { - // imperfect mode requires a filename prefix match. - return false; - } - } - - if ((map1->_projection_type != map2->_projection_type) || - (map1->_projection_matrix != map2->_projection_matrix) || - (map1->_u_angle != map2->_u_angle) || - (map1->_v_angle != map2->_v_angle) || - (map1->_uvset_name != map2->_uvset_name) || - (map1->_mirror != map2->_mirror) || - (map1->_stagger != map2->_stagger) || - (map1->_wrap_u != map2->_wrap_u) || - (map1->_wrap_v != map2->_wrap_v) || - (map1->_repeat_uv != map2->_repeat_uv) || - (map1->_offset != map2->_offset) || - (map1->_rotate_uv != map2->_rotate_uv)) { - return false; - } - // Pairing successful. - map1->_opposite = map2; - map2->_opposite = map1; - return true; -} - -/** - * Try to associate an RGB tex with an Alpha tex. - */ -string MayaShader:: -get_file_prefix(const string &fn) { - Filename pfn = Filename::from_os_specific(fn); - string base = pfn.get_basename_wo_extension(); - size_t offs = base.find("_"); - if (offs != string::npos) { - base = base.substr(0, offs); - } - offs = base.find("-"); - if (offs != string::npos) { - base = base.substr(0, offs); - } - return base; -} - -/** - * This is part of the legacy codepath. Extracts out the shading information - * from the Maya surface shader. - */ -bool MayaShader:: -find_textures_legacy(MObject shader) { - MStatus status; - MFnDependencyNode shader_fn(shader); - - if (maya_cat.is_spam()) { - maya_cat.spam() - << " Reading legacy surface shader " << shader_fn.name().asChar() << "\n"; - } - - // First, check for a connection to the color attribute. This could be a - // texture map or something, and will override whatever the shader says for - // color. - - MPlug color_plug = shader_fn.findPlug("color"); - if (color_plug.isNull()) { - // Or maybe a connection to outColor. Not sure how this differs from just - // color, but empirically it seems that either might be used. - color_plug = shader_fn.findPlug("outColor"); - } - - if (!color_plug.isNull()) { - MPlugArray color_pa; - color_plug.connectedTo(color_pa, true, false); - - MayaShaderColorDef *color_p = new MayaShaderColorDef; - for (size_t i = 0; i < color_pa.length(); i++) { - maya_cat.spam() << "color_pa[" << i << "]:" << color_pa[i].name().asChar() << endl; - color_p->find_textures_legacy(this, color_pa[0].node()); - } - - if (color_pa.length() < 1) { - // assign a blank default color to this shader - maya_cat.spam() << shader_fn.name().asChar() << " was not connected to texture" << endl; - this->_color.push_back(color_p); - } - } - - // Transparency is stored separately. - MPlug trans_plug = shader_fn.findPlug("transparency"); - if (trans_plug.isNull()) { - trans_plug = shader_fn.findPlug("outTransparency"); - } - - if (!trans_plug.isNull()) { - MPlugArray trans_pa; - trans_plug.connectedTo(trans_pa, true, false); - - for (size_t i = 0; i < trans_pa.length(); i++) { - maya_cat.spam() << "read a transparency texture" << endl; - _transparency.find_textures_legacy(this, trans_pa[0].node(), true); - } - } - - // Also try to get the ordinary color directly from the surface shader. - bool b_color_def = true; - if (shader.hasFn(MFn::kLambert)) { - MFnLambertShader lambert_fn(shader); - MColor color = lambert_fn.color(&status); - if (status) { - // Warning! The alpha component of color doesn't mean transparency in - // Maya. - for (size_t i=0; i<_color.size(); ++i) { - _color[i]->_has_flat_color = true; - _color[i]->_flat_color.set(color.r, color.g, color.b, color.a); - maya_cat.spam() << shader_fn.name().asChar() << " set shader color" << endl; - // needed to print the final check - if (!_color[i]->_has_flat_color && !_color[i]->_has_texture) - b_color_def = false; - - _transparency._flat_color.set(0.0, 0.0, 0.0, 0.0); - - // Get the transparency separately. - color = lambert_fn.transparency(&status); - if (status) { - _transparency._has_flat_color = true; - _transparency._flat_color.set(color.r, color.g, color.b, color.a); - } - } - } - } - // if (!_color._has_flat_color && !_color._has_texture) { - if (!b_color_def) { - maya_cat.info() << shader_fn.name().asChar() << "Color def not found" << endl; - if (maya_cat.is_spam()) { - maya_cat.spam() - << " Color definition not found.\n"; - } - } - - collect_maps(); - return true; -} diff --git a/pandatool/src/maya/mayaShader.h b/pandatool/src/maya/mayaShader.h deleted file mode 100644 index 34ff13a8083..00000000000 --- a/pandatool/src/maya/mayaShader.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaShader.h - * @author drose - * @date 2000-02-01 - */ - -#ifndef MAYASHADER_H -#define MAYASHADER_H - -#include "pandatoolbase.h" -#include "mayaShaderColorDef.h" - -#include "luse.h" -#include "lmatrix.h" -#include "namable.h" - - -/** - * Corresponds to a single "shader" in Maya. This extracts out all the - * parameters of a Maya shader that we might care about. There are many more - * parameters that we don't care about or don't know enough to extract. - */ -class MayaShader : public Namable { -public: - MayaShader(MObject engine, bool legacy_shader); - ~MayaShader(); - - void output(std::ostream &out) const; - void write(std::ostream &out) const; - -private: - bool find_textures_modern(MObject shader); - bool find_textures_legacy(MObject shader); - -public: - void collect_maps(); - bool _legacy_mode; - - MayaShaderColorList _all_maps; - -public: // relevant only to modern mode. - - LColord _flat_color; - - MayaShaderColorList _color_maps; - MayaShaderColorList _trans_maps; - MayaShaderColorList _normal_maps; - MayaShaderColorList _glow_maps; - MayaShaderColorList _gloss_maps; - MayaShaderColorList _height_maps; - - void bind_uvsets(MayaFileToUVSetMap &map); - -private: - void calculate_pairings(); - bool try_pair(MayaShaderColorDef *map1, - MayaShaderColorDef *map2, - bool perfect); - std::string get_file_prefix(const std::string &fn); - bool _legacy_shader; -public: // relevant only to legacy mode. - MayaShaderColorList _color; - MayaShaderColorDef _transparency; - LColor get_rgba(size_t idx=0) const; - MayaShaderColorDef *get_color_def(size_t idx=0) const; -}; - -INLINE std::ostream &operator << (std::ostream &out, const MayaShader &shader) { - shader.output(out); - return out; -} - -#endif diff --git a/pandatool/src/maya/mayaShaderColorDef.cxx b/pandatool/src/maya/mayaShaderColorDef.cxx deleted file mode 100644 index 38aa294949a..00000000000 --- a/pandatool/src/maya/mayaShaderColorDef.cxx +++ /dev/null @@ -1,799 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaShaderColorDef.cxx - * @author drose - * @date 2003-04-12 - * Modified 19Mar10 by ETC PandaSE team (see - * header comment for mayaToEgg.cxx for details) - */ - -#include "mayaShaderColorDef.h" -#include "mayaShader.h" -#include "maya_funcs.h" -#include "config_maya.h" -#include "string_utils.h" -#include "pset.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -using std::endl; -using std::string; - -/** - * - */ -MayaShaderColorDef:: -MayaShaderColorDef() { - - _blend_type = BT_unspecified; - - _projection_type = PT_off; - _projection_matrix = LMatrix4d::ident_mat(); - _u_angle = 0.0; - _v_angle = 0.0; - - _texture_filename = ""; - _texture_name = ""; - _color_gain.set(1.0f, 1.0f, 1.0f, 1.0f); - - _coverage.set(1.0, 1.0); - _translate_frame.set(0.0, 0.0); - _rotate_frame = 0.0; - - _mirror = false; - _stagger = false; - _wrap_u = true; - _wrap_v = true; - - _repeat_uv.set(1.0, 1.0); - _offset.set(0.0, 0.0); - _rotate_uv = 0.0; - - _is_alpha = false; - - _opposite = 0; - - _color_object = nullptr; - - _has_texture = false; - _has_flat_color = false; - _flat_color.set(0.0, 0.0, 0.0, 0.0); - _has_alpha_channel = false; - _keep_color = false; // classic mode overwrites color: new mode retains color with a 3rd layer - _keep_alpha = false; - _interpolate = false; - _uvset_name = "map1"; - - _map_uvs = nullptr; -} - -/** - * - */ -MayaShaderColorDef:: -MayaShaderColorDef(MayaShaderColorDef ©) { - _has_texture = copy._has_texture; - _texture_filename = copy._texture_filename; - _texture_name = copy._texture_name; - _uvset_name = copy._uvset_name; - _color_gain = copy._color_gain; - - _has_flat_color = copy._has_flat_color; - _flat_color = copy._flat_color; - - _projection_type = copy._projection_type; - _projection_matrix = copy._projection_matrix; - _u_angle = copy._u_angle; - _v_angle = copy._v_angle; - - _coverage = copy._coverage; - _translate_frame = copy._translate_frame; - _rotate_frame = copy._rotate_frame; - - _mirror = copy._mirror; - _stagger = copy._stagger; - _wrap_u = copy._wrap_u; - _wrap_v = copy._wrap_v; - - _blend_type = copy._blend_type; - _has_alpha_channel = copy._has_alpha_channel; - _keep_color = copy._keep_color; - _keep_alpha = copy._keep_alpha; - _interpolate = copy._interpolate; - - _repeat_uv = copy._repeat_uv; - _offset = copy._offset; - _rotate_uv = copy._rotate_uv; - - _is_alpha = copy._is_alpha; - - _map_uvs = copy._map_uvs; - _color_object = copy._color_object; - - _opposite = 0; -} - -/** - * - */ -MayaShaderColorDef:: -~MayaShaderColorDef() { - delete _color_object; -} - -/** - * Returns a texture matrix corresponding to the texture transforms indicated - * by the shader. - */ -LMatrix3d MayaShaderColorDef:: -compute_texture_matrix() const { - LVector2d scale(_repeat_uv[0] / _coverage[0], - _repeat_uv[1] / _coverage[1]); - LVector2d trans(_offset[0] - _translate_frame[0] / _coverage[0], - _offset[1] - _translate_frame[1] / _coverage[1]); - - return - (LMatrix3d::translate_mat(LVector2d(-0.5, -0.5)) * - LMatrix3d::rotate_mat(_rotate_frame) * - LMatrix3d::translate_mat(LVector2d(0.5, 0.5))) * - LMatrix3d::scale_mat(scale) * - LMatrix3d::translate_mat(trans); -} - -/** - * Returns true if the shader has a projection in effect. - */ -bool MayaShaderColorDef:: -has_projection() const { - return (_projection_type != PT_off); -} - -/** - * If the shader has a projection (has_projection() returns true), this - * computes the appropriate UV corresponding to the indicated 3-d point. - * Seams that might be introduced on polygons that cross quadrants are closed - * up by ensuring the point is in the same quadrant as the indicated reference - * point. - */ -LTexCoordd MayaShaderColorDef:: -project_uv(const LPoint3d &pos, const LPoint3d ¢roid) const { - nassertr(_map_uvs != nullptr, LTexCoordd::zero()); - return (this->*_map_uvs)(pos * _projection_matrix, centroid * _projection_matrix); -} - -/** - * - */ -void MayaShaderColorDef:: -write(std::ostream &out) const { - if (_has_texture) { - out << " texture filename is " << _texture_filename << "\n" - << " texture name is " << _texture_name << "\n" - << " uv_set name is " << _uvset_name << "\n" - << " coverage is " << _coverage << "\n" - << " translate_frame is " << _translate_frame << "\n" - << " rotate_frame is " << _rotate_frame << "\n" - << " mirror is " << _mirror << "\n" - << " stagger is " << _stagger << "\n" - << " wrap_u is " << _wrap_u << "\n" - << " wrap_v is " << _wrap_v << "\n" - << " repeat_uv is " << _repeat_uv << "\n" - << " offset is " << _offset << "\n" - << " rotate_uv is " << _rotate_uv << "\n" - << " color_gain is " << _color_gain << "\n"; - - } else if (_has_flat_color) { - out << " flat color is " << _flat_color << "\n"; - } -} - -/** - * Changes the texture filename stored in the Maya file for this particular - * shader. - */ -bool MayaShaderColorDef:: -reset_maya_texture(const Filename &texture) { - if (_color_object != nullptr) { - _has_texture = set_string_attribute(*_color_object, "fileTextureName", - texture.to_os_generic()); - _texture_filename = texture; - - if (!_has_texture) { - maya_cat.error() - << "Unable to reset texture filename.\n"; - } - - return _has_texture; - } - - maya_cat.error() - << "Attempt to reset texture on Maya object that has no color set.\n"; - return false; -} - - -/** - * Maya's default uvset name is "map1". Panda's default uvset name is - * "default". Otherwise, leaves uvset name untranslated. - */ -string MayaShaderColorDef:: -get_panda_uvset_name() { - if (_uvset_name == "map1") { - return "default"; - } - return _uvset_name; -} - -/** - * This is part of the deprecated codepath. Determines the surface color - * specified by the shader. This includes texturing and other advanced shader - * properties. - */ -void MayaShaderColorDef:: -find_textures_legacy(MayaShader *shader, MObject color, bool trans) { - LRGBColor color_gain; - if (get_vec3_attribute(color, "colorGain", color_gain)) { - color_gain[0] = color_gain[0] > 1.0 ? 1.0 : color_gain[0]; - color_gain[0] = color_gain[0] < 0.0 ? 0.0 : color_gain[0]; - _color_gain[0] *= color_gain[0]; - color_gain[1] = color_gain[1] > 1.0 ? 1.0 : color_gain[1]; - color_gain[1] = color_gain[1] < 0.0 ? 0.0 : color_gain[1]; - _color_gain[1] *= color_gain[1]; - color_gain[2] = color_gain[2] > 1.0 ? 1.0 : color_gain[2]; - color_gain[2] = color_gain[2] < 0.0 ? 0.0 : color_gain[2]; - _color_gain[2] *= color_gain[2]; - } - PN_stdfloat alpha_gain; - if (get_maya_attribute(color, "alphaGain", alpha_gain)) { - alpha_gain = alpha_gain > 1.0 ? 1.0 : alpha_gain; - alpha_gain = alpha_gain < 0.0 ? 0.0 : alpha_gain; - _color_gain[3] *= alpha_gain; - } - if (color.hasFn(MFn::kFileTexture)) { - MFnDependencyNode dfn(color); - _color_object = new MObject(color); - _texture_name = dfn.name().asChar(); - string filename; - _has_texture = get_string_attribute(color, "fileTextureName", filename); - _has_texture = _has_texture && !filename.empty(); - if (_has_texture) { - _texture_filename = Filename::from_os_specific(filename); - if (_texture_filename.is_directory()) { - maya_cat.warning() - << "Shader " << shader->get_name() - << " references texture filename " << filename - << " which is a directory; clearing.\n"; - _has_texture = false; - set_string_attribute(color, "fileTextureName", ""); - } - } - - get_vec2_attribute(color, "coverage", _coverage); - get_vec2_attribute(color, "translateFrame", _translate_frame); - get_angle_attribute(color, "rotateFrame", _rotate_frame); - - // get_bool_attribute(color, "alphaIsLuminance", _alpha_is_luminance); - - get_bool_attribute(color, "mirror", _mirror); - get_bool_attribute(color, "stagger", _stagger); - get_bool_attribute(color, "wrapU", _wrap_u); - get_bool_attribute(color, "wrapV", _wrap_v); - - get_vec2_attribute(color, "repeatUV", _repeat_uv); - get_vec2_attribute(color, "offset", _offset); - get_angle_attribute(color, "rotateUV", _rotate_uv); - - if (!trans) { - if (maya_cat.is_debug()) { - maya_cat.debug() << "pushed a file texture" << endl; - } - shader->_color.push_back(this); - } - - } else if (color.hasFn(MFn::kProjection)) { - if (maya_cat.is_debug()) { - maya_cat.debug() << "reading a projection texture" << endl; - } - // This is a projected texture. We will have to step one level deeper to - // find the actual texture. - MFnDependencyNode projection_fn(color); - MPlug image_plug = projection_fn.findPlug("image"); - if (!image_plug.isNull()) { - MPlugArray image_pa; - image_plug.connectedTo(image_pa, true, false); - - for (size_t i = 0; i < image_pa.length(); i++) { - find_textures_legacy(shader, image_pa[0].node()); - } - } - - if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) { - _projection_matrix = LMatrix4d::ident_mat(); - } - - // The uAngle and vAngle might be used for certain kinds of projections. - if (!get_angle_attribute(color, "uAngle", _u_angle)) { - _u_angle = 360.0; - } - if (!get_angle_attribute(color, "vAngle", _v_angle)) { - _v_angle = 180.0; - } - - string type; - if (get_enum_attribute(color, "projType", type)) { - set_projection_type(type); - } - - } else if (color.hasFn(MFn::kLayeredTexture)) { - if (maya_cat.is_debug()) { - maya_cat.debug() << "Found layered texture" << endl; - } - - int blendValue; - MStatus status; - MPlugArray color_pa; - MFnDependencyNode layered_fn(color); - layered_fn.getConnections(color_pa); - MPlug inputsPlug = layered_fn.findPlug("inputs", &status); - MPlug blendModePlug = layered_fn.findPlug("blendMode", &status); - - if (maya_cat.is_debug()) { - maya_cat.debug() << "number of connections: " << color_pa.length() << endl; - } - bool first = true; - BlendType bt = BT_modulate; - for (size_t i=0; i -1) { - // found a blend mode - if (maya_cat.is_spam()) { - MString name = inputsPlug.name(); - maya_cat.spam() << "*** Start doIt... ***" << endl; - maya_cat.spam() << "inputsPlug Name: " << name.asChar() << endl; - } - status = blendModePlug.selectAncestorLogicalIndex(li,inputsPlug); - blendModePlug.getValue(blendValue); - - if (maya_cat.is_spam()) { - MString name = blendModePlug.name(); - maya_cat.spam() - << name.asChar() << ": has value " << blendValue << endl; - } - - MFnEnumAttribute blendModeEnum(blendModePlug); - MString blendName = blendModeEnum.fieldName(blendValue, &status); - - switch (blendValue) { - case 1: - bt = BT_decal; - get_bool_attribute(color, "interpolate", _interpolate); - maya_cat.info() << "interpolate: " << _interpolate << endl; - _keep_color = true; - break; - case 6: - bt = BT_modulate; - get_bool_attribute(color, "keepAlpha", _keep_alpha); - maya_cat.info() << "keepAlpha: " << _keep_alpha << endl; - break; - case 4: - bt = BT_add; - break; - } - - if (maya_cat.is_info()) { - MString name = layered_fn.name(); - maya_cat.info() << name.asChar() << ": blendMode used " << blendName.asChar() << endl; - if (maya_cat.is_spam()) { - maya_cat.spam() << "*** END doIt... ***" << endl; - } - } - - // advance to the next plug, because that is where the shader info are - pl = color_pa[++i]; - pl.connectedTo(pla, true, false); - } - for (size_t j=0; jfind_textures_legacy(shader, pla[j].node()); - color_p->_blend_type = bt; - size_t loc = color_p->_texture_name.find('.',0); - if (loc != string::npos) { - color_p->_texture_name.resize(loc); - } - if (maya_cat.is_debug()) { - maya_cat.debug() << "uv_name : " << color_p->_texture_name << endl; - } - } - else { - if (maya_cat.is_debug()) { - maya_cat.debug() << pl.name().asChar() << " first:connectedTo: " << pla_name << endl; - } - find_textures_legacy(shader, pla[j].node()); - _texture_name.assign(pla[j].name().asChar()); - _blend_type = bt; - size_t loc = _texture_name.find('.',0); - if (loc != string::npos) { - _texture_name.resize(loc); - } - if (maya_cat.is_debug()) { - maya_cat.debug() << "uv_name : " << _texture_name << endl; - } - first = false; - } - } - } - } else { - // This shader wasn't understood. - if (maya_cat.is_debug()) { - maya_cat.info() - << "**Don't know how to interpret color attribute type " - << color.apiTypeStr() << "\n"; - - } else { - // If we don't have a heavy verbose count, only report each type of - // unsupported shader once. - static pset bad_types; - if (bad_types.insert(color.apiType()).second) { - maya_cat.info() - << "**Don't know how to interpret color attribute type " - << color.apiTypeStr() << "\n"; - } - } - } -} - -/** - * Search to find any file textures that lead into the given input plug. Any - * textures found will be added to the provided MayaShaderColorList. - */ -void MayaShaderColorDef:: -find_textures_modern(const string &shadername, MayaShaderColorList &list, MPlug inplug, bool is_alpha) { - - MPlugArray outplugs; - inplug.connectedTo(outplugs, true, false); - if (outplugs.length() == 0) { - return; - } - if (outplugs.length() > 1) { - // Only one output plug should be connected to a given input plug. - maya_cat.warning() - << "Shader " << shadername << " has weird plug connections.\n"; - return; - } - MPlug outplug = outplugs[0]; - MObject source = outplug.node(); - MFnDependencyNode sourceFn(source); - - if (source.hasFn(MFn::kFileTexture)) { - - string filename; - bool hasfn = get_string_attribute(source, "fileTextureName", filename); - if ((!hasfn) || (filename.empty())) { - maya_cat.warning() - << "Shader " << shadername << " references file texture " - << "with no file name, ignoring invalid file texture.\n"; - return; - } - Filename fn = filename; - if (fn.is_directory()) { - maya_cat.warning() - << "Shader " << shadername << " references file name " - << filename << " which is a directory, ignoring it.\n"; - return; - } - - MayaShaderColorDef *def = new MayaShaderColorDef; - - def->_color_object = new MObject(source); - def->_texture_filename = Filename::from_os_specific(filename); - def->_texture_name = sourceFn.name().asChar(); - - get_vec2_attribute(source, "coverage", def->_coverage); - get_vec2_attribute(source, "translateFrame", def->_translate_frame); - get_angle_attribute(source, "rotateFrame", def->_rotate_frame); - - get_bool_attribute(source, "mirror", def->_mirror); - get_bool_attribute(source, "stagger", def->_stagger); - get_bool_attribute(source, "wrapU", def->_wrap_u); - get_bool_attribute(source, "wrapV", def->_wrap_v); - - get_vec2_attribute(source, "repeatUV", def->_repeat_uv); - get_vec2_attribute(source, "offset", def->_offset); - get_angle_attribute(source, "rotateUV", def->_rotate_uv); - - LRGBColor color_gain; - PN_stdfloat alpha_gain; - get_vec3_attribute(source, "colorGain", color_gain); - get_maya_attribute(source, "alphaGain", alpha_gain); - def->_color_gain[0] = color_gain[0]; - def->_color_gain[1] = color_gain[1]; - def->_color_gain[2] = color_gain[2]; - def->_color_gain[3] = alpha_gain; - - def->_is_alpha = is_alpha; - - if (maya_cat.is_debug()) { - maya_cat.debug() << "pushed a file texture" << endl; - } - list.push_back(def); - - return; - } - - if (source.hasFn(MFn::kProjection)) { - // This is a projected texture. We will have to step one level deeper to - // find the actual texture. - size_t before = list.size(); - MPlug image_plug = sourceFn.findPlug("image"); - if (!image_plug.isNull()) { - MPlugArray image_pa; - image_plug.connectedTo(image_pa, true, false); - - for (size_t i = 0; i < image_pa.length(); i++) { - find_textures_modern(shadername, list, image_pa[0], is_alpha); - } - } - - // Now apply any inherited attributes to all textures found. - - for (size_t i=before; i_projection_matrix)) { - def->_projection_matrix = LMatrix4d::ident_mat(); - } - - // The uAngle and vAngle might be used for certain kinds of projections. - if (!get_angle_attribute(source, "uAngle", def->_u_angle)) { - def->_u_angle = 360.0; - } - if (!get_angle_attribute(source, "vAngle", def->_v_angle)) { - def->_v_angle = 180.0; - } - - string type; - if (get_enum_attribute(source, "projType", type)) { - def->set_projection_type(type); - } - } - return; - } - - if (source.hasFn(MFn::kLayeredTexture)) { - if (maya_cat.is_debug()) { - maya_cat.debug() << "Found layered texture" << endl; - } - - MPlug inputsPlug = sourceFn.findPlug("inputs"); - size_t nlayers = inputsPlug.numElements(); - for (size_t layer=0; layer_blend_type = BT_decal; break; - case 6: def->_blend_type = BT_modulate; break; - case 4: def->_blend_type = BT_add; break; - } - } - } - return; - } - - if (source.apiType() == MFn::kReverse) { - MPlug input_plug = sourceFn.findPlug("input"); - find_textures_modern(shadername, list, input_plug, is_alpha); - return; - } - - // This shader wasn't understood. - if (maya_cat.is_debug()) { - maya_cat.info() - << "**Don't know how to interpret color attribute type " - << source.apiTypeStr() << "\n"; - } else { - // If we don't have a heavy verbose count, only report each type of - // unsupported shader once. - static pset bad_types; - if (bad_types.insert(source.apiType()).second) { - maya_cat.warning() - << "Don't know how to export a shader of type " - << source.apiTypeStr() << " " << sourceFn.type() << "\n"; - } - } -} - -/** - * Sets up the shader to apply UV's according to the indicated projection - * type. - */ -void MayaShaderColorDef:: -set_projection_type(const string &type) { - if (cmp_nocase(type, "planar") == 0) { - _projection_type = PT_planar; - _map_uvs = &MayaShaderColorDef::map_planar; - - // The Planar projection normally projects to a range (-1, 1) in both - // axes. Scale this into our UV range of (0, 1). - _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.5, 0.5, 0.0, 1.0); - - } else if (cmp_nocase(type, "cylindrical") == 0) { - _projection_type = PT_cylindrical; - _map_uvs = &MayaShaderColorDef::map_cylindrical; - - // The cylindrical projection is orthographic in the Y axis; scale the - // range (-1, 1) in this axis into our UV range (0, 1). - _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.5, 0.0, 1.0); - - } else if (cmp_nocase(type, "spherical") == 0) { - _projection_type = PT_spherical; - _map_uvs = &MayaShaderColorDef::map_spherical; - - } else { - // Other projection types are currently unimplemented by the converter. - maya_cat.error() - << "Don't know how to handle type " << type << " projections.\n"; - _projection_type = PT_off; - _map_uvs = nullptr; - } -} - -/** - * Computes a UV based on the given point in space, using a planar projection. - */ -LPoint2d MayaShaderColorDef:: -map_planar(const LPoint3d &pos, const LPoint3d &) const { - // A planar projection is about as easy as can be. We ignore the Z axis, - // and project the point into the XY plane. Done. - return LPoint2d(pos[0], pos[1]); -} - -/** - * Computes a UV based on the given point in space, using a spherical - * projection. - */ -LPoint2d MayaShaderColorDef:: -map_spherical(const LPoint3d &pos, const LPoint3d ¢roid) const { - // To compute the x position on the frame, we only need to consider the - // angle of the vector about the Y axis. Project the vector into the XZ - // plane to do this. - - LVector2d xz(pos[0], pos[2]); - double xz_length = xz.length(); - - if (xz_length < 0.01) { - // If we have a point on or near either pole, we've got problems. This - // point maps to the entire bottom edge of the image, so which U value - // should we choose? It does make a difference, especially if we have a - // number of polygons around the south pole that all share the common - // vertex. - - // We choose the U value based on the polygon's centroid. - xz.set(centroid[0], centroid[2]); - } - - // Now, if the polygon crosses the seam, we also have problems. Make sure - // that the u value is in the same half of the texture as the centroid's u - // value. - double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle); - double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle); - - if (u - c > 0.5) { - u -= floor(u - c + 0.5); - } else if (u - c < -0.5) { - u += floor(c - u + 0.5); - } - - // Now rotate the vector into the YZ plane, and the V value is based on the - // latitude: the angle about the X axis. - LVector2d yz(pos[1], xz_length); - double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle); - - LPoint2d uv(u - 0.5, v - 0.5); - - nassertr(fabs(u - c) <= 0.5, uv); - return uv; -} - -/** - * Computes a UV based on the given point in space, using a cylindrical - * projection. - */ -LPoint2d MayaShaderColorDef:: -map_cylindrical(const LPoint3d &pos, const LPoint3d ¢roid) const { - // This is almost identical to the spherical projection, except for the - // computation of V. - - LVector2d xz(pos[0], pos[2]); - double xz_length = xz.length(); - - if (xz_length < 0.01) { -/* - * A cylindrical mapping has the same singularity problem at the pole as a - * spherical mapping does: points at the pole do not map to a single point on - * the texture. (It's technically a slightly different problem: in a - * cylindrical mapping, points at the pole do not map to any point on the - * texture, while in a spherical mapping, points at the pole map to the top or - * bottom edge of the texture. But this is a technicality that doesn't really - * apply to us.) We still solve it the same way: if our point is at or near - * the pole, compute the angle based on the centroid of the polygon (which we - * assume is further from the pole). - */ - xz.set(centroid[0], centroid[2]); - } - - // And cylinders do still have a seam at the back. - double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle; - double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle; - - if (u - c > 0.5) { - u -= floor(u - c + 0.5); - } else if (u - c < -0.5) { - u += floor(c - u + 0.5); - } - - // For a cylindrical mapping, the V value comes directly from Y. Easy. - LPoint2d uv(u - 0.5, pos[1]); - - nassertr(fabs(u - c) <= 0.5, uv); - return uv; -} diff --git a/pandatool/src/maya/mayaShaderColorDef.h b/pandatool/src/maya/mayaShaderColorDef.h deleted file mode 100644 index 2609f2bb433..00000000000 --- a/pandatool/src/maya/mayaShaderColorDef.h +++ /dev/null @@ -1,150 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaShaderColorDef.h - * @author drose - * @date 2003-04-12 - */ - -#ifndef MAYASHADERCOLORDEF_H -#define MAYASHADERCOLORDEF_H - -#include "pandatoolbase.h" - -#include "luse.h" -#include "lmatrix.h" -#include "pmap.h" -#include "pvector.h" - -class MayaShader; -class MayaShaderColorDef; -typedef pvector MayaShaderColorList; -typedef pmap MayaFileToUVSetMap; - -/** - * This defines the various attributes that Maya may associate with the - * "color" channel for a particular shader (as well as on the "transparency" - * channel). - */ -class MayaShaderColorDef { -public: - MayaShaderColorDef(); - MayaShaderColorDef (MayaShaderColorDef&); - ~MayaShaderColorDef(); - - std::string strip_prefix(std::string full_name); - - LMatrix3d compute_texture_matrix() const; - bool has_projection() const; - LTexCoordd project_uv(const LPoint3d &pos, const LPoint3d &ref_point) const; - bool reset_maya_texture(const Filename &texture); - - void write(std::ostream &out) const; - - enum BlendType { - BT_unspecified, - BT_modulate, - BT_decal, - BT_blend, - BT_replace, - BT_add, - BT_blend_color_scale, - BT_modulate_glow, - BT_modulate_gloss, - BT_normal, - BT_normal_height, - BT_gloss, - BT_glow, - BT_height, - BT_selector, - }; - - enum ProjectionType { - PT_off, - PT_planar, - PT_spherical, - PT_cylindrical, - PT_ball, - PT_cubic, - PT_triplanar, - PT_concentric, - PT_perspective, - }; - - BlendType _blend_type; - ProjectionType _projection_type; - LMatrix4d _projection_matrix; - double _u_angle; - double _v_angle; - - Filename _texture_filename; - std::string _texture_name; - LColor _color_gain; - - LVector2 _coverage; - LVector2 _translate_frame; - double _rotate_frame; - - bool _mirror; - bool _stagger; - bool _wrap_u; - bool _wrap_v; - - LVector2 _repeat_uv; - LVector2 _offset; - double _rotate_uv; - - bool _is_alpha; - - std::string _uvset_name; - MayaShaderColorDef *_opposite; - - std::string get_panda_uvset_name(); - -private: - MObject *_color_object; - -private: - static void find_textures_modern(const std::string &shadername, MayaShaderColorList &list, MPlug inplug, bool is_alpha); - void find_textures_legacy(MayaShader *shader, MObject color, bool trans=false); - - void set_projection_type(const std::string &type); - - LPoint2d map_planar(const LPoint3d &pos, const LPoint3d ¢roid) const; - LPoint2d map_spherical(const LPoint3d &pos, const LPoint3d ¢roid) const; - LPoint2d map_cylindrical(const LPoint3d &pos, const LPoint3d ¢roid) const; - - // Define a pointer to one of the above member functions. - LPoint2d (MayaShaderColorDef::*_map_uvs)(const LPoint3d &pos, const LPoint3d ¢roid) const; - - friend class MayaShader; - - -/* - * Legacy Fields - these fields are only used by the legacy codepath. These - * fields are deprecated for the following reasons: * has_texture is redundant - * --- if there's no texture, just don't allocate a MayaShaderColorDef. * - * has_flat_color and flat_color don't belong here, they belong in the shader. - * * has_alpha_channel is not needed - there are better ways to determine if a - * texture stage involves an alpha channel. * keep_color, keep_alpha, and - * interpolate are all adjuncts to blend_mode - it would make more sense just - * to add some more blend_modes. - */ - -public: - bool _has_texture; // deprecated, see above. - bool _has_flat_color; // deprecated, see above. - LColord _flat_color; // deprecated, see above. - bool _has_alpha_channel; // deprecated, see above. - bool _keep_color; // deprecated, see above. - bool _keep_alpha; // deprecated, see above. - bool _interpolate; // deprecated, see above. - -}; - -#endif diff --git a/pandatool/src/maya/mayaShaders.cxx b/pandatool/src/maya/mayaShaders.cxx deleted file mode 100644 index 3809574bcb7..00000000000 --- a/pandatool/src/maya/mayaShaders.cxx +++ /dev/null @@ -1,200 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaShaders.cxx - * @author drose - * @date 2000-02-11 - */ - -#include "mayaShaders.h" -#include "mayaShader.h" -#include "maya_funcs.h" -#include "config_maya.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -using std::string; - -/** - * - */ -MayaShaders:: -MayaShaders() { -} - -/** - * - */ -MayaShaders:: -~MayaShaders() { - clear(); -} - -/** - * Extracts the shader assigned to the indicated node. - */ -MayaShader *MayaShaders:: -find_shader_for_node(MObject node, bool legacy_shader) { - MStatus status; - MFnDependencyNode node_fn(node); - // Look on the instObjGroups attribute for shading engines. - MObject iog_attr = node_fn.attribute("instObjGroups", &status); - if (!status) { - // The node is not renderable. What are you thinking? - maya_cat.error() - << node_fn.name().asChar() << " : not a renderable object.\n"; - return nullptr; - } - - // instObjGroups is a multi attribute, whatever that means. For now, we'll - // just get the first connection, since that's what the example code did. - // Is there any reason to search deeper? - - MPlug iog_plug(node, iog_attr); - MPlugArray iog_pa; - iog_plug.elementByLogicalIndex(0).connectedTo(iog_pa, false, true, &status); - if (!status) { - // No shading group defined for this object. - maya_cat.error() - << node_fn.name().asChar() << " : no shading group defined.\n"; - return nullptr; - } - - // Now we have a number of ShadingEngines defined, one for each of these - // connections we just turned up. Usually there will only be one. In fact, - // we'll just take the first one we find. - - size_t i; - for (i = 0; i < iog_pa.length(); i++) { - MObject engine = iog_pa[i].node(); - if (engine.hasFn(MFn::kShadingEngine)) { - return find_shader_for_shading_engine(engine, legacy_shader); - } - } - - // Well, we didn't find a ShadingEngine after all. Huh. - if (maya_cat.is_debug()) { - maya_cat.debug() - << node_fn.name().asChar() << " : no shading engine found.\n"; - } - return nullptr; -} - -/** - * Causes all shaders in the set to use the given mesh as a file-to-uvset map. - */ -void MayaShaders:: -bind_uvsets(MObject mesh) { - _uvset_names.clear(); - _file_to_uvset.clear(); - - if (mesh.hasFn(MFn::kMesh)) { - MFnMesh mesh_fn(mesh); - MStatus status; - MStringArray maya_uvset_names; - status = mesh_fn.getUVSetNames(maya_uvset_names); - for (size_t i=0; ibind_uvsets(_file_to_uvset); - } -} - -/** - * Returns the MayaShader object associated with the indicated "shading - * engine". This will create a new MayaShader object if this is the first - * time we have encountered the indicated engine. - */ -MayaShader *MayaShaders:: -find_shader_for_shading_engine(MObject engine, bool legacy_shader) { - MFnDependencyNode engine_fn(engine); - // See if we have already decoded this engine. - string engine_name = engine_fn.name().asChar(); - Shaders::const_iterator si = _shaders.find(engine_name); - if (si != _shaders.end()) { - return (*si).second; - } - - // All right, this is a newly encountered shading engine. Create a new - // MayaShader object to represent it. - MayaShader *shader = new MayaShader(engine, legacy_shader); - shader->bind_uvsets(_file_to_uvset); - - // Record this for the future. - _shaders.insert(Shaders::value_type(engine_name, shader)); - _shaders_in_order.push_back(shader); - return shader; -} - -/** - * Returns the current mapping from file to uvset for the given file texture - * name. - */ -string MayaShaders:: -find_uv_link(const string &match) { - MayaFileToUVSetMap::iterator it = _file_to_uvset.find(match); - if (it == _file_to_uvset.end()) { - return "not found"; - } else { - return (*it).second; - } -} - -/** - * Returns the number of unique MayaShaders that have been discovered so far. - */ -int MayaShaders:: -get_num_shaders() const { - return _shaders_in_order.size(); -} - -/** - * Returns the nth MayaShader that has been discovered so far. - */ -MayaShader *MayaShaders:: -get_shader(int n) const { - nassertr(n >= 0 && n < (int)_shaders_in_order.size(), nullptr); - return _shaders_in_order[n]; -} - -/** - * Frees all of the previously-defined MayaShader objects associated with this - * set. - */ -void MayaShaders:: -clear() { - ShadersInOrder::iterator si; - for (si = _shaders_in_order.begin(); si != _shaders_in_order.end(); ++si) { - delete (*si); - } - - _shaders.clear(); - _shaders_in_order.clear(); - _file_to_uvset.clear(); -} diff --git a/pandatool/src/maya/mayaShaders.h b/pandatool/src/maya/mayaShaders.h deleted file mode 100644 index 5428ab5f73c..00000000000 --- a/pandatool/src/maya/mayaShaders.h +++ /dev/null @@ -1,51 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaShaders.h - * @author drose - * @date 2000-02-11 - */ - -#ifndef MAYASHADERS_H -#define MAYASHADERS_H - -#include "pandatoolbase.h" - -#include "pmap.h" -#include "pvector.h" -#include "mayaShaderColorDef.h" - -class MayaShader; - -/** - * Collects the set of MayaShaders that have been encountered so far. - */ -class MayaShaders { -public: - MayaShaders(); - ~MayaShaders(); - MayaShader *find_shader_for_node(MObject node, bool legacy_shader); - MayaShader *find_shader_for_shading_engine(MObject engine, bool legacy_shader); - - int get_num_shaders() const; - MayaShader *get_shader(int n) const; - - MayaFileToUVSetMap _file_to_uvset; - pvector _uvset_names; - void clear(); - void bind_uvsets(MObject mesh); - std::string find_uv_link(const std::string &match); - -private: - typedef pmap Shaders; - Shaders _shaders; - typedef pvector ShadersInOrder; - ShadersInOrder _shaders_in_order; -}; - -#endif diff --git a/pandatool/src/maya/maya_funcs.I b/pandatool/src/maya/maya_funcs.I deleted file mode 100644 index 1a56126c444..00000000000 --- a/pandatool/src/maya/maya_funcs.I +++ /dev/null @@ -1,26 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maya_funcs.I - * @author drose - * @date 2002-04-15 - */ - -/** - * - */ -INLINE std::ostream &operator << (std::ostream &out, const MString &str) { - return out << str.asChar(); -} - -/** - * - */ -INLINE std::ostream &operator << (std::ostream &out, const MVector &vec) { - return out << vec.x << " " << vec.y << " " << vec.z; -} diff --git a/pandatool/src/maya/maya_funcs.T b/pandatool/src/maya/maya_funcs.T deleted file mode 100644 index 3418ce36477..00000000000 --- a/pandatool/src/maya/maya_funcs.T +++ /dev/null @@ -1,48 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maya_funcs.T - * @author drose - * @date 2000-02-16 - */ - -/** - * A generic function to extract an attribute of some type from an MObject. - * This is used to implement get_bool_attribute(), etc. - */ -template -bool -get_maya_attribute(MObject &node, const std::string &attribute_name, - ValueType &value) { - bool status = false; - - MPlug plug; - if (get_maya_plug(node, attribute_name, plug)) { - status = plug.getValue(value); - } - - return status; -} - -/** - * A generic function to set an attribute of some type on an MObject. This is - * used to implement set_bool_attribute(), etc. - */ -template -bool -set_maya_attribute(MObject &node, const std::string &attribute_name, - ValueType &value) { - bool status = false; - - MPlug plug; - if (get_maya_plug(node, attribute_name, plug)) { - status = plug.setValue(value); - } - - return status; -} diff --git a/pandatool/src/maya/maya_funcs.cxx b/pandatool/src/maya/maya_funcs.cxx deleted file mode 100644 index b07b8089d1e..00000000000 --- a/pandatool/src/maya/maya_funcs.cxx +++ /dev/null @@ -1,731 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maya_funcs.cxx - * @author drose - * @date 2000-02-16 - */ - -#include "maya_funcs.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -using std::endl; -using std::string; - -/** - * Gets the named MPlug associated, if any. - */ -bool -get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug) { - MStatus status; - MFnDependencyNode node_fn(node, &status); - if (!status) { - maya_cat.error() - << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n"; - return false; - } - - MObject attr = node_fn.attribute(attribute_name.c_str(), &status); - if (!status) { - return false; - } - - MFnAttribute attr_fn(attr, &status); - if (!status) { - maya_cat.error() - << "Attribute " << attribute_name << " on " << node_fn.name().asChar() - << " is a " << attr.apiTypeStr() << ", not an Attribute.\n"; - return false; - } - - plug = MPlug(node, attr); - return true; -} - -/** - * Returns true if the named connection exists on the node and is connected to - * anything, false otherwise. - */ -bool -is_connected(MObject &node, const string &attribute_name) { - MPlug plug; - if (!get_maya_plug(node, attribute_name, plug)) { - return false; - } - - return plug.isConnected(); -} - -/** - * Returns true if the node has the indicated attribute, false otherwise. - */ -bool -has_attribute(MObject &node, const string &attribute_name) { - MStatus status; - MFnDependencyNode node_fn(node, &status); - if (!status) { - maya_cat.error() - << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n"; - return false; - } - - node_fn.attribute(attribute_name.c_str(), &status); - if (!status) { - // No such attribute. - return false; - } - return true; -} - -/** - * Removes the named attribute from the indicated Maya node. Returns true if - * successful, false otherwise. - */ -bool -remove_attribute(MObject &node, const string &attribute_name) { - MStatus status; - MFnDependencyNode node_fn(node, &status); - if (!status) { - maya_cat.error() - << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n"; - return false; - } - - MObject attr = node_fn.attribute(attribute_name.c_str(), &status); - if (!status) { - return false; - } - - { - // Just to prove the the attr is, in fact, an Attribute. According to the - // Maya docs, we shouldn't leave the MFnAttribute object around while we - // remove the attribute, though. - MFnAttribute attr_fn(attr, &status); - if (!status) { - maya_cat.error() - << "Attribute " << attribute_name << " on " << node_fn.name().asChar() - << " is a " << attr.apiTypeStr() << ", not an Attribute.\n"; - return false; - } - } - - MFnDependencyNode::MAttrClass type = node_fn.attributeClass(attr, &status); - if (!status) { - maya_cat.error() - << "Couldn't get class of attribute " << attribute_name << " on " - << node_fn.name().asChar() << ".\n"; - return false; - } - - status = node_fn.removeAttribute(attr, type); - if (!status) { - maya_cat.error() - << "Couldn't remove attribute " << attribute_name << " from " - << node_fn.name().asChar() << ".\n"; - return false; - } - - return true; -} - -/** - * Extracts the named boolean attribute from the MObject. - */ -bool -get_bool_attribute(MObject &node, const string &attribute_name, - bool &value) { - if (!has_attribute(node, attribute_name)) { - // For bool attributes only, we assume if the attribute is absent it's the - // same thing as being false. - return false; - } - - if (!get_maya_attribute(node, attribute_name, value)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have a bool value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - return true; -} - -/** - * Extracts the named angle in degrees from the MObject. - */ -bool -get_angle_attribute(MObject &node, const string &attribute_name, - double &value) { - MAngle maya_value; - if (!get_maya_attribute(node, attribute_name, maya_value)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have an angle value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - value = maya_value.asDegrees(); - return true; -} - -/** - * Extracts the named two-component vector from the MObject. - */ -bool -get_vec2_attribute(MObject &node, const string &attribute_name, - LVecBase2 &value) { - MStatus status; - - MObject vec2_object; - if (!get_maya_attribute(node, attribute_name, vec2_object)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have a vec2 object value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - - MFnNumericData data(vec2_object, &status); - if (!status) { - maya_cat.warning() - << "Attribute " << attribute_name << " is of type " - << vec2_object.apiTypeStr() << ", not a NumericData.\n"; - return false; - } - - status = data.getData(value[0], value[1]); - if (!status) { - maya_cat.warning() - << "Unable to extract 2 floats from " << attribute_name - << ", of type " << vec2_object.apiTypeStr() << "\n"; - } - - return true; -} - -/** - * Extracts the named three-component vector from the MObject. - */ -bool -get_vec3_attribute(MObject &node, const string &attribute_name, - LVecBase3 &value) { - MStatus status; - - MObject vec3_object; - if (!get_maya_attribute(node, attribute_name, vec3_object)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have a vec3 object value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - - MFnNumericData data(vec3_object, &status); - if (!status) { - maya_cat.warning() - << "Attribute " << attribute_name << " is of type " - << vec3_object.apiTypeStr() << ", not a NumericData.\n"; - return false; - } - - status = data.getData(value[0], value[1], value[2]); - if (!status) { - maya_cat.warning() - << "Unable to extract 3 floats from " << attribute_name - << ", of type " << vec3_object.apiTypeStr() << "\n"; - } - - return true; -} - -/** - * Extracts the named two-component vector from the MObject. - */ -bool -get_vec2d_attribute(MObject &node, const string &attribute_name, - LVecBase2d &value) { - MStatus status; - - MObject vec2d_object; - if (!get_maya_attribute(node, attribute_name, vec2d_object)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have a vec2d object value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - - MFnNumericData data(vec2d_object, &status); - if (!status) { - maya_cat.warning() - << "Attribute " << attribute_name << " is of type " - << vec2d_object.apiTypeStr() << ", not a NumericData.\n"; - return false; - } - - status = data.getData(value[0], value[1]); - if (!status) { - maya_cat.warning() - << "Unable to extract 2 doubles from " << attribute_name - << ", of type " << vec2d_object.apiTypeStr() << "\n"; - } - - return true; -} - -/** - * Extracts the named three-component vector from the MObject. - */ -bool -get_vec3d_attribute(MObject &node, const string &attribute_name, - LVecBase3d &value) { - MStatus status; - - MObject vec3d_object; - if (!get_maya_attribute(node, attribute_name, vec3d_object)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have a vec3d object value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - - MFnNumericData data(vec3d_object, &status); - if (!status) { - maya_cat.warning() - << "Attribute " << attribute_name << " is of type " - << vec3d_object.apiTypeStr() << ", not a NumericData.\n"; - return false; - } - - status = data.getData(value[0], value[1], value[2]); - if (!status) { - maya_cat.warning() - << "Unable to extract 3 doubles from " << attribute_name - << ", of type " << vec3d_object.apiTypeStr() << "\n"; - } - - return true; -} - -/** - * Extracts the named 4x4 matrix from the MObject. - */ -bool -get_mat4d_attribute(MObject &node, const string &attribute_name, - LMatrix4d &value) { - MStatus status; - MObject matrix; - if (!get_maya_attribute(node, attribute_name, matrix)) { - return false; - } - - MFnMatrixData matrix_data(matrix, &status); - if (!status) { - maya_cat.warning() - << "Attribute " << attribute_name << " is of type " - << node.apiTypeStr() << ", not a Matrix.\n"; - return false; - } - - const MMatrix &mat = matrix_data.matrix(); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - value(i, j) = mat(i, j); - } - } - return true; -} - -/** - * artists should be able to set arbitrary tags. Query all the attributes on - * this object and return the lists of attribute names that has "tag" prefix - */ -void -get_tag_attribute_names(MObject &node, pvector &tag_names) { - MStatus status; - MFnDependencyNode node_fn(node, &status); - if (!status) { - maya_cat.warning() - << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n"; - return; - } - - string name = node_fn.name().asChar(); - unsigned i; - - for (i = 0; i < node_fn.attributeCount(); i++) { - MObject attr = node_fn.attribute(i, &status); - if (status) { - MFnAttribute attrib(attr, &status); - if (status) { - string attribute_name = attrib.name().asChar(); - if (attribute_name.find("tag", 0) != string::npos) { - maya_cat.info() << ":" << name << ":" << " is tagged with <" - << attribute_name << ">" << endl; - tag_names.push_back(attribute_name); - } - } - } - } -} -/** - * Extracts the enum attribute from the MObject as a string value. - */ -bool -get_enum_attribute(MObject &node, const string &attribute_name, - string &value) { - MStatus status; - - MPlug plug; - if (!get_maya_plug(node, attribute_name.c_str(), plug)) { - return false; - } - - MObject attrib = plug.attribute(); - MFnEnumAttribute enum_attrib(attrib, &status); - if (!status) { - maya_cat.warning() - << "Not an enum attribute: " << attribute_name << "\n"; - return false; - } - - short index; - status = plug.getValue(index); - if (!status) { - maya_cat.warning() - << "Could not get numeric value of " << attribute_name << "\n"; - status.perror("MPlug::getValue(short)"); - return false; - } - - MString name = enum_attrib.fieldName(index, &status); - if (!status) { - maya_cat.warning() - << "Invalid value for " << attribute_name << ": " << index << "\n"; - status.perror("MFnEnumAttribute::fieldName()"); - return false; - } - - value = name.asChar(); - return true; -} - -/** - * Extracts the named string attribute from the MObject. - */ -bool -get_string_attribute(MObject &node, const string &attribute_name, - string &value) { - MStatus status; - - MObject string_object; - if (!get_maya_attribute(node, attribute_name, string_object)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have an string object value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - - MFnStringData data(string_object, &status); - if (!status) { - maya_cat.warning() - << "Attribute " << attribute_name << " is of type " - << string_object.apiTypeStr() << ", not a StringData.\n"; - return false; - } - - value = data.string().asChar(); - return true; -} - -/** - * Sets the named string attribute on the MObject. - */ -bool -set_string_attribute(MObject &node, const string &attribute_name, - const string &value) { - MStatus status; - - // First, we get the string_object, then we set its string. - MObject string_object; - if (!get_maya_attribute(node, attribute_name, string_object)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " does not have a string object value.\n"; - describe_maya_attribute(node, attribute_name); - return false; - } - - MFnStringData data(string_object, &status); - if (!status) { - maya_cat.warning() - << "Attribute " << attribute_name << " is of type " - << string_object.apiTypeStr() << ", not a StringData.\n"; - return false; - } - - MString mstring_value(value.data(), value.length()); - status = data.set(mstring_value); - if (!status) { - status.perror(attribute_name.c_str()); - return false; - } - - // And it appears we now need to set the string object back. - if (!set_maya_attribute(node, attribute_name, string_object)) { - maya_cat.warning() - << "Attribute " << attribute_name - << " suddenly does not have a string object value.\n"; - return false; - } - - return true; -} - -/** - * Extracts the children of this attribute from the MObject. test for now - */ -bool -describe_compound_attribute(MObject &node) { - MStatus status; - - MFnCompoundAttribute comp_attr(node, &status); - - maya_cat.info() << "comp_attr has:" << comp_attr.numChildren() << " children" << endl; - for (size_t i = 0; i < comp_attr.numChildren(); i++) { - MObject child = comp_attr.child(i, &status); - if (child.apiType() == MFn::kAttribute3Float){ - /* - LRGBColor color; - if (get_vec3_attribute(child, "color", color)) { - maya_cat.info() << "color: " << color << endl; - } - */ - } - else if (child.apiType() == MFn::kNumericAttribute) { - MFnNumericAttribute numeric(child, &status); - if (status) { - switch(numeric.unitType()) { - case MFnNumericData::kFloat : - PN_stdfloat alpha; - status = numeric.getDefault(alpha); - maya_cat.info() << "found a float :" << alpha << endl; - break; - case MFnNumericData::kBoolean : - bool v; - status = numeric.getDefault(v); - maya_cat.info() << "found a bool :" << v << endl; - default: - maya_cat.info() << numeric.unitType() << endl; - } - } - } - else if (child.apiType() == MFn::kEnumAttribute) { - MFnEnumAttribute enu(child, &status); - if (status) { - MString blah; - status = enu.getDefault(blah); - maya_cat.info() << "found a string :" << blah.asChar() << endl; - MPlug plug = MPlug(node, child); - maya_cat.info() << "plug name" << plug.name().asChar() << endl; - } - } - } - return true; -} - -/** - * Writes some warning output about the indicated Maya attribute. - */ -void -describe_maya_attribute(MObject &node, const string &attribute_name) { - MStatus status; - MFnDependencyNode node_fn(node, &status); - if (!status) { - maya_cat.warning() - << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n"; - return; - } - - MObject attr = node_fn.attribute(attribute_name.c_str(), &status); - if (!status) { - maya_cat.warning() - << "Object " << node_fn.name().asChar() << " does not support attribute " - << attribute_name << "\n"; - return; - } - - maya_cat.warning() - << "Attribute " << attribute_name << " on object " - << node_fn.name().asChar() << " has type " << attr.apiTypeStr() << "\n"; -} - -string -string_mfndata_type(MFnData::Type type) { - switch (type) { - case MFnData::kInvalid: - return "kInvalid"; - - case MFnData::kNumeric: - return "kNumeric"; - - case MFnData::kPlugin: - return "kPlugin"; - - case MFnData::kPluginGeometry: - return "kPluginGeometry"; - - case MFnData::kString: - return "kString"; - - case MFnData::kMatrix: - return "kMatrix"; - - case MFnData::kStringArray: - return "kStringArray"; - - case MFnData::kDoubleArray: - return "kDoubleArray"; - - case MFnData::kIntArray: - return "kIntArray"; - - case MFnData::kPointArray: - return "kPointArray"; - - case MFnData::kVectorArray: - return "kVectorArray"; - - case MFnData::kComponentList: - return "kComponentList"; - - case MFnData::kMesh: - return "kMesh"; - - case MFnData::kLattice: - return "kLattice"; - - case MFnData::kNurbsCurve: - return "kNurbsCurve"; - - case MFnData::kNurbsSurface: - return "kNurbsSurface"; - - case MFnData::kSphere: - return "kSphere"; - - case MFnData::kDynArrayAttrs: - return "kDynArrayAttrs"; - - case MFnData::kDynSweptGeometry: - return "kDynSweptGeometry"; - - case MFnData::kSubdSurface: - return "kSubdSurface"; - - case MFnData::kLast: - default: - break; - } - - return "**invalid**"; -} - -/** - * Writes some info output showing all the attributes on the given dependency - * node. Primarily useful during development, to figure out where the heck - * Maya hides some of the connected properties. - */ -void -list_maya_attributes(MObject &node) { - MStatus status; - MFnDependencyNode node_fn(node, &status); - if (!status) { - maya_cat.warning() - << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n"; - return; - } - - string name = node_fn.name().asChar(); - unsigned i; - - MPlugArray connections; - status = node_fn.getConnections(connections); - if (!status) { - status.perror("MFnDependencyNode::getConnections"); - - } else { - maya_cat.info() - << name << " has " << connections.length() << " connections.\n"; - for (i = 0; i < connections.length(); i++) { - MPlug plug = connections[i]; - - maya_cat.info(false) - << " " << i << ". " << plug.name().asChar() << ", " - << plug.attribute().apiTypeStr() << ", " - << plug.node().apiTypeStr(); - if (plug.attribute().apiType() == MFn::kCompoundAttribute) { - // maya_cat.info() << plug.info(); - // describe_compound_attribute(plug.attribute()); - } - if (plug.isConnected()) { - maya_cat.info(false) - << " (*)"; - } - maya_cat.info(false) - << "\n"; - } - } - - maya_cat.info() - << name << " has " << node_fn.attributeCount() << " attributes.\n"; - for (i = 0; i < node_fn.attributeCount(); i++) { - MObject attr = node_fn.attribute(i, &status); - if (status) { - MFnTypedAttribute typed_attrib(attr, &status); - if (status) { - // It's a typed attrib. - maya_cat.info(false) - << " " << i << ". " << typed_attrib.name().asChar() - << " [" << attr.apiTypeStr() << ", " - << string_mfndata_type(typed_attrib.attrType()) << "]\n"; - } else { - MFnAttribute attrib(attr, &status); - if (status) { - // It's a generic attrib. - maya_cat.info(false) - << " " << i << ". " << attrib.name().asChar() - << " [" << attr.apiTypeStr() << "]\n"; - } else { - // Don't know what it is. - maya_cat.info(false) - << " " << i << ". [" << attr.apiTypeStr() << "]\n"; - } - } - } - } -} diff --git a/pandatool/src/maya/maya_funcs.h b/pandatool/src/maya/maya_funcs.h deleted file mode 100644 index ad0a7210b34..00000000000 --- a/pandatool/src/maya/maya_funcs.h +++ /dev/null @@ -1,118 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file maya_funcs.h - * @author drose - * @date 2000-02-16 - */ - -#ifndef MAYA_FUNCS_H -#define MAYA_FUNCS_H - -#include "pandatoolbase.h" -#include "luse.h" -#include "config_maya.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - - -bool -get_maya_plug(MObject &node, const std::string &attribute_name, MPlug &plug); - -bool -is_connected(MObject &node, const std::string &attribute_name); - -template -bool -get_maya_attribute(MObject &node, const std::string &attribute_name, - ValueType &value); - -template -bool -set_maya_attribute(MObject &node, const std::string &attribute_name, - ValueType &value); - -bool -has_attribute(MObject &node, const std::string &attribute_name); - -bool -remove_attribute(MObject &node, const std::string &attribute_name); - -bool -get_bool_attribute(MObject &node, const std::string &attribute_name, - bool &value); - -bool -get_angle_attribute(MObject &node, const std::string &attribute_name, - double &value); - -bool -get_vec2_attribute(MObject &node, const std::string &attribute_name, - LVecBase2 &value); - -bool -get_vec3_attribute(MObject &node, const std::string &attribute_name, - LVecBase3 &value); - -bool -get_vec2d_attribute(MObject &node, const std::string &attribute_name, - LVecBase2d &value); - -bool -get_vec3d_attribute(MObject &node, const std::string &attribute_name, - LVecBase3d &value); - -bool -get_mat4d_attribute(MObject &node, const std::string &attribute_name, - LMatrix4d &value); - -void -get_tag_attribute_names(MObject &node, pvector &tag_names); - -bool -get_enum_attribute(MObject &node, const std::string &attribute_name, - std::string &value); - -bool -get_string_attribute(MObject &node, const std::string &attribute_name, - std::string &value); - -bool -set_string_attribute(MObject &node, const std::string &attribute_name, - const std::string &value); - -void -describe_maya_attribute(MObject &node, const std::string &attribute_name); - -bool -describe_compound_attribute(MObject &node); - -std::string -string_mfndata_type(MFnData::Type type); - -void -list_maya_attributes(MObject &node); - -// Also, we must define some output functions for Maya objects, since we can't -// use those built into Maya (which forward-defines the ostream type -// incorrectly). -INLINE std::ostream &operator << (std::ostream &out, const MString &str); -INLINE std::ostream &operator << (std::ostream &out, const MVector &vec); - -#include "maya_funcs.I" -#include "maya_funcs.T" - -#endif diff --git a/pandatool/src/maya/p3maya_composite1.cxx b/pandatool/src/maya/p3maya_composite1.cxx deleted file mode 100644 index 6d952402b65..00000000000 --- a/pandatool/src/maya/p3maya_composite1.cxx +++ /dev/null @@ -1,6 +0,0 @@ -#include "config_maya.cxx" -#include "mayaApi.cxx" -#include "mayaShader.cxx" -#include "mayaShaderColorDef.cxx" -#include "mayaShaders.cxx" -#include "maya_funcs.cxx" diff --git a/pandatool/src/maya/post_maya_include.h b/pandatool/src/maya/post_maya_include.h deleted file mode 100644 index 34e7152b63c..00000000000 --- a/pandatool/src/maya/post_maya_include.h +++ /dev/null @@ -1,15 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file post_maya_include.h - * @author drose - * @date 2002-04-11 - */ - -// This header file works in conjunction with pre_maya_include.h; it cleans up -// some of the definitions that it left open. diff --git a/pandatool/src/maya/pre_maya_include.h b/pandatool/src/maya/pre_maya_include.h deleted file mode 100644 index 85442c1e7be..00000000000 --- a/pandatool/src/maya/pre_maya_include.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file pre_maya_include.h - * @author drose - * @date 2002-04-11 - */ - -// This header file defines a few things that are necessary to define before -// including any Maya headers, just to work around some of Maya's assumptions -// about the compiler. It must not try to protect itself from multiple -// inclusion with #ifdef .. #endif, since it must be used each time it is -// included. - -// Maya 2008 will declare some VS2005-specific hacks unless we define this. -#if defined(_MSC_VER) && _MSC_VER < 1400 -#define MLIBRARY_DONTUSE_MFC_MANIFEST -#endif - -// Maya will try to typedef bool unless this symbol is defined. -#ifndef _BOOL -#define _BOOL 1 -#endif - -// In Maya 5.0, the headers seem to provide the manifest REQUIRE_IOSTREAM, -// which forces it to use the new headers instead of the old -// headers. It also says this is for Linux only, but it seems to -// work just fine on Windows, obviating the need for sneaky #defines in this -// and in post_maya_include.h. -#ifdef PHAVE_IOSTREAM -#define REQUIRE_IOSTREAM -#endif // PHAVE_IOSTREAM - -#ifdef __MACH__ -#define OSMac_ 1 -// This defines MAYA_API_VERSION -#include -#if MAYA_API_VERSION < 201600 -#include -#endif -#else -// This defines MAYA_API_VERSION -#include -#endif - -#if MAYA_API_VERSION >= 20180000 -#include -#else -class MObject; -class MDagPath; -class MFloatArray; -class MFnDagNode; -class MFnMesh; -class MFnNurbsCurve; -class MFnNurbsSurface; -class MPlug; -class MPointArray; -#endif diff --git a/pandatool/src/mayaegg/config_mayaegg.cxx b/pandatool/src/mayaegg/config_mayaegg.cxx deleted file mode 100644 index 396af693441..00000000000 --- a/pandatool/src/mayaegg/config_mayaegg.cxx +++ /dev/null @@ -1,64 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_mayaegg.cxx - * @author drose - * @date 2002-04-15 - */ - -#include "config_mayaegg.h" -#include "mayaEggGroupUserData.h" -#include "mayaNodeDesc.h" -#include "mayaBlendDesc.h" -#include "configVariableBool.h" - -#include "dconfig.h" - -Configure(config_mayaegg); -NotifyCategoryDef(mayaegg, ":maya"); - -ConfigureFn(config_mayaegg) { - init_libmayaegg(); -} - -// These control the default behavior of the mayaegg converter, but not -// necessarily the default behavior of the maya2egg command-line tool (which -// has its own defaults). - -// Should we respect the Maya double-sided flag (true) or ignore it and assume -// everything is single-sided (false)? -bool maya_default_double_sided; - -// Should we apply vertex color even when a texture is applied (true) or only -// when no texture is applied or the vertex-color egg flag is set (false)? -bool maya_default_vertex_color; - -/** - * Initializes the library. This must be called at least once before any of - * the functions or classes in this library can be used. Normally it will be - * called by the static initializers and need not be called explicitly, but - * special cases exist. - */ -void -init_libmayaegg() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - - MayaEggGroupUserData::init_type(); - MayaNodeDesc::init_type(); - MayaBlendDesc::init_type(); - - // For some reason, static init is not reliably running when this is loaded - // as a plug-in of a plug-in. Initialize these explicitly here. - maya_default_double_sided = ConfigVariableBool("maya-default-double-sided", false).get_value(); - maya_default_vertex_color = ConfigVariableBool("maya-default-vertex-color", true).get_value(); - -} diff --git a/pandatool/src/mayaegg/config_mayaegg.h b/pandatool/src/mayaegg/config_mayaegg.h deleted file mode 100644 index ede177ab26a..00000000000 --- a/pandatool/src/mayaegg/config_mayaegg.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_mayaegg.h - * @author drose - * @date 2002-04-15 - */ - -#ifndef CONFIG_MAYAEGG_H -#define CONFIG_MAYAEGG_H - -#include "pandatoolbase.h" -#include "notifyCategoryProxy.h" - -NotifyCategoryDeclNoExport(mayaegg); - -extern bool maya_default_double_sided; -extern bool maya_default_vertex_color; - -extern void init_libmayaegg(); - -#endif diff --git a/pandatool/src/mayaegg/mayaBlendDesc.cxx b/pandatool/src/mayaegg/mayaBlendDesc.cxx deleted file mode 100644 index b396ed86b6e..00000000000 --- a/pandatool/src/mayaegg/mayaBlendDesc.cxx +++ /dev/null @@ -1,69 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaBlendDesc.cxx - * @author drose - * @date 2004-02-10 - */ - -#include "mayaBlendDesc.h" -#include "config_mayaegg.h" - -TypeHandle MayaBlendDesc::_type_handle; - -/** - * - */ -MayaBlendDesc:: -MayaBlendDesc(MFnBlendShapeDeformer &deformer, int weight_index) : - _deformer(deformer.object()), - _weight_index(weight_index) -{ - std::ostringstream strm; - strm << _deformer.name().asChar() << "." << _weight_index; - set_name(strm.str()); - - _anim = nullptr; -} - -/** - * - */ -MayaBlendDesc:: -~MayaBlendDesc() { -} - -/** - * Moves the Maya slider associated with this blend shape to the indicated - * value. This will move all the affected vertices. - */ -void MayaBlendDesc:: -set_slider(PN_stdfloat value) { - MStatus status = _deformer.setWeight(_weight_index, value); - if (!status) { - mayaegg_cat.warning() - << "Unable to set slider " << get_name() << "\n"; - } -} - -/** - * Returns the current position of the Maya slider associated with this blend - * shape. - */ -PN_stdfloat MayaBlendDesc:: -get_slider() const { - return _deformer.weight(_weight_index); -} - -/** - * Clears the egg pointers from this blend desc. - */ -void MayaBlendDesc:: -clear_egg() { - _anim = nullptr; -} diff --git a/pandatool/src/mayaegg/mayaBlendDesc.h b/pandatool/src/mayaegg/mayaBlendDesc.h deleted file mode 100644 index 3be9183a828..00000000000 --- a/pandatool/src/mayaegg/mayaBlendDesc.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaBlendDesc.h - * @author drose - * @date 2004-02-10 - */ - -#ifndef MAYABLENDDESC_H -#define MAYABLENDDESC_H - -#include "pandatoolbase.h" - -#include "referenceCount.h" -#include "pointerTo.h" -#include "namable.h" - -#include "pre_maya_include.h" -#include -#include -#include "post_maya_include.h" - -class EggTable; -class EggSAnimData; - -/** - * A handle to a Maya blend shape description. This is just one target of a - * Maya BlendShape object, and thus corresponds more or less one-to-one with a - * single Egg morph target. (We don't attempt to support Maya's chained - * target shapes here; should we need to later, it would mean breaking each of - * those target shapes on the one continuous Maya slider into a separate - * MayaBlendDesc object, and synthesizing the egg slider values - * appropriately.) - */ -class MayaBlendDesc : public ReferenceCount, public Namable { -public: - MayaBlendDesc(MFnBlendShapeDeformer &deformer, int weight_index); - ~MayaBlendDesc(); - - void set_slider(PN_stdfloat value); - PN_stdfloat get_slider() const; - -private: - void clear_egg(); - - MFnBlendShapeDeformer _deformer; - int _weight_index; - - EggSAnimData *_anim; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - ReferenceCount::init_type(); - Namable::init_type(); - register_type(_type_handle, "MayaBlendDesc", - ReferenceCount::get_class_type(), - Namable::get_class_type()); - } - -private: - static TypeHandle _type_handle; - - friend class MayaNodeTree; -}; - -#endif diff --git a/pandatool/src/mayaegg/mayaEggGroupUserData.I b/pandatool/src/mayaegg/mayaEggGroupUserData.I deleted file mode 100644 index d3e6061e73d..00000000000 --- a/pandatool/src/mayaegg/mayaEggGroupUserData.I +++ /dev/null @@ -1,44 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaEggGroupUserData.I - * @author drose - * @date 2003-06-03 - */ - -/** - * - */ -INLINE MayaEggGroupUserData:: -MayaEggGroupUserData() { - _vertex_color = false; - _double_sided = false; -} - - -/** - * - */ -INLINE MayaEggGroupUserData:: -MayaEggGroupUserData(const MayaEggGroupUserData ©) : - EggUserData(copy), - _vertex_color(copy._vertex_color), - _double_sided(copy._double_sided) -{ -} - - -/** - * - */ -INLINE void MayaEggGroupUserData:: -operator = (const MayaEggGroupUserData ©) { - EggUserData::operator = (copy); - _vertex_color = copy._vertex_color; - _double_sided = copy._double_sided; -} diff --git a/pandatool/src/mayaegg/mayaEggGroupUserData.cxx b/pandatool/src/mayaegg/mayaEggGroupUserData.cxx deleted file mode 100644 index 47fd08227fd..00000000000 --- a/pandatool/src/mayaegg/mayaEggGroupUserData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaEggGroupUserData.cxx - * @author drose - * @date 2003-06-03 - */ - -#include "mayaEggGroupUserData.h" - -TypeHandle MayaEggGroupUserData::_type_handle; diff --git a/pandatool/src/mayaegg/mayaEggGroupUserData.h b/pandatool/src/mayaegg/mayaEggGroupUserData.h deleted file mode 100644 index 46b2d2ba790..00000000000 --- a/pandatool/src/mayaegg/mayaEggGroupUserData.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaEggGroupUserData.h - * @author drose - * @date 2003-06-03 - */ - -#ifndef MAYAEGGGROUPUSERDATA_H -#define MAYAEGGGROUPUSERDATA_H - -#include "pandatoolbase.h" -#include "eggUserData.h" - -/** - * This class contains extra user data which is piggybacked onto EggGroup - * objects for the purpose of the maya converter. - */ -class MayaEggGroupUserData : public EggUserData { -public: - INLINE MayaEggGroupUserData(); - INLINE MayaEggGroupUserData(const MayaEggGroupUserData ©); - INLINE void operator = (const MayaEggGroupUserData ©); - - bool _vertex_color; - bool _double_sided; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - EggUserData::init_type(); - register_type(_type_handle, "MayaEggGroupUserData", - EggUserData::get_class_type()); - } - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - -private: - static TypeHandle _type_handle; -}; - -#include "mayaEggGroupUserData.I" - -#endif diff --git a/pandatool/src/mayaegg/mayaEggLoader.cxx b/pandatool/src/mayaegg/mayaEggLoader.cxx deleted file mode 100644 index 200154bdc53..00000000000 --- a/pandatool/src/mayaegg/mayaEggLoader.cxx +++ /dev/null @@ -1,2209 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaEggLoader.cxx - * @author jyelon - * @date 2005-07-20 - * - * This file contains the code for class MayaEggLoader. This class - * does the actual work of copying an EggData tree into the maya scene. - */ - -#include "pandatoolbase.h" -#include "notifyCategoryProxy.h" - -#include "eggBin.h" -#include "eggData.h" -#include "eggTable.h" -#include "eggVertex.h" -#include "eggPolygon.h" -#include "eggComment.h" -#include "eggXfmSAnim.h" -#include "eggSAnimData.h" -#include "eggPrimitive.h" -#include "eggGroupNode.h" -#include "eggVertexPool.h" -#include "eggPolysetMaker.h" -#include "eggNurbsSurface.h" -#include "texture.h" -#include "texturePool.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -#include "mayaEggLoader.h" - -using std::cerr; -using std::endl; -using std::ostringstream; -using std::string; -using std::vector; - -class MayaEggGroup; -class MayaEggGeom; -class MayaEggMesh; -class MayaEggJoint; -class MayaEggTex; -class MayaAnim; -class MayaEggNurbsSurface; - -NotifyCategoryDeclNoExport(mayaloader); -NotifyCategoryDef(mayaloader, ""); - -class MayaEggLoader -{ -public: - bool ConvertEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals); - bool ConvertEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals); - - -public: - void TraverseEggNode(EggNode *node, EggGroup *context, string delim); - MayaEggMesh *GetMesh(EggVertexPool *pool, EggGroup *parent); - MayaEggJoint *FindJoint(EggGroup *joint); - MayaEggJoint *MakeJoint(EggGroup *joint, EggGroup *context); - MayaEggGroup *FindGroup(EggGroup *group); - MayaEggGroup *MakeGroup(EggGroup *group, EggGroup *context); - MayaEggTex *GetTex(EggTexture *etex); - void CreateSkinCluster(MayaEggGeom *M); - - MayaAnim *GetAnim(EggXfmSAnim *pool); - MObject GetDependencyNode(string givenName); - - MayaEggNurbsSurface *GetSurface(EggVertexPool *pool, EggGroup *parent); - - typedef phash_map MeshTable; - typedef phash_map AnimTable; - typedef phash_map JointTable; - typedef phash_map GroupTable; - typedef phash_map TexTable; - typedef phash_map SurfaceTable; - - MeshTable _mesh_tab; - AnimTable _anim_tab; - JointTable _joint_tab; - GroupTable _group_tab; - TexTable _tex_tab; - SurfaceTable _surface_tab; - - vector _joint_list; - - int _start_frame; - int _end_frame; - int _frame_rate; - MTime::Unit _timeUnit; - - void ParseFrameInfo(string comment); - void PrintData(MayaEggMesh *mesh); - -private: - int _unnamed_idx; - MSelectionList _collision_nodes; -}; - -MPoint MakeMPoint(const LVector3d &vec) -{ - return MPoint(vec[0], vec[1], vec[2]); -} - -MFloatPoint MakeMayaPoint(const LVector3d &vec) -{ - return MFloatPoint(vec[0], vec[1], vec[2]); -} - -MVector MakeMayaVector(const LVector3d &vec) -{ - return MVector(vec[0], vec[1], vec[2]); -} - -MColor MakeMayaColor(const LColor &vec) -{ - return MColor(vec[0], vec[1], vec[2], vec[3]); -} - -// [gjeon] to create enum attribute, fieldNames is a stringArray of enum -// names, and filedIndex is the default index value -MStatus create_enum_attribute(MObject &node, MString fullName, MString briefName, - MStringArray fieldNames, unsigned fieldIndex) { - MStatus stat; - - MFnDependencyNode fnDN( node, &stat ); - if ( MS::kSuccess != stat ) { - mayaloader_cat.error() - << "Could not create MFnDependencyNode" << "\n"; - return stat; - } - - MFnEnumAttribute fnAttr; - MObject newAttr = fnAttr.create( fullName, briefName, - 0, &stat ); - if ( MS::kSuccess != stat ) { - mayaloader_cat.error() - << "Could not create new enum attribute " << fullName.asChar() << "\n"; - return stat; - } - for (unsigned i = 0; i < fieldNames.length(); i++){ - fnAttr.addField(fieldNames[i], i); - } - - stat = fnAttr.setDefault(fieldIndex); - if ( MS::kSuccess != stat ) { - mayaloader_cat.error() - << "Could not set value for enum attribute " << fullName.asChar() << "\n"; - return stat; - } - - fnAttr.setKeyable( true ); - fnAttr.setReadable( true ); - fnAttr.setWritable( true ); - fnAttr.setStorable( true ); - - // Now add the new attribute to this dependency node - stat = fnDN.addAttribute(newAttr, MFnDependencyNode::kLocalDynamicAttr); - if ( MS::kSuccess != stat ) { - mayaloader_cat.error() - << "Could not add new enum attribute " << fullName.asChar() << "\n"; - return stat; - } - - return stat; -} - -// MayaEggTex - -class MayaEggTex -{ -public: - string _name; - string _path; - MObject _file_texture; - MObject _shader; - MObject _shading_group; - - MFnSingleIndexedComponent _component; - void AssignNames(void); -}; - -void MayaEggTex::AssignNames(void) -{ - if (_name == "") { - return; - } - MFnDependencyNode shader(_shader); - MFnDependencyNode sgroup(_shading_group); - MFnDependencyNode filetex(_file_texture); - shader.setName(MString(_name.c_str())+"Shader"); - sgroup.setName(MString(_name.c_str())); - if (_file_texture != MObject::kNullObj) { - filetex.setName(MString(_name.c_str())+"File"); - } -} - -MayaEggTex *MayaEggLoader::GetTex(EggTexture* etex) -{ - string name = ""; - string fn = ""; - if (etex != nullptr) { - name = etex->get_name(); - fn = etex->get_fullpath().to_os_specific(); - } - - if (_tex_tab.count(fn)) { - return _tex_tab[fn]; - } - - MStatus status; - MFnLambertShader shader; - MFnDependencyNode filetex; - MFnSet sgroup; - MPlugArray oldplugs; - MDGModifier dgmod; - - /* - if (fn=="") { - MSelectionList selection; - MObject initGroup; - selection.clear(); - MGlobal::getSelectionListByName("initialShadingGroup",selection); - selection.getDependNode(0, initGroup); - sgroup.setObject(initGroup); - } else { - */ - if (1) { - shader.create(true,&status); - MColor firstColor(1.0,1.0,1.0,1.0); - status = shader.setColor(firstColor); - if (status != MStatus::kSuccess) { - mayaloader_cat.error() << "setColor failed on LambertShader\n"; - status.perror("shader setColor failed!"); - } - sgroup.create(MSelectionList(), MFnSet::kRenderableOnly, &status); - MPlug surfplug = sgroup.findPlug("surfaceShader"); - if (surfplug.connectedTo(oldplugs,true,false)) { - for (unsigned int i=0; iget_fullpath(), 0, false, options); - if (((tex != nullptr) && (tex->get_num_components() == 4)) - || (etex->get_format() == EggTexture::F_alpha) - || (etex->get_format() == EggTexture::F_luminance_alpha)) - dgmod.connect(filetex.findPlug("outTransparency"),shader.findPlug("transparency")); - } - status = dgmod.doIt(); - if (status != MStatus::kSuccess) { - status.perror("DGMod doIt"); - } - } - - MayaEggTex *res = new MayaEggTex; - res->_name = name; - res->_path = fn; - res->_file_texture = filetex.object(); - res->_shader = shader.object(); - res->_shading_group = sgroup.object(); - - _tex_tab[fn] = res; - return res; -} - -// MayaEggGroup - -class MayaEggGroup -{ -public: - string _name; - MObject _parent; - MObject _group; - - bool _addedEggFlag; -}; - -MayaEggGroup *MayaEggLoader::MakeGroup(EggGroup *group, EggGroup *context) -{ - MStatus status; - MayaEggGroup *pg = FindGroup(context); - MayaEggGroup *result = new MayaEggGroup; - MFnDagNode dgn; - - MObject parent = MObject::kNullObj; - if (pg) { - parent = pg->_group; - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "parent (group) :" << ((MFnDagNode)parent).name().asChar() << endl; - } - } - - result->_name = group->get_name(); - result->_group = dgn.create("transform", MString(result->_name.c_str()), parent, &status); - result->_addedEggFlag = false; - - if (group->get_cs_type() != EggGroup::CST_none) - _collision_nodes.add(result->_group, true); - - if (group->has_transform3d()) { - LMatrix4d tMat = group->get_transform3d(); - double matData[4][4] = {{tMat.get_cell(0,0), tMat.get_cell(0,1), tMat.get_cell(0,2), tMat.get_cell(0,3)}, - {tMat.get_cell(1,0), tMat.get_cell(1,1), tMat.get_cell(1,2), tMat.get_cell(1,3)}, - {tMat.get_cell(2,0), tMat.get_cell(2,1), tMat.get_cell(2,2), tMat.get_cell(2,3)}, - {tMat.get_cell(3,0), tMat.get_cell(3,1), tMat.get_cell(3,2), tMat.get_cell(3,3)}}; - MMatrix mat(matData); - - MTransformationMatrix matrix = MTransformationMatrix(mat); - MFnTransform tFn(result->_group, &status); - if (status != MStatus::kSuccess) { - status.perror("MFnTransformNode:create failed!"); - } else { - tFn.set(matrix); - } - } - - if (status != MStatus::kSuccess) { - status.perror("MFnDagNode:create failed!"); - } - - if ((pg) && (pg->_addedEggFlag == false)){ - // [gjeon] to handle other flags - MStringArray eggFlags; - for (int i = 0; i < context->get_num_object_types(); i++) { - eggFlags.append(MString(context->get_object_type(i).c_str())); - } - - for (unsigned i = 0; i < eggFlags.length(); i++) { - MString attrName = "eggObjectTypes"; - attrName += (int)(i + 1); - status = create_enum_attribute(parent, attrName, attrName, eggFlags, i); - if (status != MStatus::kSuccess) { - status.perror("create_enum_attribute failed!"); - } - } - pg->_addedEggFlag = true; - } - - _group_tab[group] = result; - return result; -} - -MayaEggGroup *MayaEggLoader::FindGroup(EggGroup *group) -{ - if (group==0) { - return 0; - } - return _group_tab[group]; -} - -// MayaEggJoint - -class MayaEggJoint -{ -public: - LMatrix4d _trans; - LVector3d _endpos; - LVector3d _perp; - double _thickness; - MObject _joint; - MMatrix _joint_abs; - MDagPath _joint_dag_path; - bool _inskin; - int _index; - EggGroup *_egg_joint; - EggGroup *_egg_parent; - MayaEggJoint *_parent; - vector _children; - -public: - void GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv); - LVector3d GetPos(void) { return _trans.get_row3(3); } - MayaEggJoint *ChooseBestChild(LVector3d dir); - void ChooseEndPos(double thickness); - void CreateMayaBone(MayaEggGroup *eggParent); - void AssignNames(void); -}; - -void MayaEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv) -{ - xv = _trans.get_row3(0); - yv = _trans.get_row3(1); - zv = _trans.get_row3(2); - xv.normalize(); - yv.normalize(); - zv = xv.cross(yv); - zv.normalize(); - yv = zv.cross(xv); -} - -void MayaEggJoint::AssignNames(void) -{ - string name = _egg_joint->get_name(); - MFnDependencyNode joint(_joint); - joint.setName(name.c_str()); - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "joint " << joint.name().asChar() << ": -> " << name << endl; - } -} - -MayaEggJoint *MayaEggLoader::FindJoint(EggGroup *joint) -{ - if (joint==nullptr) { - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "joint:" << joint->get_name() << " is null: " << endl; - } - return 0; - } - if (!joint->is_joint()) { - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "joint:" << joint->get_name() << " is not a joint: " << endl; - } - return 0; - } - return _joint_tab[joint]; -} - -MayaEggJoint *MayaEggLoader::MakeJoint(EggGroup *joint, EggGroup *context) -{ - MayaEggJoint *parent = FindJoint(context); - if (mayaloader_cat.is_debug()) { - string parent_name = ""; - if (parent) - parent_name = context->get_name(); - } - MayaEggJoint *result = new MayaEggJoint; - LMatrix4d t = joint->get_transform3d(); - if (parent) { - result->_trans = t * parent->_trans; - } else { - result->_trans = t; - } - result->_endpos = LVector3d(0,0,0); - result->_perp = LVector3d(0,0,0); - result->_thickness = 0.0; - result->_egg_joint = joint; - result->_egg_parent = context; - result->_parent = parent; - result->_joint = MObject::kNullObj; - result->_inskin = false; - result->_index = -1; - if (parent) { - parent->_children.push_back(result); - } - _joint_tab[joint] = result; - - // [gjeon] since _joint_tab is not always properly sorted - _joint_list.push_back(result); - - return result; -} - -MayaEggJoint *MayaEggJoint::ChooseBestChild(LVector3d dir) -{ - if (dir.length() < 0.001) { - return 0; - } - dir.normalize(); - double firstbest = -1000; - MayaEggJoint *firstchild = 0; - LVector3d firstpos = GetPos(); - double secondbest = 0; - for (unsigned int i=0; i<_children.size(); i++) { - MayaEggJoint *child = _children[i]; - LVector3d tryfwd = child->GetPos() - GetPos(); - if ((child->GetPos() != firstpos) && (tryfwd.length() > 0.001)) { - LVector3d trydir = tryfwd; - trydir.normalize(); - double quality = trydir.dot(dir); - if (quality > firstbest) { - secondbest = firstbest; - firstbest = quality; - firstpos = child->GetPos(); - firstchild = child; - } else if (quality > secondbest) { - secondbest = quality; - } - } - } - if (firstbest > secondbest + 0.1) { - return firstchild; - } - return 0; -} - -void MayaEggJoint::ChooseEndPos(double thickness) -{ - LVector3d parentpos(0,0,0); - LVector3d parentendpos(0,0,1); - if (_parent) { - parentpos = _parent->GetPos(); - parentendpos = _parent->_endpos; - } - LVector3d fwd = GetPos() - parentpos; - if (fwd.length() < 0.001) { - fwd = parentendpos - parentpos; - } - // mayaloader_cat.debug() << "fwd : " << fwd << endl; - fwd.normalize(); - MayaEggJoint *child = ChooseBestChild(fwd); - if (child == 0) { - _endpos = fwd * thickness * 0.8 + GetPos(); - _thickness = thickness * 0.8; - } else { - _endpos = child->GetPos(); - _thickness = (_endpos - GetPos()).length(); - if (_thickness > thickness) _thickness = thickness; - } - LVector3d orient = _endpos - GetPos(); - orient.normalize(); - LVector3d altaxis = orient.cross(LVector3d(0,-1,0)); - if (altaxis.length() < 0.001) { - altaxis = orient.cross(LVector3d(0,0,1)); - } - _perp = altaxis.cross(orient); - _perp.normalize(); -} - -void MayaEggJoint::CreateMayaBone(MayaEggGroup *eggParent) -{ - LVector3d rxv, ryv, rzv; - // GetRotation(rxv, ryv, rzv); [gjeon] I think we shouldn't need to use this - // GetRotation function here since this function removes scale information - // from the matrix. Let's just use the matrix directly. - rxv = _trans.get_row3(0); - ryv = _trans.get_row3(1); - rzv = _trans.get_row3(2); - - MFloatPoint xv(MakeMayaPoint(rxv)); - MFloatPoint yv(MakeMayaPoint(ryv)); - MFloatPoint zv(MakeMayaPoint(rzv)); - MFloatPoint pos(MakeMayaPoint(GetPos())); - MFloatPoint endpos(MakeMayaPoint(_endpos)); - MFloatPoint tzv(MakeMayaPoint(_perp)); - double m[4][4]; - m[0][0]=xv.x; m[0][1]=xv.y; m[0][2]=xv.z; m[0][3]=0; - m[1][0]=yv.x; m[1][1]=yv.y; m[1][2]=yv.z; m[1][3]=0; - m[2][0]=zv.x; m[2][1]=zv.y; m[2][2]=zv.z; m[2][3]=0; - m[3][0]=pos.x; m[3][1]=pos.y; m[3][2]=pos.z; m[3][3]=1; - MMatrix trans(m); - _joint_abs = trans; - if (_parent) { - trans = trans * _parent->_joint_abs.inverse(); - } - MTransformationMatrix mtm(trans); - - MFnIkJoint ikj; - if (_parent) { - ikj.create(_parent->_joint); - } - else { - if (eggParent) { - // must be part of a group that is not a joint - ikj.create(eggParent->_group); - } else { - ikj.create(); - } - } - ikj.set(mtm); - - _joint = ikj.object(); - ikj.getPath(_joint_dag_path); -} - - -// MayaEggGeom : base abstract class of MayaEggMesh and MayaEggNurbsSurface - -typedef std::pair MayaEggWeight; - -struct MayaEggVertex -{ - LVertexd _pos; - LNormald _normal; - LTexCoordd _uv; - vector _weights; - double _sumWeights; // [gjeon] to be used in normalizing weights - int _index; - int _external_index; // masad: use egg's index directly -}; - -struct MEV_Compare: public stl_hash_compare -{ - size_t operator()(const MayaEggVertex &key) const - { - return key._pos.add_hash(key._normal.get_hash()); - } - bool operator()(const MayaEggVertex &k1, const MayaEggVertex &k2) const - { - int n = k1._pos.compare_to(k2._pos); - if (n < 0) { - return true; - } - if (n > 0) { - return false; - } - n = k1._normal.compare_to(k2._normal); - if (n < 0) { - return true; - } - if (n > 0) { - return false; - } - n = k1._uv.compare_to(k2._uv); - if (n < 0) { - return true; - } - if (n > 0) { - return false; - } - n = k1._weights.size() - k2._weights.size(); - if (n < 0) { - return true; - } - if (n > 0) { - return false; - } - for (unsigned int i=0; i 0) { - return false; - } - EggGroup *g1 = k1._weights[i].second; - EggGroup *g2 = k2._weights[i].second; - if (g1 < g2) { - return true; - } - if (g1 > g2) { - return false; - } - } - n = k1._external_index - k2._external_index; - - if (n < 0) { - return true; - } - if (n > 0) { - return false; - } - - return false; - } -}; - -typedef phash_set VertTable; - -class MayaEggGeom -{ -public: - - EggVertexPool *_pool; - MObject _transNode; - MObject _shapeNode; - EggGroup *_parent; - MDagPath _shape_dag_path; - int _vert_count; - - string _name; - - MFloatPointArray _vertexArray; - MVectorArray _normalArray; - MColorArray _vertColorArray; - MIntArray _vertColorIndices; - MIntArray _vertNormalIndices; - - MStringArray _eggObjectTypes; - VertTable _vert_tab; - - bool _renameTrans; - - int GetVert(EggVertex *vert, EggGroup *context); - EggGroup *GetControlJoint(void); - - virtual void ConnectTextures(void) = 0; - void AssignNames(void); - void AddEggFlag(MString); -}; - -// [gjeon] moved from MayaEggMesh to MayaEggGeom -int MayaEggGeom::GetVert(EggVertex *vert, EggGroup *context) -{ - MayaEggVertex vtx; - vtx._sumWeights = 0.0; - - const LMatrix4d &xform = context->get_vertex_to_node(); - - vtx._pos = vert->get_pos3() * xform; - if (vert->has_normal()) { - vtx._normal = vert->get_normal() * xform; - } - if (vert->has_uv()) { - vtx._uv = vert->get_uv(); - } - vtx._index = 0; - vtx._external_index = vert->get_index()-1; - - EggVertex::GroupRef::const_iterator gri; - // double remaining_weight = 1.0; - for (gri = vert->gref_begin(); gri != vert->gref_end(); ++gri) { - EggGroup *egg_joint = (*gri); - double membership = egg_joint->get_vertex_membership(vert); - - if (membership < 0) - { - mayaloader_cat.warning() << "negative weight value " << membership << " is replaced with 0 on: " << context->get_name() << endl; - membership = 0.0; - } - // remaining_weight -= membership; - vtx._weights.push_back(MayaEggWeight(membership, egg_joint)); - vtx._sumWeights += membership; // [gjeon] to be used in normalizing weights - } - - if (vtx._weights.size()==0) { - if (context != 0) { - vtx._weights.push_back(MayaEggWeight(1.0, context)); - vtx._sumWeights = 1.0; // [gjeon] to be used in normalizing weights - } - // remaining_weight = 0.0; - }/* else { - // some soft models came up short of 1.0 on vertex membership add the - // remainder of the weight on first joint in the membership - if ((remaining_weight) > 0.01) { - gri = vert->gref_begin(); - EggGroup *egg_joint = (*gri); - double membership = egg_joint->get_vertex_membership(vert); - vtx._weights.push_back(MayaEggWeight(membership+remaining_weight, egg_joint)); - vtx._sumWeights += (membership + remaining_weight); - } - }*/ //[gjeon] we had better nomarlize weights than add remaining weight to first weight - - VertTable::const_iterator vti = _vert_tab.find(vtx); - if (vti != _vert_tab.end()) { - /* if ((remaining_weight) > 0.01) { - mayaloader_cat.warning() << "weight munged to 1.0 by " << remaining_weight << " on: " << context->get_name() << " idx:" << vti->_index << endl; - } */ - if (mayaloader_cat.is_spam()) { - ostringstream stream; - stream << "(" << vti->_pos << " " << vti->_normal << " " << vti->_uv << ")\n"; - stream << "[" << vtx._pos << " " << vtx._normal << " " << vtx._uv << "]\n"; - stream << "{" << vert->get_pos3() << " "; - if (vert->has_normal()) { - stream << vert->get_normal() << " "; - } - if (vert->has_uv()) { - stream << vert->get_uv(); - } - stream << "}"; - mayaloader_cat.spam() << "found a matching vertex: " << *vert << endl << stream.str() << endl; - } - return vti->_index; - } - - // _vert_count++; - vtx._index = _vert_count++; - /* - if ((remaining_weight) > 0.01) { - mayaloader_cat.warning() << "weight munged to 1.0 by " << remaining_weight << " on: " << context->get_name() << " idx:" << vtx._index << endl; - } */ - - _vertexArray.append(MakeMayaPoint(vtx._pos)); - if (vert->has_normal()) { - _normalArray.append(MakeMayaVector(vtx._normal)); - _vertNormalIndices.append(vtx._index); - } - if (vert->has_color()) { - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "found a vertex color\n"; - } - _vertColorArray.append(MakeMayaColor(vert->get_color())); - _vertColorIndices.append(vtx._index); - } - _vert_tab.insert(vtx); - return vtx._index; -} - -// [gjeon] moved from MayaEggMesh to MayaEggGeom -void MayaEggGeom::AssignNames(void) -{ - string name = _pool->get_name(); - size_t nsize = name.size(); - if (nsize > 6 && name.rfind(".verts") == (nsize - 6)) { - name.resize(nsize - 6); - } - if (nsize > 4 && name.rfind(".cvs") == (nsize - 4)) { - name.resize(nsize - 4); - } - - MFnDependencyNode dnshape(_shapeNode); - MFnDependencyNode dntrans(_transNode); - - if (_renameTrans) { - dntrans.setName(MString(name.c_str())); - } - - string shape_name = string(dntrans.name().asChar()); - string numbers ("0123456789"); - size_t found; - - found=shape_name.find_last_not_of(numbers); - if (found!=string::npos) - shape_name.insert(found+1, "Shape"); - else - shape_name.append("Shape"); - - dnshape.setName(MString(shape_name.c_str())); -} - -#define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1))) - -// [gjeon] moved from MayaEggMesh to MayaEggGeom -EggGroup *MayaEggGeom::GetControlJoint(void) -{ - EggGroup *result; - VertTable::const_iterator vert = _vert_tab.begin(); - if (vert == _vert_tab.end()) { - return 0; - } - switch (vert->_weights.size()) { - case 0: - for (++vert; vert != _vert_tab.end(); ++vert) { - if (vert->_weights.size() != 0) { - return CTRLJOINT_DEFORM; - } - } - return 0; - case 1: - result = vert->_weights[0].second; - for (++vert; vert != _vert_tab.end(); ++vert) { - if ((vert->_weights.size() != 1) || (vert->_weights[0].second != result)) { - return CTRLJOINT_DEFORM; - } - } - return result; - default: - return CTRLJOINT_DEFORM; - } -} - -void MayaEggGeom::AddEggFlag(MString fieldName) { - bool addNewFlag = true; - for (unsigned i = 0; i < _eggObjectTypes.length(); i++) { - if (_eggObjectTypes[i] == fieldName) { - addNewFlag = false; - break; - } - } - if (addNewFlag) { - _eggObjectTypes.append(fieldName); - } -} - -// MayaEggMesh -typedef phash_map TVertTable; -typedef phash_map CVertTable; - -class MayaEggMesh final : public MayaEggGeom -{ -public: - MColorArray _faceColorArray; - MIntArray _faceIndices; - MIntArray _polygonCounts; - MIntArray _polygonConnects; - MFloatArray _uarray; - MFloatArray _varray; - MIntArray _uvIds; - - - int _tvert_count; - int _cvert_count; - int _face_count; - vector _face_tex; - - TVertTable _tvert_tab; - CVertTable _cvert_tab; - - int GetTVert(const LTexCoordd &uv); - int GetCVert(const LColor &col); - int AddFace(unsigned numVertices, MIntArray mvertIndices, MIntArray mtvertIndices, MayaEggTex *tex); - - void ConnectTextures(void) override; -}; - -int MayaEggMesh::GetTVert(const LTexCoordd &uv) -{ - if (_tvert_tab.count(uv)) { - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "found uv coords idx: " << _tvert_tab[uv] << endl; - } - return _tvert_tab[uv]; - } - int idx = _tvert_count++; - _uarray.append(uv.get_x()); - _varray.append(uv.get_y()); - _tvert_tab[uv] = idx; - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "adding uv coords idx:" << idx << endl; - } - return idx; -} - -int MayaEggMesh::GetCVert(const LColor &col) -{ -/* - * if (_cvert_tab.count(col)) return _cvert_tab[col]; if (_cvert_count == - * _mesh->numCVerts) { int nsize = _cvert_count*2 + 100; - * _mesh->setNumVertCol(nsize, _cvert_count?TRUE:FALSE); } int idx = - * _cvert_count++; _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), - * col.get_z()); _cvert_tab[col] = idx; return idx; - */ - return 0; -} - -MayaEggMesh *MayaEggLoader::GetMesh(EggVertexPool *pool, EggGroup *parent) -{ - MayaEggMesh *result = _mesh_tab[parent]; - if (result == 0) { - result = new MayaEggMesh; - if (parent != nullptr) { - result->_name = parent->get_name(); - } - result->_pool = pool; - result->_parent = parent; - result->_vert_count = 0; - result->_tvert_count = 0; - result->_cvert_count = 0; - result->_face_count = 0; - result->_vertColorArray.clear(); - result->_vertNormalIndices.clear(); - result->_vertColorIndices.clear(); - result->_faceColorArray.clear(); - result->_faceIndices.clear(); - result->_eggObjectTypes.clear(); - result->_renameTrans = false; - _mesh_tab[parent] = result; - } - return result; -} - -int MayaEggMesh::AddFace(unsigned numVertices, MIntArray mvertIndices, MIntArray mtvertIndices, MayaEggTex *tex) -{ - int idx = _face_count++; - _polygonCounts.append(numVertices); - for (unsigned i = 0; i < mvertIndices.length(); i++) - { - _polygonConnects.append(mvertIndices[i]); - _uvIds.append(mtvertIndices[i]); - } - _face_tex.push_back(tex); - return idx; -} - -void MayaEggMesh::ConnectTextures(void) -{ - bool subtex = false; - for (int i=1; i<_face_count; i++) { - if (_face_tex[i] != _face_tex[0]) { - subtex = true; - } - } - if (!subtex) { - MFnSet sg(_face_tex[0]->_shading_group); - sg.addMember(_shapeNode); - return; - } - for (int i=0; i<_face_count; i++) { - MayaEggTex *tex = _face_tex[i]; - if (tex->_component.object()==MObject::kNullObj) { - tex->_component.create(MFn::kMeshPolygonComponent); - } - tex->_component.addElement(i); - } - for (int i=0; i<_face_count; i++) { - MayaEggTex *tex = _face_tex[i]; - if (tex->_component.object()!=MObject::kNullObj) { - MFnSet sg(tex->_shading_group); - sg.addMember(_shape_dag_path, tex->_component.object()); - tex->_component.setObject(MObject::kNullObj); - } - } -} - - -// MayaEggNurbsSurface -class MayaEggNurbsSurface : public MayaEggGeom -{ -public: - - - MPointArray _cvArray; - MDoubleArray _uKnotArray; - MDoubleArray _vKnotArray; - unsigned _uDegree; - unsigned _vDegree; - unsigned _uNumCvs; - unsigned _vNumCvs; - - MFnNurbsSurface::Form _uForm; - MFnNurbsSurface::Form _vForm; - - MayaEggTex *_tex; - - void ConnectTextures(void); - void PrintData(void); -}; - -MayaEggNurbsSurface *MayaEggLoader::GetSurface(EggVertexPool *pool, EggGroup *parent) -{ - MayaEggNurbsSurface *result = _surface_tab[parent]; - if (result == 0) { - result = new MayaEggNurbsSurface; - result->_pool = pool; - result->_parent = parent; - result->_name = parent->get_name(); - - result->_vert_count = 0; - result->_vertColorArray.clear(); - result->_vertNormalIndices.clear(); - result->_vertColorIndices.clear(); - - result->_cvArray.clear(); - result->_uKnotArray.clear(); - result->_vKnotArray.clear(); - - result->_uDegree = 0; - result->_vDegree = 0; - result->_uNumCvs = 0; - result->_vNumCvs = 0; - result->_uForm = MFnNurbsSurface::kClosed; - result->_vForm = MFnNurbsSurface::kClosed; - - result->_eggObjectTypes.clear(); - result->_renameTrans = false; - _surface_tab[parent] = result; - } - return result; -} - -void MayaEggNurbsSurface::ConnectTextures(void) -{ - // masad: since nurbs surfaces do not support vertex colors I am infusing - // the surface's first vertex color (if any) into the shader to achive the - // color. masad: check if there is any vertex color for this surface - MStatus status; - MColor firstColor(0.5,0.5,0.5,1.0); - if (_vertColorArray.length() > 0) { - firstColor = _vertColorArray[0]; - MFnLambertShader sh(_tex->_shader); - status = sh.setColor(firstColor); - if (status != MStatus::kSuccess) { - mayaloader_cat.error() << "setColor failed on " << _name; - status.perror("shader setColor failed!"); - } - } - MFnSet sg(_tex->_shading_group); - status = sg.addMember(_shapeNode); - if (status != MStatus::kSuccess) { - mayaloader_cat.error() << "addMember failed on " << _name; - status.perror("shader addMember failed!"); - } - return; -} - -void MayaEggNurbsSurface::PrintData(void) -{ - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "nurbsSurface : " << _name << endl; - - mayaloader_cat.debug() << "u_form : " << _uForm << endl; - mayaloader_cat.debug() << "v_form : " << _vForm << endl; - } - - /* - for (unsigned i = 0; i < _cvArray.length(); i++) - { - MPoint cv =_cvArray[i]; - mayaloader_cat.debug() << cv[0] << " " << cv[1] << " " << cv[2] << endl; - } - - for (unsigned i = 0; i < _uKnotArray.length(); i++) - { - mayaloader_cat.debug() << _uKnotArray[i] << endl; - } - - for (unsigned i = 0; i < _vKnotArray.length(); i++) - { - mayaloader_cat.debug() << _vKnotArray[i] << endl; - } - */ -} - -// MayaAnim: -class MayaAnim -{ -public: - string _name; - EggTable *_joint; - EggXfmSAnim *_pool; - void PrintData(void); -}; - -MayaAnim *MayaEggLoader::GetAnim(EggXfmSAnim *pool) -{ - MayaAnim *result = _anim_tab[pool]; - if (result == 0) { - result = new MayaAnim; - result->_pool = pool; - result->_name = pool->get_name(); - _anim_tab[pool] = result; - EggNode *jointNode = (DCAST(EggNode, pool))->get_parent(); - EggTable *joint = DCAST(EggTable, jointNode); - result->_joint = joint; - - } - return result; -} - -void MayaAnim::PrintData(void) -{ - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "anim on joint : " << _joint->get_name() << endl; - } - _pool->write(mayaloader_cat.debug(), 0); -} - -// MayaEggLoader functions - -void MayaEggLoader::CreateSkinCluster(MayaEggGeom *M) -{ - MString cmd("skinCluster -mi "); - vector joints; - - VertTable::const_iterator vert; - int maxInfluences = 0; - for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { - if ((int)(vert->_weights.size()) > maxInfluences) { - maxInfluences = vert->_weights.size(); - } - for (unsigned int i=0; i_weights.size(); i++) { - MayaEggJoint *joint = FindJoint(vert->_weights[i].second); - if (joint && !joint->_inskin) { - joint->_inskin = true; - joint->_index = joints.size(); - joints.push_back(joint); - /* - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << joints[i]->_egg_joint->get_name() << ": adding to skin\n"; - } - */ - } - } - } - cmd += maxInfluences; - - /* - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << joints.size() << " joints have weights on " << M->_pool->get_name() << endl; - } - */ - if (joints.size() == 0) { - // no need to cluster; there are no weights - return; - } - - for (unsigned int i=0; i_joint); - cmd = cmd + " "; - cmd = cmd + joint.name(); - } - - MFnDependencyNode shape(M->_shapeNode); - cmd = cmd + " "; - cmd = cmd + shape.name(); - - MStatus status; - MDGModifier dgmod; - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << cmd.asChar() << endl; - string spamCmd = M->_pool->get_name(); - for (unsigned int i=0; i_egg_joint->get_name(); - } - mayaloader_cat.spam() << spamCmd << ": total = " << joints.size() << endl; - } - status = dgmod.commandToExecute(cmd); - if (status != MStatus::kSuccess) { - perror("skinCluster commandToExecute"); - return; - } - status = dgmod.doIt(); - if (status != MStatus::kSuccess) { - perror("skinCluster doIt"); - return; - } - - MPlugArray oldplugs; - MPlug inPlug; - if (shape.typeName() == "mesh") { - inPlug = shape.findPlug("inMesh"); - } else if (shape.typeName() == "nurbsSurface") { - inPlug = shape.findPlug("create"); - } else { - // we only support mesh and nurbsSurface - return; - } - - if ((!inPlug.connectedTo(oldplugs,true,false))||(oldplugs.length() != 1)) { - cerr << "skinCluster command failed"; - return; - } - MFnSkinCluster skinCluster(oldplugs[0].node()); - MIntArray influenceIndices; - MFnSingleIndexedComponent component; - component.create(MFn::kMeshVertComponent); // [gjeon] Interestingly, we can use MFn::kMeshVertComponent for NURBS surface, too - component.setCompleteData(M->_vert_count); - for (unsigned int i=0; i_joint_dag_path, &status); - if (status != MStatus::kSuccess) { - perror("skinCluster index"); - return; - } - influenceIndices.append((int)index); - } - - MDagPathArray paths; - unsigned infcount = skinCluster.influenceObjects(paths, &status); - if (status != MStatus::kSuccess) { - perror("influenceObjects"); - return; - } - for (unsigned int i=0; i_shape_dag_path, component.object(), index, 0.0, false, nullptr); - } - - MFloatArray values; - int tot = M->_vert_count * joints.size(); - values.setLength(tot); - for (int i=0; i_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) { - for (unsigned int i=0; i_weights.size(); i++) { - double strength = vert->_weights[i].first / vert->_sumWeights; // [gjeon] nomalizing weights - MayaEggJoint *joint = FindJoint(vert->_weights[i].second); - values[vert->_index * joints.size() + joint->_index] = (PN_stdfloat)strength; - } - } - skinCluster.setWeights(M->_shape_dag_path, component.object(), influenceIndices, values, false, nullptr); - - for (unsigned int i=0; i_egg_joint->get_name() << ": clearing skin\n"; - } - */ - joints[i]->_inskin = false; - joints[i]->_index = -1; - } -} - -// TraverseEggData We have an EggData in memory, and now we're going to copy -// that over into the maya scene graph. - -void MayaEggLoader::TraverseEggNode(EggNode *node, EggGroup *context, string delim) -{ - vector vertIndices; - vector tvertIndices; - vector cvertIndices; - - string delstring = " "; - - if (node->is_of_type(EggPolygon::get_class_type())) { - /* - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << delim+delstring << "found an EggMesh: " << node->get_name() << endl; - } - */ - EggPolygon *poly = DCAST(EggPolygon, node); - if (poly->empty()) { - return; - } - poly->cleanup(); - - MayaEggTex *tex = 0; - LMatrix3d uvtrans = LMatrix3d::ident_mat(); - - if (poly->has_texture()) { - EggTexture *etex = poly->get_texture(0); - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "Texture format : " << etex->get_format() << endl; - } - tex = GetTex(etex); - if (etex->has_transform()) - uvtrans = etex->get_transform2d(); - } else { - tex = GetTex(nullptr); - } - - EggPolygon::const_iterator ci; - MayaEggMesh *mesh = GetMesh(poly->get_pool(), context); - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "traverse mesh pointer " << mesh << "\n"; - } - vertIndices.clear(); - tvertIndices.clear(); - cvertIndices.clear(); - int numVertices = 0; - for (ci = poly->begin(); ci != poly->end(); ++ci) { - EggVertex *vtx = (*ci); - LTexCoordd uv(0,0); - if (vtx->has_uv()) { - uv = vtx->get_uv(); - } - vertIndices.push_back(mesh->GetVert(vtx, context)); - tvertIndices.push_back(mesh->GetTVert(uv * uvtrans)); - cvertIndices.push_back(mesh->GetCVert(vtx->get_color())); - numVertices++; - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "num vertices: " << vertIndices.size() << "\n"; - } - - if (numVertices < 3) - return; - - MIntArray mvertIndices; - MIntArray mtvertIndices; - for (int i = 0; i < numVertices; i++) { - mvertIndices.append(vertIndices[i]); - mtvertIndices.append(tvertIndices[i]); - } - if (poly->has_color()) { - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "found a face color of " << poly->get_color() << endl; - } - mesh->_faceIndices.append(mesh->_face_count); - mesh->_faceColorArray.append(MakeMayaColor(poly->get_color())); - } - mesh->AddFace(numVertices, mvertIndices, mtvertIndices, tex); - - // [gjeon] to handle double-sided flag - if (poly->get_bface_flag()) { - mesh->AddEggFlag("double-sided"); - } - - // [gjeon] to handle model flag - if (context->get_model_flag()) { - mesh->AddEggFlag("model"); - } - - // [gjeon] to handle billboard flag - switch (context->get_billboard_type()) { - case EggGroup::BT_axis: - mesh->AddEggFlag("billboard"); - break; - - case EggGroup::BT_point_camera_relative: - mesh->AddEggFlag("billboard-point"); - break; - - default: - ; - } - - // [gjeon] to handle other flags - for (int i = 0; i < context->get_num_object_types(); i++) { - mesh->AddEggFlag(MString(context->get_object_type(i).c_str())); - } - - } else if (node->is_of_type(EggNurbsSurface::get_class_type())) { - // [gjeon] to convert nurbsSurface - EggNurbsSurface *eggNurbsSurface = DCAST(EggNurbsSurface, node); - - EggNurbsSurface::const_iterator ci; - EggVertexPool *pool = eggNurbsSurface->get_pool(); - MayaEggNurbsSurface *surface = GetSurface(pool, context); - - for (ci = eggNurbsSurface->begin(); ci != eggNurbsSurface->end(); ++ci) { - EggVertex *vtx = (*ci); - surface->GetVert(vtx, context); - } - - // [gjeon] finding textures - MayaEggTex *tex = 0; - LMatrix3d uvtrans = LMatrix3d::ident_mat(); - - if (eggNurbsSurface->has_texture()) { - EggTexture *etex = eggNurbsSurface->get_texture(0); - tex = GetTex(etex); - if (etex->has_transform()) - { - mayaloader_cat.debug() << "uvtrans?" << endl; - uvtrans = etex->get_transform2d(); - } - } else { - tex = GetTex(nullptr); - } - - surface->_tex = tex; - surface->_uNumCvs = eggNurbsSurface->get_num_u_cvs(); - surface->_vNumCvs = eggNurbsSurface->get_num_v_cvs(); - - // [gjeon] building cvArray - for (unsigned int ui = 0; ui < surface->_uNumCvs; ui++) { - for (unsigned int vi = 0; vi < surface->_vNumCvs; vi++) { - EggVertex *vtx = eggNurbsSurface->get_vertex(eggNurbsSurface->get_vertex_index(ui, vi)); - surface->_cvArray.append(MakeMPoint(vtx->get_pos3())); - } - } - - // [gjeon] building u knotArray - for (int i = 1; i < eggNurbsSurface->get_num_u_knots()-1; i++) { - surface->_uKnotArray.append(eggNurbsSurface->get_u_knot(i)); - } - - // [gjeon] building v knotArray - for (int i = 1; i < eggNurbsSurface->get_num_v_knots()-1; i++) { - surface->_vKnotArray.append(eggNurbsSurface->get_v_knot(i)); - } - - surface->_uDegree = eggNurbsSurface->get_u_degree(); - surface->_vDegree = eggNurbsSurface->get_v_degree(); - - if (eggNurbsSurface->is_closed_u()) { - surface->_uForm = MFnNurbsSurface::kClosed; - } else { - surface->_vForm = MFnNurbsSurface::kOpen; - } - - if (eggNurbsSurface->is_closed_v()) { - surface->_vForm = MFnNurbsSurface::kClosed; - } else { - surface->_vForm = MFnNurbsSurface::kOpen; - } - - // [gjeon] to handle double-sided flag - if (eggNurbsSurface->get_bface_flag()) { - surface->AddEggFlag("double-sided"); - } - - // [gjeon] to handle model flag - if (context->get_model_flag()) { - surface->AddEggFlag("model"); - } - - // [gjeon] to handle other flags - for (int i = 0; i < context->get_num_object_types(); i++) { - surface->AddEggFlag(MString(context->get_object_type(i).c_str())); - } - - } else if (node->is_of_type(EggComment::get_class_type())) { - string comment = (DCAST(EggComment, node))->get_comment(); - if (comment.find("2egg") != string::npos) { - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << delim+delstring << "found an EggComment: " << comment << endl; - } - if (comment.find("chan") != string::npos) { - ParseFrameInfo(comment); - } - } - } else if (node->is_of_type(EggSAnimData::get_class_type())) { - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << delim+delstring << "found an EggSAnimData: " << node->get_name() << endl; - } - // EggSAnimData *anim = DCAST(EggSAnimData, node); MayaAnimData *animData - // = GetAnimData(anim, DCAST(EggXfmSAnim, node->get_parent())); - // animData->PrintData(); if (_end_frame < - // animData->_pool->get_num_rows()) { _end_frame = - // animData->_pool->get_num_rows(); } - } else if (node->is_of_type(EggGroupNode::get_class_type())) { - EggGroupNode *group = DCAST(EggGroupNode, node); - if (node->is_of_type(EggGroup::get_class_type())) { - EggGroup *group = DCAST(EggGroup, node); - - if (group->get_name() == "") { - ostringstream stream; - stream << _unnamed_idx; - group->set_name("unnamed" + stream.str()); - _unnamed_idx++; - } - - string group_name = group->get_name(); - size_t found = group_name.find(":"); - if (found != string::npos) - group->set_name(group_name.replace(int(found), 1, "_")); - - string parent_name = ""; - if (context) - parent_name = context->get_name(); - if (group->is_joint()) { - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << delim+delstring << group->get_name() << ":" << parent_name << endl; - } - MakeJoint(group, context); - context = group; - } else { - // lets create a group node for it so that it is reflected in Maya - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << delim+delstring << group->get_name() << "@" << parent_name << endl; - } - MakeGroup(group, context); - context = group; - } - } else if (node->is_of_type(EggTable::get_class_type())) { - // EggTable *anim = DCAST(EggTable, node); - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << delim+delstring << "found an EggTable: " << node->get_name() << endl; - } - } else if (node->is_of_type(EggXfmSAnim::get_class_type())) { - // Create a MayaAnim equivalent of the EggXfmSAnim - GetAnim(DCAST(EggXfmSAnim, node)); - //anim->PrintData(); - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << delim+delstring << "found an EggXfmSAnim: " << node->get_name() << endl; - } - } - - EggGroupNode::const_iterator ci; - for (ci = group->begin(); ci != group->end(); ++ci) { - TraverseEggNode(*ci, context, delim+delstring); - } - } -} - -bool MayaEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals) -{ - if (!merge) { - mayaloader_cat.error() << "Currently, only 'merge' mode is implemented.\n"; - return false; - } - - /* - if ((anim) || (!model)) { - mayaloader_cat.error() << "Currently, only model-loading is implemented.\n"; - return false; - } - */ - - _start_frame = 0; - _end_frame = 0; - _frame_rate = 24; - _timeUnit = MTime::kFilm; - _unnamed_idx = 1; - - MeshTable::const_iterator ci; - JointTable::const_iterator ji; - TexTable::const_iterator ti; - SurfaceTable::const_iterator si; - AnimTable::const_iterator ei; - - if (MGlobal::isYAxisUp()) { - data->set_coordinate_system(CS_yup_right); - } else { - data->set_coordinate_system(CS_zup_right); - } - - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "root node: " << data->get_type() << endl; - } - TraverseEggNode(data, nullptr, ""); - - MStatus status; - - MFnSet collision_set; - collision_set.create(_collision_nodes, MFnSet::kNone, &status); - - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "num meshes : " << _mesh_tab.size() << endl; - } - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MayaEggMesh *mesh = (*ci).second; - if (mesh->_face_count==0) { - continue; - } - - // MStatus status; - MFnMesh mfn; - MString cset; - - MayaEggGroup *parentNode = FindGroup(mesh->_parent); - MObject parent = MObject::kNullObj; - if (parentNode) { - parent = parentNode->_group; - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "mesh's parent (group) : " << parentNode->_name << endl; - } - } else { - mesh->_renameTrans = true; - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "mesh's parent (null) : " << endl; - } - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "mesh pointer : " << mesh << " and parent_pointer: " << &parent << endl; - mayaloader_cat.spam() << "mesh vert_count : " << mesh->_vert_count << endl; - mayaloader_cat.spam() << "mesh face_count : " << mesh->_face_count << endl; - mayaloader_cat.spam() << "mesh vertexArray size: " << mesh->_vertexArray.length() << endl; - mayaloader_cat.spam() << "mesh polygonCounts size: " << mesh->_polygonCounts.length() << endl; - mayaloader_cat.spam() << "mesh polygonConnects size: " << mesh->_polygonConnects.length() << endl; - mayaloader_cat.spam() << "mesh uarray size: " << mesh->_uarray.length() << endl; - mayaloader_cat.spam() << "mesh varray size: " << mesh->_varray.length() << endl; - } - mesh->_transNode = mfn.create(mesh->_vert_count, mesh->_face_count, - mesh->_vertexArray, mesh->_polygonCounts, mesh->_polygonConnects, - mesh->_uarray, mesh->_varray, - parent, &status); - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "transNode created." << endl; - } - - if (!mesh->_renameTrans) { - mesh->_transNode = parent; - } - - // [gjeon] add eggFlag attributes if any exists - for (unsigned i = 0; i < mesh->_eggObjectTypes.length(); i++) { - MString attrName = "eggObjectTypes"; - attrName += (int)(i + 1); - status = create_enum_attribute(mesh->_transNode, attrName, attrName, mesh->_eggObjectTypes, i); - if (status != MStatus::kSuccess) { - status.perror("create_enum_attribute failed!"); - } - } - - // Check the "Display Colors" box by default, so that vertex colors (if - // any) will be visible. - MPlug displayColors = mfn.findPlug("displayColors"); - displayColors.setValue((bool)true); - - mesh->_shapeNode = mfn.object(); - mfn.getPath(mesh->_shape_dag_path); - mesh->ConnectTextures(); - - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "textures connected." << endl; - } - - mfn.getCurrentUVSetName(cset); - status = mfn.assignUVs(mesh->_polygonCounts, mesh->_uvIds, &cset); - - if (status != MStatus::kSuccess) { - status.perror("assignUVs failed"); - if (mayaloader_cat.is_spam()) { - PrintData(mesh); - } - } - else { - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "uvs assigned." << endl; - } - } - - // lets try to set normals per vertex - if (respect_normals) { - status = mfn.setVertexNormals(mesh->_normalArray, mesh->_vertNormalIndices, MSpace::kTransform); - if (status != MStatus::kSuccess) { - status.perror("setVertexNormals failed!"); - } - } - - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "vertex normals set." << endl; - } - - // lets try to set colors per vertex - /* - MDGModifier dgmod; - status = dgmod.doIt(); - if (status != MStatus::kSuccess) { - status.perror("setVertexColors doIt"); - } - status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices, &dgmod); - */ - status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices); - if (status != MStatus::kSuccess) { - status.perror("setVertexColors failed!"); - } - status = mfn.setFaceColors(mesh->_faceColorArray, mesh->_faceIndices); - /* - if (status != MStatus::kSuccess) { - status.perror("setFaceColors failed!"); - } - */ - } - - for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) { - MayaEggNurbsSurface *surface = (*si).second; - if (surface->_cvArray.length()==0) { - continue; - } - - // MStatus status; - MFnNurbsSurface mfnNurbsSurface; - - MayaEggGroup *parentNode = FindGroup(surface->_parent); - MObject parent = MObject::kNullObj; - if (parentNode) { - parent = parentNode->_group; - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "surface's parent (group) : " << parentNode->_name << endl; - } - } else { - surface->_renameTrans = true; - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "surface's parent (null) : " << endl; - } - } - - surface->_transNode = mfnNurbsSurface.create(surface->_cvArray, surface->_uKnotArray, surface->_vKnotArray, - surface->_uDegree, surface->_vDegree, surface->_uForm, surface->_vForm, - true, parent, &status); - - if (!surface->_renameTrans) { - surface->_transNode = parent; - } - - // [gjeon] add eggFlag attributes if any exists - for (unsigned i = 0; i < surface->_eggObjectTypes.length(); i++) { - MString attrName = "eggObjectTypes"; - attrName += (int)(i + 1); - status = create_enum_attribute(surface->_transNode, attrName, attrName, surface->_eggObjectTypes, i); - if (status != MStatus::kSuccess) { - status.perror("create_enum_attribute failed!"); - } - } - surface->_shapeNode = mfnNurbsSurface.object(); - mfnNurbsSurface.getPath(surface->_shape_dag_path); - surface->ConnectTextures(); - - mayaloader_cat.debug() << status.errorString().asChar() << endl; - } - - - double thickness = 0.0; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - MayaEggJoint *joint = (*ji).second; - double dfo = (joint->GetPos()).length(); - if (dfo > thickness) { - thickness = dfo; - } - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "thickness from joints: " << thickness << endl; - } - thickness = thickness * 0.025; - for (unsigned int i=0; i<_joint_list.size(); i++) { - MayaEggJoint *joint = _joint_list[i]; - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "creating a joint: " << joint->_egg_joint->get_name() << endl; - } - joint->ChooseEndPos(thickness); - joint->CreateMayaBone(FindGroup(joint->_egg_parent)); - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "went past all the joints" << endl; - } - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MayaEggMesh *mesh = (*ci).second; - EggGroup *joint = mesh->GetControlJoint(); - if (joint) { - CreateSkinCluster(mesh); - } - } - for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) { - MayaEggNurbsSurface *surface = (*si).second; - EggGroup *joint = surface->GetControlJoint(); - if (joint) { - CreateSkinCluster(surface); - } - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "went past creating skin cluster" << endl; - } - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - (*ci).second->AssignNames(); - } - for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) { - (*si).second->AssignNames(); - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "went past mesh AssignNames" << endl; - } - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - (*ji).second->AssignNames(); - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "went past joint AssignNames" << endl; - } - for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) { - (*ti).second->AssignNames(); - } - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "went past tex AssignNames" << endl; - } - - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << "-fri: " << _frame_rate << " -sf: " << _start_frame - << " -ef: " << _end_frame << endl; - } - - // masad: keep track of maximum frames of animation on all these joints - MTime maxFrame(_start_frame - 1, _timeUnit); - MTime minFrame = maxFrame; - - for (ei = _anim_tab.begin(); ei != _anim_tab.end(); ++ei) { - MayaAnim *anim = (*ei).second; - MObject node = GetDependencyNode(anim->_joint->get_name()); - MFnDagNode mfnNode(node, &status); - - MMatrix mMat = mfnNode.transformationMatrix(&status); - - MObject attrTX = mfnNode.attribute("translateX", &status); - MObject attrTY = mfnNode.attribute("translateY", &status); - MObject attrTZ = mfnNode.attribute("translateZ", &status); - MObject attrRX = mfnNode.attribute("rotateX", &status); - MObject attrRY = mfnNode.attribute("rotateY", &status); - MObject attrRZ = mfnNode.attribute("rotateZ", &status); - MObject attrSX = mfnNode.attribute("scaleX", &status); - MObject attrSY = mfnNode.attribute("scaleY", &status); - MObject attrSZ = mfnNode.attribute("scaleZ", &status); - - MFnAnimCurve mfnAnimCurveTX; - MFnAnimCurve mfnAnimCurveTY; - MFnAnimCurve mfnAnimCurveTZ; - MFnAnimCurve mfnAnimCurveRX; - MFnAnimCurve mfnAnimCurveRY; - MFnAnimCurve mfnAnimCurveRZ; - MFnAnimCurve mfnAnimCurveSX; - MFnAnimCurve mfnAnimCurveSY; - MFnAnimCurve mfnAnimCurveSZ; - - mfnAnimCurveTX.create(node, attrTX, MFnAnimCurve::kAnimCurveTL, nullptr, &status); - mfnAnimCurveTY.create(node, attrTY, MFnAnimCurve::kAnimCurveTL, nullptr, &status); - mfnAnimCurveTZ.create(node, attrTZ, MFnAnimCurve::kAnimCurveTL, nullptr, &status); - mfnAnimCurveRX.create(node, attrRX, MFnAnimCurve::kAnimCurveTA, nullptr, &status); - mfnAnimCurveRY.create(node, attrRY, MFnAnimCurve::kAnimCurveTA, nullptr, &status); - mfnAnimCurveRZ.create(node, attrRZ, MFnAnimCurve::kAnimCurveTA, nullptr, &status); - mfnAnimCurveSX.create(node, attrSX, MFnAnimCurve::kAnimCurveTU, nullptr, &status); - mfnAnimCurveSY.create(node, attrSY, MFnAnimCurve::kAnimCurveTU, nullptr, &status); - mfnAnimCurveSZ.create(node, attrSZ, MFnAnimCurve::kAnimCurveTU, nullptr, &status); - - MTransformationMatrix matrix( mMat ); - MVector trans = matrix.translation(MSpace::kTransform, &status); - - double rot[3]; - MTransformationMatrix::RotationOrder order = MTransformationMatrix::kXYZ; - status = matrix.getRotation(rot, order); - - double scale[3]; - status = matrix.getScale(scale, MSpace::kTransform); - MFnAnimCurve::TangentType tangent = MFnAnimCurve::kTangentClamped; - MTime time(_start_frame - 1, _timeUnit); - - mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, nullptr, &status); - mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, nullptr, &status); - mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, nullptr, &status); - mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, nullptr, &status); - mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, nullptr, &status); - mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, nullptr, &status); - mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, nullptr, &status); - mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, nullptr, &status); - mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, nullptr, &status); - - for (int frame = 0; frame < anim->_pool->get_num_rows(); frame++) - { - LMatrix4d tMat; - anim->_pool->get_value(frame, tMat); - - double matData[4][4] = {{tMat.get_cell(0,0), tMat.get_cell(0,1), tMat.get_cell(0,2), tMat.get_cell(0,3)}, - {tMat.get_cell(1,0), tMat.get_cell(1,1), tMat.get_cell(1,2), tMat.get_cell(1,3)}, - {tMat.get_cell(2,0), tMat.get_cell(2,1), tMat.get_cell(2,2), tMat.get_cell(2,3)}, - {tMat.get_cell(3,0), tMat.get_cell(3,1), tMat.get_cell(3,2), tMat.get_cell(3,3)}}; - MMatrix mat(matData); - - matrix = MTransformationMatrix(mat); - trans = matrix.translation(MSpace::kTransform, &status); - status = matrix.getRotation(rot, order); - status = matrix.getScale(scale, MSpace::kTransform); - time = MTime(frame + _start_frame, _timeUnit); - - mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, nullptr, &status); - mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, nullptr, &status); - mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, nullptr, &status); - mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, nullptr, &status); - mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, nullptr, &status); - mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, nullptr, &status); - mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, nullptr, &status); - mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, nullptr, &status); - mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, nullptr, &status); - } - if (maxFrame < time) { - maxFrame = time; - } - } - if (anim) { - // masad: set the control's max time with maxFrame - MAnimControl::setMaxTime(maxFrame); - MAnimControl::setMinTime(minFrame); - } - - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - delete (*ci).second; - } - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - delete (*ji).second; - } - for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) { - delete (*ti).second; - } - for (ei = _anim_tab.begin(); ei != _anim_tab.end(); ++ei) { - delete (*ei).second; - } - - // ResumeSetKeyMode(); ResumeAnimate(); - - mayaloader_cat.info() << "Egg import successful\n"; - return true; -} - -void MayaEggLoader::PrintData(MayaEggMesh *mesh) -{ - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "Mesh: " << mesh->_name << endl; - mayaloader_cat.spam() << "num vertexArray: " << mesh->_vertexArray.length() << endl; - ostringstream stream3; - for (unsigned int i=0; i < mesh->_vertexArray.length(); ++i) { - stream3 << "[" << mesh->_vertexArray[i].x << " " << mesh->_vertexArray[i].y << " " << mesh->_vertexArray[i].z << "]" << endl; - } - - mayaloader_cat.spam() << "vertexArray: \n" << stream3.str() << endl; - mayaloader_cat.spam() << "num polygonConnects: " << mesh->_polygonConnects.length() << endl; - mayaloader_cat.spam() << "num uvCounts: " << mesh->_polygonCounts.length() << endl; - mayaloader_cat.spam() << "num uvIds: " << mesh->_uvIds.length() << endl; - ostringstream stream1, stream4; - unsigned int k=0; - for (unsigned int i=0; i < mesh->_polygonCounts.length(); ++i) { - stream1 << mesh->_polygonCounts[i] << ":->"; - stream4 << mesh->_polygonCounts[i] << ":->"; - for (int j=0; j < mesh->_polygonCounts[i]; ++j, ++k) { - stream1 << mesh->_uvIds[k] << ","; - stream4 << mesh->_polygonConnects[k] << ","; - } - stream1 << endl; - stream4 << endl; - } - mayaloader_cat.spam() << "uvCounts:->uvIds " << endl << stream1.str() << endl; - mayaloader_cat.spam() << "vertexCount:->polygonConnects" << endl << stream4.str() << endl; - } -} - -void MayaEggLoader::ParseFrameInfo(string comment) -{ - size_t pos, ls, le; - - pos = comment.find("-fri"); - if (pos != string::npos) { - ls = comment.find(" ", pos+4); - le = comment.find(" ", ls+1); - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl; - } - _frame_rate = atoi(comment.substr(ls+1,le-ls-1).data()); - // mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; - // frame_rate = " << _frame_rate << endl; - - switch (_frame_rate) { - case 15: - _timeUnit = MTime::kGames; - break; - case 24: - _timeUnit = MTime::kFilm; - break; - case 25: - _timeUnit = MTime::kPALFrame; - break; - case 30: - _timeUnit = MTime::kNTSCFrame; - break; - case 48: - _timeUnit = MTime::kShowScan; - break; - case 50: - _timeUnit = MTime::kPALField; - break; - case 60: - _timeUnit = MTime::kNTSCField; - break; - case 2: - _timeUnit = MTime::k2FPS; - break; - case 3: - _timeUnit = MTime::k3FPS; - break; - case 4: - _timeUnit = MTime::k4FPS; - break; - case 5: - _timeUnit = MTime::k5FPS; - break; - case 6: - _timeUnit = MTime::k6FPS; - break; - case 8: - _timeUnit = MTime::k8FPS; - break; - case 10: - _timeUnit = MTime::k10FPS; - break; - case 12: - _timeUnit = MTime::k12FPS; - break; - case 16: - _timeUnit = MTime::k16FPS; - break; - case 20: - _timeUnit = MTime::k20FPS; - break; - case 40: - _timeUnit = MTime::k40FPS; - break; - case 75: - _timeUnit = MTime::k75FPS; - break; - case 80: - _timeUnit = MTime::k80FPS; - break; - case 100: - _timeUnit = MTime::k100FPS; - break; - default: - _timeUnit = MTime::kFilm; - } - - } - - pos = comment.find("-sf"); - if (pos != string::npos) { - ls = comment.find(" ", pos+3); - le = comment.find(" ", ls+1); - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl; - } - if (le == string::npos) { - _start_frame = atoi(comment.substr(ls+1,le).data()); - } else { - _start_frame = atoi(comment.substr(ls+1,le-ls-1).data()); - } - // mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; - // start_frame = " << _start_frame << endl; - } - pos = comment.find("-ef"); - if (pos != string::npos) { - ls = comment.find(" ", pos+3); - le = comment.find(" ", ls+1); - if (mayaloader_cat.is_debug()) { - mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl; - } - if (le == string::npos) { - _end_frame = atoi(comment.substr(ls+1,le).data()); - } else { - _end_frame = atoi(comment.substr(ls+1,le-ls-1).data()); - } - // mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; - // end_frame = " << _end_frame << endl; - } - - -} - -bool MayaEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals) -{ - EggData data; - Filename datafn = Filename::from_os_specific(name); - if (!data.read(datafn)) { - mayaloader_cat.error() << "Cannot read Egg file for import\n"; - return false; - } - return ConvertEggData(&data, merge, model, anim, respect_normals); -} - -MObject MayaEggLoader::GetDependencyNode(string givenName) -{ - MObject node = MObject::kNullObj; - size_t pos; - string name; - - pos = givenName.find(":"); - if (pos != string::npos) { - name = givenName.substr(pos+1); - } else - name = givenName; - - /* - // masad: I do not think you want to return a mesh node because keyframes - // should only apply to joint nodes. - MeshTable::const_iterator ci; - for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) { - MayaEggMesh *mesh = (*ci).second; - - string meshName = mesh->_pool->get_name(); - int nsize = meshName.size(); - if ((nsize > 6) && (meshName.rfind(".verts")==(nsize-6))) { - meshName.resize(nsize-6); - } - if (meshName == name) - { - node = mesh->_transNode; - cerr << "foo get dependency node returning a mesh's transNode? why? : " << givenName << endl; - return node; - } - } - */ - - JointTable::const_iterator ji; - for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) { - MayaEggJoint *joint = (*ji).second; - if (mayaloader_cat.is_spam()) { - mayaloader_cat.spam() << "traversing a joint: " << joint->_egg_joint->get_name() << endl; - } - string jointName = joint->_egg_joint->get_name(); - if (jointName == name) - { - node = joint->_joint; - return node; - } - } - - return node; -} - -// The two global functions that form the API of this module. - -bool MayaLoadEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals) -{ - MayaEggLoader loader; - bool temp = loader.ConvertEggData(data, merge, model, anim, respect_normals); - return temp; -} - -bool MayaLoadEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals) -{ - MayaEggLoader loader; - return loader.ConvertEggFile(name, merge, model, anim, respect_normals); -} diff --git a/pandatool/src/mayaegg/mayaEggLoader.h b/pandatool/src/mayaegg/mayaEggLoader.h deleted file mode 100644 index 077d0da5aef..00000000000 --- a/pandatool/src/mayaegg/mayaEggLoader.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaEggLoader.h - * @author jyelon - * @date 2005-07-20 - */ - -#ifndef MAYAEGGLOADER_H -#define MAYAEGGLOADER_H - -class EggData; - -bool MayaLoadEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals); -bool MayaLoadEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals); - -#endif diff --git a/pandatool/src/mayaegg/mayaNodeDesc.cxx b/pandatool/src/mayaegg/mayaNodeDesc.cxx deleted file mode 100644 index 2c251ac9ca3..00000000000 --- a/pandatool/src/mayaegg/mayaNodeDesc.cxx +++ /dev/null @@ -1,572 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaNodeDesc.cxx - * @author drose - * @date 2003-06-06 - */ - -#include "mayaNodeDesc.h" -#include "mayaNodeTree.h" -#include "mayaBlendDesc.h" -#include "mayaToEggConverter.h" -#include "maya_funcs.h" -#include "eggGroup.h" -#include "config_mayaegg.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include "post_maya_include.h" - -using std::string; - -TypeHandle MayaNodeDesc::_type_handle; - -// This is a list of the names of Maya connections that count as a transform. -static const char *transform_connections[] = { - "translate", - "translateX", - "translateY", - "translateZ", - "rotate", - "rotateX", - "rotateY", - "rotateZ", -}; -static const int num_transform_connections = sizeof(transform_connections) / sizeof(const char *); - -/** - * - */ -MayaNodeDesc:: -MayaNodeDesc(MayaNodeTree *tree, MayaNodeDesc *parent, const string &name) : - Namable(name), - _tree(tree), - _parent(parent) -{ - _dag_path = nullptr; - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - _joint_type = JT_none; - _is_lod = false; - _tagged = false; - _joint_tagged = false; - - // Add ourselves to our parent. - if (_parent != nullptr) { - _parent->_children.push_back(this); - } -} - -/** - * - */ -MayaNodeDesc:: -~MayaNodeDesc() { - delete _dag_path; -} - -/** - * Indicates an association between the MayaNodeDesc and some Maya instance. - */ -void MayaNodeDesc:: -from_dag_path(const MDagPath &dag_path, MayaToEggConverter *converter) { - MStatus status; - - if (_dag_path == nullptr) { - _dag_path = new MDagPath(dag_path); - - string name; - MFnDagNode dag_node(dag_path, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - } else { - name = dag_node.name().asChar(); - } - - if (_dag_path->hasFn(MFn::kJoint) || converter->force_joint(name)) { - // This node is a joint, or the user specifically asked to treat it like - // a joint. - _joint_type = JT_joint; - if (_parent != nullptr) { - _parent->mark_joint_parent(); - } - - } else { - // The node is not a joint, but maybe its transform is controlled by - // connected inputs. If so, we should treat it like a joint. - bool transform_connected = false; - - MStatus status; - MObject node = dag_path.node(&status); - if (status) { - for (int i = 0; - i < num_transform_connections && !transform_connected; - i++) { - if (is_connected(node, transform_connections[i])) { - transform_connected = true; - } - } - } - - if (transform_connected) { - _joint_type = JT_joint; - if (_parent != nullptr) { - _parent->mark_joint_parent(); - } - } - } - - if (dag_path.hasFn(MFn::kNurbsSurface)) { - MFnNurbsSurface surface(dag_path, &status); - if (status) { - check_blend_shapes(surface, "create"); - } - } else if (dag_path.hasFn(MFn::kMesh)) { - MFnMesh mesh(dag_path, &status); - if (status) { - check_blend_shapes(mesh, "inMesh"); - } - } - } -} - -/** - * Returns true if a Maya dag path has been associated with this node, false - * otherwise. - */ -bool MayaNodeDesc:: -has_dag_path() const { - return (_dag_path != nullptr); -} - -/** - * Returns the dag path associated with this node. It is an error to call - * this unless has_dag_path() returned true. - */ -const MDagPath &MayaNodeDesc:: -get_dag_path() const { - nassertr(_dag_path != nullptr, *_dag_path); - return *_dag_path; -} - -/** - * Returns the number of unique MayaBlendDesc objects (and hence the number of - * morph sliders) that affect the geometry in this node. - */ -int MayaNodeDesc:: -get_num_blend_descs() const { - return _blend_descs.size(); -} - -/** - * Returns the nth MayaBlendDesc object that affects the geometry in this - * node. - */ -MayaBlendDesc *MayaNodeDesc:: -get_blend_desc(int n) const { - nassertr(n >= 0 && n < (int)_blend_descs.size(), nullptr); - return _blend_descs[n]; -} - -/** - * Returns true if the node should be treated as a joint by the converter. - */ -bool MayaNodeDesc:: -is_joint() const { - // return _joint_type == JT_joint || _joint_type == JT_pseudo_joint; - return _joint_tagged && (_joint_type == JT_joint || _joint_type == JT_pseudo_joint); -} - -/** - * Returns true if the node is the parent or ancestor of a joint. - */ -bool MayaNodeDesc:: -is_joint_parent() const { - return _joint_type == JT_joint_parent; - // return _joint_tagged && (_joint_type == JT_joint_parent); -} - -/** - * Returns true if the node has been joint_tagged to be converted, false - * otherwise. - */ -bool MayaNodeDesc:: -is_joint_tagged() const { - return _joint_tagged; -} - -/** - * Tags this node for conversion, but does not tag child nodes. - */ -void MayaNodeDesc:: -tag_joint() { - _joint_tagged = true; -} - -/** - * Tags this node and all descendant nodes for conversion. - */ -void MayaNodeDesc:: -tag_joint_recursively() { - _joint_tagged = true; - // mayaegg_cat.info() << "tjr: " << get_name() << endl; - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MayaNodeDesc *child = (*ci); - child->tag_joint_recursively(); - } -} - -/** - * Returns true if the node has been tagged to be converted, false otherwise. - */ -bool MayaNodeDesc:: -is_tagged() const { - return _tagged; -} - -/** - * Tags this node for conversion, but does not tag child nodes. - */ -void MayaNodeDesc:: -tag() { - _tagged = true; -} - -/** - * Un-tags this node for conversion, but does not tag child nodes. - */ -void MayaNodeDesc:: -untag() { - _tagged = false; -} - -/** - * Tags this node and all descendant nodes for conversion. - */ -void MayaNodeDesc:: -tag_recursively() { - _tagged = true; - - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MayaNodeDesc *child = (*ci); - child->tag_recursively(); - } -} - -/** - * Un-tags this node and all descendant nodes for conversion. - */ -void MayaNodeDesc:: -untag_recursively() { - _tagged = false; - - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MayaNodeDesc *child = (*ci); - child->untag_recursively(); - } -} - -/** - * Returns true if this node or any of its parent has_object_type of - * object_type. - */ -bool MayaNodeDesc:: -has_object_type(string object_type) const { - bool ret = false; - if ((_egg_group != nullptr) - && _egg_group->has_object_type(object_type)) { - return true; - } - if (_parent != nullptr) { - ret |= _parent->has_object_type(object_type); - } - return ret; -} - -/** - * Recursively clears the egg pointers from this node and all children. - */ -void MayaNodeDesc:: -clear_egg() { - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MayaNodeDesc *child = (*ci); - child->clear_egg(); - } -} - -/** - * Indicates that this node has at least one child that is a joint or a - * pseudo-joint. - */ -void MayaNodeDesc:: -mark_joint_parent() { - if (_joint_type == JT_none) { - _joint_type = JT_joint_parent; - if (_parent != nullptr) { - _parent->mark_joint_parent(); - } - } -} - -/** - * Walks the hierarchy, looking for non-joint nodes that are both children and - * parents of a joint. These nodes are deemed to be pseudo joints, since the - * converter must treat them as joints. - */ -void MayaNodeDesc:: -check_pseudo_joints(bool joint_above) { - static uint32_t space_count = 0; - string space; - for (uint32_t idx=0; idxcheck_pseudo_joints(joint_above); - // if (child->is_joint()) { - if (child->_joint_type == JT_joint || child->_joint_type == JT_pseudo_joint) { - any_joints = true; - } - } - - // If any children qualify as joints, then any sibling nodes that are - // parents of joints are also elevated to joints. - if (any_joints) { - bool all_joints = true; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MayaNodeDesc *child = (*ci); - MStatus status; - MFnDagNode dag_node(child->get_dag_path(), &status); - if (!status) { - status.perror("MFnDagNode constructor"); - } - string type_name = dag_node.typeName().asChar(); - if (child->_joint_type == JT_joint_parent) { - child->_joint_type = JT_pseudo_joint; - } else if (child->_joint_type == JT_none) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "cpj: " << space << "jt_none for " << child->get_name() << std::endl; - } - if (type_name.find("transform") == string::npos) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "cpj: " << space << "all_joints false for " << get_name() << std::endl; - } - all_joints = false; - } - } - } - - if (all_joints) { - // Finally, if all children are joints, then we are too. - if (_joint_type == JT_joint_parent) { - if (!get_name().empty()) { // make sure parent of root is not a joint - _joint_type = JT_pseudo_joint; - } - } - } - } - } - if (mayaegg_cat.is_spam()) { - if (space_count > 0) - --space_count; - } -} - -/** - * Looks for blend shapes on a NURBS surface or polygon mesh and records any - * blend shapes found. This is similar to - * MayaToEggConverter::get_vertex_weights(), which checks for membership of - * vertices to joints; Maya stores the blend shape table in the same place. - * See the comments in get_vertex_weights() for a more in-depth description of - * the iteration process here. - */ -void MayaNodeDesc:: -check_blend_shapes(const MFnDagNode &node, const string &attrib_name) { - MStatus status; - - MObject attr = node.attribute(attrib_name.c_str()); - - MPlug history(node.object(), attr); - MItDependencyGraph it(history, MFn::kDependencyNode, - MItDependencyGraph::kUpstream, - MItDependencyGraph::kDepthFirst, - MItDependencyGraph::kNodeLevel); - - while (!it.isDone()) { - MObject c_node = it.thisNode(); - - if (c_node.hasFn(MFn::kBlendShape)) { - MFnBlendShapeDeformer blends(c_node, &status); - if (!status) { - status.perror("MFnBlendShapeDeformer constructor"); - - } else { - // Check if the slider is a "parallel blender", which is a construct - // created by Maya for Maya's internal purposes only. We don't want - // to fiddle with the parallel blenders. - MPlug plug = blends.findPlug("pb"); - bool is_parallel_blender; - status = plug.getValue(is_parallel_blender); - if (!status) { - status.perror("Could not get value of pb plug."); - is_parallel_blender = false; - } - - if (is_parallel_blender || - _tree->ignore_slider(blends.name().asChar())) { - _tree->report_ignored_slider(blends.name().asChar()); - - } else { - MObjectArray base_objects; - status = blends.getBaseObjects(base_objects); - if (!status) { - status.perror("MFnBlendShapeDeformer::getBaseObjects"); - } else { - for (unsigned int oi = 0; oi < base_objects.length(); oi++) { - MObject base_object = base_objects[oi]; - - MIntArray index_list; - status = blends.weightIndexList(index_list); - if (!status) { - status.perror("MFnBlendShapeDeformer::weightIndexList"); - } else { - for (unsigned int i = 0; i < index_list.length(); i++) { - int wi = index_list[i]; - PT(MayaBlendDesc) blend_desc = new MayaBlendDesc(blends, wi); - blend_desc = _tree->add_blend_desc(blend_desc); - _blend_descs.push_back(blend_desc); - } - } - } - } - } - } - } - - it.next(); - } -} - -/** - * Walks through the hierarchy again and checks for LOD specifications. Any - * such specifications found are recorded on the child nodes of the lodGroups - * themselves: the nodes that actually switch in and out. (This is the way - * they are recorded in an egg file.) - */ -void MayaNodeDesc:: -check_lods() { - // Walk through the children first. This makes it easier in the below (we - // only have to return in the event of an error). - Children::iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - MayaNodeDesc *child = (*ci); - child->check_lods(); - } - - // Now consider whether this node is an lodGroup. - if (_dag_path != nullptr && - _dag_path->hasFn(MFn::kLodGroup)) { - // This node is a parent lodGroup; its children, therefore, are LOD's. - MStatus status; - MFnDagNode dag_node(*_dag_path, &status); - if (!status) { - status.perror("Couldn't get node from dag path for lodGroup"); - return; - } - - MPlug plug = dag_node.findPlug("threshold", &status); - if (!status) { - status.perror("Couldn't get threshold attributes on lodGroup"); - return; - } - - // There ought to be the one fewer elements in the array than there are - // children of the node. - unsigned int num_elements = plug.numElements(); - unsigned int num_children = _children.size(); - if (num_elements + 1 != num_children) { - mayaegg_cat.warning() - << "Node " << get_name() << " has " << num_elements - << " LOD entries, but " << num_children << " children.\n"; - } - - // Should we also consider cameraMatrix, to transform the LOD's origin? - // It's not clear precisely what this transform matrix means in Maya, so - // we'll wait until we have a sample file that demonstrates its use. - - double switch_out = 0.0; - unsigned int i = 0; - while (i < num_elements && i < num_children) { - MPlug element = plug.elementByLogicalIndex(i); - MayaNodeDesc *child = _children[i]; - - double switch_in; - status = element.getValue(switch_in); - if (!status) { - status.perror("Couldn't get double value from threshold."); - return; - } - - child->_is_lod = true; - child->_switch_in = switch_in; - child->_switch_out = switch_out; - - switch_out = switch_in; - ++i; - } - - while (i < num_children) { - // Also set the last child(ren). Maya wants this to switch in at - // infinity, but Panda doesn't have such a concept; we'll settle for - // four times the switch_out distance. - MayaNodeDesc *child = _children[i]; - child->_is_lod = true; - child->_switch_in = switch_out * 4.0; - child->_switch_out = switch_out; - - ++i; - } - } -} diff --git a/pandatool/src/mayaegg/mayaNodeDesc.h b/pandatool/src/mayaegg/mayaNodeDesc.h deleted file mode 100644 index f4123ee9a2d..00000000000 --- a/pandatool/src/mayaegg/mayaNodeDesc.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaNodeDesc.h - * @author drose - * @date 2003-06-06 - */ - -#ifndef MAYANODEDESC_H -#define MAYANODEDESC_H - -#include "pandatoolbase.h" - -#include "mayaBlendDesc.h" -#include "referenceCount.h" -#include "pointerTo.h" -#include "namable.h" - -#include "pre_maya_include.h" -#include -#include -#include "post_maya_include.h" - -class MayaToEggConverter; -class MayaNodeTree; -class EggGroup; -class EggTable; -class EggXfmSAnim; - -/** - * Describes a single instance of a node in the Maya scene graph, relating it - * to the corresponding egg structures (e.g. node, group, or table entry) - * that will be created. - */ -class MayaNodeDesc : public ReferenceCount, public Namable { -public: - MayaNodeDesc(MayaNodeTree *tree, - MayaNodeDesc *parent = nullptr, const std::string &name = std::string()); - ~MayaNodeDesc(); - - void from_dag_path(const MDagPath &dag_path, MayaToEggConverter *converter); - bool has_dag_path() const; - const MDagPath &get_dag_path() const; - - int get_num_blend_descs() const; - MayaBlendDesc *get_blend_desc(int n) const; - - bool is_joint() const; - bool is_joint_parent() const; - - bool is_tagged() const; - bool is_joint_tagged() const; - bool has_object_type(std::string object_type) const; - - MayaNodeTree *_tree; - MayaNodeDesc *_parent; - typedef pvector< PT(MayaNodeDesc) > Children; - Children _children; - -private: - void tag(); - void untag(); - void tag_recursively(); - void untag_recursively(); - void tag_joint(); - void tag_joint_recursively(); - - void clear_egg(); - void mark_joint_parent(); - void check_pseudo_joints(bool joint_above); - void check_blend_shapes(const MFnDagNode &node, - const std::string &attrib_name); - void check_lods(); - - MDagPath *_dag_path; - - EggGroup *_egg_group; - EggTable *_egg_table; - EggXfmSAnim *_anim; - - typedef pvector< PT(MayaBlendDesc) > BlendDescs; - BlendDescs _blend_descs; - - enum JointType { - JT_none, // Not a joint. - JT_joint, // An actual joint in Maya. - JT_pseudo_joint, // Not a joint in Maya, but treated just like a - // joint for the purposes of the converter. - JT_joint_parent, // A parent or ancestor of a joint or pseudo joint. - }; - JointType _joint_type; - - bool _is_lod; - double _switch_in, _switch_out; - - bool _tagged; - bool _joint_tagged; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - ReferenceCount::init_type(); - Namable::init_type(); - register_type(_type_handle, "MayaNodeDesc", - ReferenceCount::get_class_type(), - Namable::get_class_type()); - } - -private: - static TypeHandle _type_handle; - - friend class MayaNodeTree; -}; - -#endif diff --git a/pandatool/src/mayaegg/mayaNodeTree.cxx b/pandatool/src/mayaegg/mayaNodeTree.cxx deleted file mode 100644 index 977fec29254..00000000000 --- a/pandatool/src/mayaegg/mayaNodeTree.cxx +++ /dev/null @@ -1,634 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaNodeTree.cxx - * @author drose - * @date 2003-06-06 - */ - -#include "mayaNodeTree.h" -#include "mayaBlendDesc.h" -#include "mayaEggGroupUserData.h" -#include "mayaToEggConverter.h" -#include "config_mayaegg.h" -#include "maya_funcs.h" -#include "eggGroup.h" -#include "eggTable.h" -#include "eggXfmSAnim.h" -#include "eggSAnimData.h" -#include "eggData.h" -#include "eggSwitchCondition.h" -#include "dcast.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include "post_maya_include.h" - -#include - -using std::string; - -/** - * - */ -MayaNodeTree:: -MayaNodeTree(MayaToEggConverter *converter) : - _converter(converter) -{ - _root = new MayaNodeDesc(this); - _fps = 0.0; - _egg_data = nullptr; - _egg_root = nullptr; - _skeleton_node = nullptr; - _morph_node = nullptr; -} - -/** - * Returns a pointer to the node corresponding to the indicated dag_path - * object, creating it first if necessary. - */ -MayaNodeDesc *MayaNodeTree:: -build_node(const MDagPath &dag_path) { - MayaNodeDesc *node_desc = r_build_node(dag_path.fullPathName().asChar()); - node_desc->from_dag_path(dag_path, _converter); - return node_desc; -} - -/** - * Walks through the complete Maya hierarchy but does not tag any nodes for - * conversion. - */ -bool MayaNodeTree:: -build_hierarchy() { - MStatus status; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - return false; - } - - /* - // this is how you can reset the traverser to a specific node - status = dag_iterator.reset(dag_iterator.item(),MItDag::kDepthFirst, MFn::kTransform); - */ - // Get the entire Maya scene. - - // This while loop walks through the entire Maya hierarchy, one node at a - // time. Maya's MItDag object automatically performs a depth-first - // traversal of its scene graph. - - bool all_ok = true; - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - } else { - build_node(dag_path); - } - - dag_iterator.next(); - } - - if (all_ok) { - _root->check_pseudo_joints(false); - _root->check_lods(); - } - - return all_ok; -} - -/** - * Tags the entire hierarchy for conversion. This is the normal behavior. - */ -void MayaNodeTree:: -tag_joint_all() { - _root->tag_joint_recursively(); -} - -/** - * Tags nodes matching the indicated glob (and all of their children) for - * conversion. Returns true on success, false otherwise (e.g. the named node - * does not exist). - */ -bool MayaNodeTree:: -tag_joint_named(const GlobPattern &glob) { - // There might be multiple nodes matching the name; search for all of them. - bool found_any = false; - - Nodes::iterator ni; - for (ni = _nodes.begin(); ni != _nodes.end(); ++ni) { - MayaNodeDesc *node = (*ni); - if (glob.matches(node->get_name())) { - node->tag_joint_recursively(); - found_any = true; - } - } - - return found_any; -} - -/** - * Tags the entire hierarchy for conversion. This is the normal behavior. - */ -void MayaNodeTree:: -tag_all() { - _root->tag_recursively(); -} - -/** - * Tags nodes matching the indicated glob (and all of their children) for - * conversion. Returns true on success, false otherwise (e.g. the named node - * does not exist). - */ -bool MayaNodeTree:: -tag_named(const GlobPattern &glob) { - // There might be multiple nodes matching the name; search for all of them. - bool found_any = false; - - Nodes::iterator ni; - for (ni = _nodes.begin(); ni != _nodes.end(); ++ni) { - MayaNodeDesc *node = (*ni); - if (glob.matches(node->get_name())) { - node->tag_recursively(); - found_any = true; - } - } - - return found_any; -} - -/** - * Un-tags nodes matching the indicated glob (and all of their children) for - * conversion. Returns true on success, false otherwise (e.g. the named node - * does not exist). - */ -bool MayaNodeTree:: -untag_named(const GlobPattern &glob) { - // There might be multiple nodes matching the name; search for all of them. - bool found_any = false; - - Nodes::iterator ni; - for (ni = _nodes.begin(); ni != _nodes.end(); ++ni) { - MayaNodeDesc *node = (*ni); - if (glob.matches(node->get_name())) { - node->untag_recursively(); - found_any = true; - } - } - - return found_any; -} - -/** - * Tags the just the selected hierarchy for conversion, or the entire - * hierarchy if nothing is selected. Returns true on success, false on - * failure. - */ -bool MayaNodeTree:: -tag_selected() { - MStatus status; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - return false; - } - - MSelectionList selection; - status = MGlobal::getActiveSelectionList(selection); - if (!status) { - status.perror("MGlobal::getActiveSelectionList"); - return false; - } - - if (selection.isEmpty()) { - mayaegg_cat.info() - << "Selection list is empty.\n"; - tag_all(); - return true; - } - - bool all_ok = true; - unsigned int length = selection.length(); - for (unsigned int i = 0; i < length; i++) { - MDagPath root_path; - status = selection.getDagPath(i, root_path); - if (!status) { - status.perror("MSelectionList::getDagPath"); - } else { - // Now traverse through the selected dag path and all nested dag paths. - dag_iterator.reset(root_path); - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - } else { - build_node(dag_path)->tag(); - } - - dag_iterator.next(); - } - } - } - - if (all_ok) { - _root->check_pseudo_joints(false); - } - - return all_ok; -} - -/** - * Returns the total number of nodes in the hierarchy, not counting the root - * node. - */ -int MayaNodeTree:: -get_num_nodes() const { - return _nodes.size(); -} - -/** - * Returns the nth node in the hierarchy, in an arbitrary ordering. - */ -MayaNodeDesc *MayaNodeTree:: -get_node(int n) const { - nassertr(n >= 0 && n < (int)_nodes.size(), nullptr); - return _nodes[n]; -} - -/** - * Resets the entire tree in preparation for repopulating with a new scene. - */ -void MayaNodeTree:: -clear() { - _root = new MayaNodeDesc(this); - _fps = 0.0; - _egg_data = nullptr; - _egg_root = nullptr; - _skeleton_node = nullptr; - _morph_node = nullptr; - _nodes_by_path.clear(); - _nodes.clear(); -} - -/** - * Removes all of the references to generated egg structures from the tree, - * and prepares the tree for generating new egg structures. - */ -void MayaNodeTree:: -clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node, EggGroupNode *morph_node) { - _root->clear_egg(); - BlendDescs::iterator bi; - for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) { - (*bi)->clear_egg(); - } - - _egg_data = egg_data; - _egg_root = egg_root; - _skeleton_node = skeleton_node; - _morph_node = morph_node; -} - -/** - * Returns the EggGroupNode corresponding to the group or joint for the - * indicated node. Creates the group node if it has not already been created. - */ -EggGroup *MayaNodeTree:: -get_egg_group(MayaNodeDesc *node_desc) { - nassertr(_egg_root != nullptr, nullptr); - - if (node_desc->_egg_group == nullptr) { - // We need to make a new group node. - EggGroup *egg_group; - - nassertr(node_desc->_parent != nullptr, nullptr); - egg_group = new EggGroup(node_desc->get_name()); - if (node_desc->is_joint()) { - if (_converter->get_animation_convert() == AC_model || - _converter->get_animation_convert() == AC_both) { - egg_group->set_group_type(EggGroup::GT_joint); - } - } - - MayaEggGroupUserData *parent_user_data = nullptr; - - if (node_desc->_parent == _root) { - // The parent is the root. - _egg_root->add_child(egg_group); - - } else { - // The parent is another node. - EggGroup *parent_egg_group = get_egg_group(node_desc->_parent); - parent_egg_group->add_child(egg_group); - - if (parent_egg_group->has_user_data()) { - DCAST_INTO_R(parent_user_data, parent_egg_group->get_user_data(), nullptr); - } - } - - if (node_desc->has_dag_path()) { - // Check for an object type setting, from Oliver's plug-in. - MObject dag_object = node_desc->get_dag_path().node(); - string object_type; - LVector3d value; - - for (unsigned int i = 1; ; i++) { - std::ostringstream attr; - attr << "eggObjectTypes" << i; - - if (!get_enum_attribute(dag_object, attr.str(), object_type)) { - if (i < 3) { - // Support out-of-order legacy object types. - continue; - } - - // We have run out of object types to add. - break; - } - - egg_group->add_object_type(object_type); - } - - if(has_attribute(dag_object, "scrollUV")) { - if(get_vec3d_attribute(dag_object, "scrollUV", value)) { - egg_group->set_scroll_u(value[0]); - egg_group->set_scroll_v(value[1]); - egg_group->set_scroll_r(value[2]); - } - } - - pvector tag_attribute_names; - get_tag_attribute_names(dag_object, tag_attribute_names); - for (unsigned int ti=0; ti < tag_attribute_names.size(); ti++) { - if (get_enum_attribute(dag_object, tag_attribute_names[ti], object_type)) { - egg_group->set_tag(tag_attribute_names[ti].substr(3), object_type); - } - } - - // Is the node flagged to be invisible? If it is, it is tagged with the - // "hidden" visibility flag, so it won't get converted in the normal - // case (unless it represents a collision solid or something). - bool visible = true; - get_bool_attribute(dag_object, "visibility", visible); - if (!visible && egg_group->get_num_object_types() == 0) { - egg_group->set_visibility_mode(EggGroup::VM_hidden); - } - - // We treat the object type "billboard" as a special case: we apply this - // one right away and also flag the group as an instance. - if (egg_group->has_object_type("billboard")) { - egg_group->remove_object_type("billboard"); - egg_group->set_group_type(EggGroup::GT_instance); - egg_group->set_billboard_type(EggGroup::BT_axis); - - } else if (egg_group->has_object_type("billboard-point")) { - egg_group->remove_object_type("billboard-point"); - egg_group->set_group_type(EggGroup::GT_instance); - egg_group->set_billboard_type(EggGroup::BT_point_camera_relative); - - } else if (egg_group->has_object_type("bbpoint")) { - egg_group->remove_object_type("bbpoint"); - egg_group->set_group_type(EggGroup::GT_instance); - egg_group->set_billboard_type(EggGroup::BT_point_camera_relative); - } - - // We also treat the object type "dcs" and "model" as a special case, so - // we can test for these flags later. - if (egg_group->has_object_type("dcs")) { - egg_group->remove_object_type("dcs"); - egg_group->set_dcs_type(EggGroup::DC_default); - } - if (egg_group->has_object_type("model")) { - egg_group->remove_object_type("model"); - egg_group->set_model_flag(true); - } - - // And "vertex-color" and "double-sided" have meaning only to this - // converter. - MayaEggGroupUserData *user_data; - if (parent_user_data == nullptr) { - user_data = new MayaEggGroupUserData; - } else { - // Inherit the flags from above. - user_data = new MayaEggGroupUserData(*parent_user_data); - } - - if (egg_group->has_object_type("vertex-color")) { - egg_group->remove_object_type("vertex-color"); - user_data->_vertex_color = true; - } - if (egg_group->has_object_type("double-sided")) { - egg_group->remove_object_type("double-sided"); - user_data->_double_sided = true; - } - egg_group->set_user_data(user_data); - } - - if (node_desc->_is_lod) { - // Create an LOD specification. - egg_group->set_lod(EggSwitchConditionDistance(node_desc->_switch_in, - node_desc->_switch_out, - LPoint3d::zero())); - } - - node_desc->_egg_group = egg_group; - } - - return node_desc->_egg_group; -} - -/** - * Returns the EggTable corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggTable *MayaNodeTree:: -get_egg_table(MayaNodeDesc *node_desc) { - nassertr(_skeleton_node != nullptr, nullptr); - nassertr(node_desc->is_joint(), nullptr); - - if (node_desc->_egg_table == nullptr) { - // We need to make a new table node. - nassertr(node_desc->_parent != nullptr, nullptr); - - EggTable *egg_table = new EggTable(node_desc->get_name()); - node_desc->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system()); - node_desc->_anim->set_fps(_fps); - egg_table->add_child(node_desc->_anim); - - if (!node_desc->_parent->is_joint()) { - // The parent is not a joint; put it at the top. - _skeleton_node->add_child(egg_table); - - } else { - // The parent is another joint. - EggTable *parent_egg_table = get_egg_table(node_desc->_parent); - parent_egg_table->add_child(egg_table); - } - - node_desc->_egg_table = egg_table; - } - - return node_desc->_egg_table; -} - -/** - * Returns the anim table corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggXfmSAnim *MayaNodeTree:: -get_egg_anim(MayaNodeDesc *node_desc) { - get_egg_table(node_desc); - return node_desc->_anim; -} - -/** - * Returns the anim table corresponding to the slider for the indicated blend. - * Creates the table node if it has not already been created. - */ -EggSAnimData *MayaNodeTree:: -get_egg_slider(MayaBlendDesc *blend_desc) { - nassertr(_morph_node != nullptr, nullptr); - - if (blend_desc->_anim == nullptr) { - // We need to make a new anim table. - EggSAnimData *egg_anim = new EggSAnimData(blend_desc->get_name()); - egg_anim->set_fps(_fps); - _morph_node->add_child(egg_anim); - - blend_desc->_anim = egg_anim; - } - - return blend_desc->_anim; -} - -/** - * Returns true if the indicated name is on the list of sliders to ignore, - * false otherwise. - */ -bool MayaNodeTree:: -ignore_slider(const string &name) const { - return _converter->ignore_slider(name); -} - -/** - * Outputs a message to the user reporting that a slider was ignored. Each - * slider is only reported once. - */ -void MayaNodeTree:: -report_ignored_slider(const string &name) { - if (_ignored_slider_names.insert(name).second) { - mayaegg_cat.info() - << "Ignoring slider " << name << "\n"; - } -} - -/** - * Adds the indicated MayaBlendDesc object to the list of blends collected so - * far. If a MayaBlendDesc object with the same name is already part of the - * tree, the supplied object is discarded and the previously-added object is - * returned; otherwise, the supplied object is added to the tree and the same - * object is returned. - * - * In either case, the return value is the MayaBlendDesc that should be used - * henceforth. - */ -MayaBlendDesc *MayaNodeTree:: -add_blend_desc(MayaBlendDesc *blend_desc) { - BlendDescs::iterator bi = _blend_descs.insert(blend_desc).first; - - return (*bi); -} - -/** - * Returns the number of unique MayaBlendDesc objects (and hence the number of - * morph sliders) discovered in the tree. - */ -int MayaNodeTree:: -get_num_blend_descs() const { - return _blend_descs.size(); -} - -/** - * Returns the nth MayaBlendDesc object discovered in the tree. - */ -MayaBlendDesc *MayaNodeTree:: -get_blend_desc(int n) const { - nassertr(n >= 0 && n < (int)_blend_descs.size(), nullptr); - return _blend_descs[n]; -} - -/** - * Resets all of the sliders associated with all blend shapes down to 0. - */ -void MayaNodeTree:: -reset_sliders() { - BlendDescs::iterator bi; - for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) { - (*bi)->set_slider(0.0); - } -} - - -/** - * The recursive implementation of build_node(). - */ -MayaNodeDesc *MayaNodeTree:: -r_build_node(const string &path) { - // If we have already encountered this pathname, return the corresponding - // MayaNodeDesc immediately. - NodesByPath::const_iterator ni = _nodes_by_path.find(path); - if (ni != _nodes_by_path.end()) { - return (*ni).second; - } - - // Otherwise, we have to create it. Do this recursively, so we create each - // node along the path. - MayaNodeDesc *node_desc = nullptr; - - // mayaegg_cat.info() << "path: " << path << endl; - if (path.empty()) { - // This is the top. mayaegg_cat.info() << "found empty path: " << path << - // endl; - node_desc = _root; - - } else { - // Maya uses vertical bars to separate path components. Remove everything - // from the rightmost bar on; this will give us the parent's path name. - size_t bar = path.rfind("|"); - string parent_path, local_name; - if (bar != string::npos) { - parent_path = path.substr(0, bar); - // mayaegg_cat.info() << "parent_path: " << parent_path << endl; - local_name = path.substr(bar + 1); - if (local_name == _subroot_parent_name) { - node_desc = _root; - } - } else { - local_name = path; - } - // mayaegg_cat.info() << "local_name: " << local_name << endl; - - if (node_desc != _root) { - MayaNodeDesc *parent_node_desc = r_build_node(parent_path); - if (parent_node_desc == nullptr) - mayaegg_cat.info() << "empty parent: " << local_name << std::endl; - node_desc = new MayaNodeDesc(this, parent_node_desc, local_name); - _nodes.push_back(node_desc); - } - } - - _nodes_by_path.insert(NodesByPath::value_type(path, node_desc)); - return node_desc; -} diff --git a/pandatool/src/mayaegg/mayaNodeTree.h b/pandatool/src/mayaegg/mayaNodeTree.h deleted file mode 100644 index e355c45ff3a..00000000000 --- a/pandatool/src/mayaegg/mayaNodeTree.h +++ /dev/null @@ -1,100 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaNodeTree.h - * @author drose - * @date 2003-06-06 - */ - -#ifndef MAYANODETREE_H -#define MAYANODETREE_H - -#include "pandatoolbase.h" - -#include "mayaNodeDesc.h" -#include "mayaBlendDesc.h" -#include "globPattern.h" -#include "indirectCompareNames.h" -#include "ordered_vector.h" -#include "pset.h" -#include "pmap.h" - -class MayaToEggConverter; -class EggData; -class EggGroupNode; -class EggTable; -class EggXfmSAnim; -class EggSAnimData; - -/** - * Describes a complete tree of maya nodes for conversion. - */ -class MayaNodeTree { -public: - MayaNodeTree(MayaToEggConverter *converter); - MayaNodeDesc *build_node(const MDagPath &dag_path); - bool build_hierarchy(); - - void tag_joint_all(); - // bool tag_joint_selected(); - bool tag_joint_named(const GlobPattern &glob); - - void tag_all(); - bool tag_selected(); - bool tag_named(const GlobPattern &glob); - bool untag_named(const GlobPattern &glob); - - int get_num_nodes() const; - MayaNodeDesc *get_node(int n) const; - - void clear(); - void clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node, EggGroupNode *morph_node); - EggGroup *get_egg_group(MayaNodeDesc *node_desc); - EggTable *get_egg_table(MayaNodeDesc *node_desc); - EggXfmSAnim *get_egg_anim(MayaNodeDesc *node_desc); - EggSAnimData *get_egg_slider(MayaBlendDesc *blend_desc); - - bool ignore_slider(const std::string &name) const; - void report_ignored_slider(const std::string &name); - - MayaBlendDesc *add_blend_desc(MayaBlendDesc *blend_desc); - int get_num_blend_descs() const; - MayaBlendDesc *get_blend_desc(int n) const; - - void reset_sliders(); - -public: - std::string _subroot_parent_name; - PT(MayaNodeDesc) _root; - PN_stdfloat _fps; - -private: - MayaNodeDesc *r_build_node(const std::string &path); - - MayaToEggConverter *_converter; - - EggData *_egg_data; - EggGroupNode *_egg_root; - EggGroupNode *_skeleton_node; - EggGroupNode *_morph_node; - - typedef pmap NodesByPath; - NodesByPath _nodes_by_path; - - typedef pvector Nodes; - Nodes _nodes; - - typedef ov_set > BlendDescs; - BlendDescs _blend_descs; - - typedef pset Strings; - Strings _ignored_slider_names; -}; - -#endif diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx deleted file mode 100644 index 3f693dd0045..00000000000 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ /dev/null @@ -1,3221 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaToEggConverter.cxx - * @author drose - * @date 1999-11-10 - * Modified 19Mar10 by ETC PandaSE team - * Added set_vertex_color_modern to fix Phong shader bug; also see - * header comment for mayaToEgg.cxx for more details - */ - -#include "mayaToEggConverter.h" -#include "mayaShader.h" -#include "maya_funcs.h" -#include "config_mayaegg.h" -#include "mayaEggGroupUserData.h" - -#include "eggData.h" -#include "eggGroup.h" -#include "eggTable.h" -#include "eggVertex.h" -#include "eggVertexPool.h" -#include "eggNurbsSurface.h" -#include "eggNurbsCurve.h" -#include "eggPolygon.h" -#include "eggPrimitive.h" -#include "eggTexture.h" -#include "eggTextureCollection.h" -#include "eggXfmSAnim.h" -#include "eggSAnimData.h" -#include "string_utils.h" -#include "dcast.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -using std::endl; -using std::string; - - -/** - * - */ -MayaToEggConverter:: -MayaToEggConverter(const string &program_name) : - _program_name(program_name), - _tree(this) -{ - // Make sure the library is properly initialized. - init_libmayaegg(); - - _from_selection = false; - - _polygon_output = false; - _polygon_tolerance = 0.01; - _respect_maya_double_sided = maya_default_double_sided; - _always_show_vertex_color = maya_default_vertex_color; - _keep_all_uvsets = false; - _round_uvs = false; - _legacy_shader = false; - _convert_cameras = false; - _convert_lights = false; - - _transform_type = TT_model; -} - -/** - * - */ -MayaToEggConverter:: -MayaToEggConverter(const MayaToEggConverter ©) : - _program_name(copy._program_name), - _from_selection(copy._from_selection), - _subsets(copy._subsets), - _subroots(copy._subroots), - _excludes(copy._excludes), - _ignore_sliders(copy._ignore_sliders), - _force_joints(copy._force_joints), - _tree(this), - _maya(copy._maya), - _polygon_output(copy._polygon_output), - _polygon_tolerance(copy._polygon_tolerance), - _respect_maya_double_sided(copy._respect_maya_double_sided), - _always_show_vertex_color(copy._always_show_vertex_color), - _keep_all_uvsets(copy._keep_all_uvsets), - _convert_cameras(copy._convert_cameras), - _convert_lights(copy._convert_lights), - _round_uvs(copy._round_uvs), - _legacy_shader(copy._legacy_shader), - _transform_type(copy._transform_type) -{ -} - -/** - * - */ -MayaToEggConverter:: -~MayaToEggConverter() { - close_api(); -} - -/** - * Allocates and returns a new copy of the converter. - */ -SomethingToEggConverter *MayaToEggConverter:: -make_copy() { - return new MayaToEggConverter(*this); -} - -/** - * Returns the English name of the file type this converter supports. - */ -string MayaToEggConverter:: -get_name() const { - return "Maya"; -} - -/** - * Returns the common extension of the file type this converter supports. - */ -string MayaToEggConverter:: -get_extension() const { - return "mb"; -} - -/** - * Returns a space-separated list of extension, in addition to the one - * returned by get_extension(), that are recognized by this converter. - */ -string MayaToEggConverter:: -get_additional_extensions() const { - return "ma"; -} - -/** - * Handles the reading of the input file and converting it to egg. Returns - * true if successful, false otherwise. - * - * This is designed to be as generic as possible, generally in support of run- - * time loading. Also see convert_maya(). - */ -bool MayaToEggConverter:: -convert_file(const Filename &filename) { - if (!open_api()) { - mayaegg_cat.error() - << "Maya is not available.\n"; - return false; - } - - // We must ensure our Maya pointers are cleared before we reset the Maya - // scene, because resetting the Maya scene will invalidate all the Maya - // pointers we are holding and cause a crash if we try to free them later. - clear(); - - if (!_maya->read(filename)) { - mayaegg_cat.error() - << "Unable to read " << filename << "\n"; - return false; - } - - if (_character_name.empty()) { - _character_name = filename.get_basename_wo_extension(); - } - - return convert_maya(); -} - -/** - * Empties the list of subroot nodes added via add_subroot(). The entire file - * will once again be converted. - */ -void MayaToEggConverter:: -clear_subroots() { - _subroots.clear(); -} - -/** - * Adds a name pattern to the list of subroot nodes. If the list of subroot - * nodes is not empty, then only a subroot of the nodes in the maya file will - * be converted: those whose names match one of the patterns given on this - * list. - */ -void MayaToEggConverter:: -add_subroot(const GlobPattern &glob) { - _subroots.push_back(glob); -} - -/** - * Empties the list of subset nodes added via add_subset(). The entire file - * will once again be converted. - */ -void MayaToEggConverter:: -clear_subsets() { - _subsets.clear(); -} - -/** - * Adds a name pattern to the list of subset nodes. If the list of subset - * nodes is not empty, then only a subset of the nodes in the maya file will - * be converted: those whose names match one of the patterns given on this - * list. - */ -void MayaToEggConverter:: -add_subset(const GlobPattern &glob) { - _subsets.push_back(glob); -} - -/** - * Empties the list of excluded nodes added via add_exclude(). - */ -void MayaToEggConverter:: -clear_excludes() { - _excludes.clear(); -} - -/** - * Adds a name pattern to the list of excluded nodes. - */ -void MayaToEggConverter:: -add_exclude(const GlobPattern &glob) { - _excludes.push_back(glob); -} - -/** - * Empties the list of ignore_sliders added via add_ignore_slider(). No - * sliders will be ignored. - */ -void MayaToEggConverter:: -clear_ignore_sliders() { - _ignore_sliders.clear(); -} - -/** - * Adds a name pattern to the list of ignore_sliders. Any slider (blend shape - * deformer) that matches a name on the list will not be converted or - * otherwise molested by the converter. This is occasionally necessary to - * filter out automatically-created sliders that are not intended to be used - * directly, but instead have an indirect effect on other sliders. - */ -void MayaToEggConverter:: -add_ignore_slider(const GlobPattern &glob) { - _ignore_sliders.push_back(glob); -} - -/** - * Returns true if the indicated name is on the list of sliders to ignore, - * false otherwise. - */ -bool MayaToEggConverter:: -ignore_slider(const string &name) const { - Globs::const_iterator gi; - for (gi = _ignore_sliders.begin(); gi != _ignore_sliders.end(); ++gi) { - if ((*gi).matches(name)) { - return true; - } - } - - return false; -} - -/** - * Empties the list of force_joints added via add_force_joint(). No joints - * will be forced. - */ -void MayaToEggConverter:: -clear_force_joints() { - _force_joints.clear(); -} - -/** - * Adds a name pattern to the list of force_joints. - * - * Any DAG node that matches a name on the list will be treated as if it were - * a joint during the conversion process; it will receive animation and - * position information. Normally, a true Maya joint, as well as any DAG - * nodes whose transforms are animated, will automatically be flagged as a - * Panda joint. - */ -void MayaToEggConverter:: -add_force_joint(const GlobPattern &glob) { - _force_joints.push_back(glob); -} - -/** - * Returns true if the indicated name is on the list of DAG nodes to treat as - * a joint, false otherwise. - */ -bool MayaToEggConverter:: -force_joint(const string &name) const { - Globs::const_iterator gi; - for (gi = _force_joints.begin(); gi != _force_joints.end(); ++gi) { - if ((*gi).matches(name)) { - return true; - } - } - - return false; -} - -/** - * Sets the flag that indicates whether the currently selected Maya geometry - * will be converted. If this is true, and the selection is nonempty, then - * only the selected geometry will be converted. If this is false, the entire - * file will be converted. - */ -void MayaToEggConverter:: -set_from_selection(bool from_selection) { - _from_selection = from_selection; -} - -/** - * This may be called after convert_file() has been called and returned true, - * indicating a successful conversion. It will return the distance units - * represented by the converted egg file, if known, or DU_invalid if not - * known. - */ -DistanceUnit MayaToEggConverter:: -get_input_units() { - return _maya->get_units(); -} - -/** - * Fills up the egg_data structure according to the global maya model data. - * Returns true if successful, false if there is an error. - */ -bool MayaToEggConverter:: -convert_maya() { - clear(); - clear_error(); - - if (!open_api()) { - mayaegg_cat.error() - << "Maya is not available.\n"; - return false; - } - - if (_egg_data->get_coordinate_system() == CS_default) { - _egg_data->set_coordinate_system(_maya->get_coordinate_system()); - } - - mayaegg_cat.info() - << "Converting from Maya.\n"; - - // Figure out the animation parameters. - double start_frame, end_frame, frame_inc, input_frame_rate, output_frame_rate; - if (has_start_frame()) { - start_frame = get_start_frame(); - } else { - start_frame = MAnimControl::minTime().value(); - } - if (has_end_frame()) { - end_frame = get_end_frame(); - } else { - end_frame = MAnimControl::maxTime().value(); - // end_frame = MAnimControl::animationEndTime().value(); masad: we could - // use this - } - if (has_frame_inc()) { - frame_inc = get_frame_inc(); - } else { - frame_inc = 1.0; - } - if (has_input_frame_rate()) { - input_frame_rate = get_input_frame_rate(); - } else { - MTime time(1.0, MTime::kSeconds); - input_frame_rate = time.as(MTime::uiUnit()); - } - if (has_output_frame_rate()) { - output_frame_rate = get_output_frame_rate(); - } else { - output_frame_rate = input_frame_rate; - } - - frame_inc = frame_inc * input_frame_rate / output_frame_rate; - - bool all_ok = _tree.build_hierarchy(); - - if (all_ok) { - if (!_subroots.empty()) { - Globs::const_iterator gi; - for (gi = _subroots.begin(); gi != _subroots.end(); ++gi) { - if (!_tree.tag_joint_named(*gi)) { - mayaegg_cat.info() - << "No node matching " << *gi << " found.\n"; - } - } - - } else { - // This call makes every node a potential joint; but it does not - // necessarily force nodes to be joints. - _tree.tag_joint_all(); - } - } - - if (all_ok) { - if (_from_selection) { - all_ok = _tree.tag_selected(); - } else if (!_subsets.empty()) { - Globs::const_iterator gi; - for (gi = _subsets.begin(); gi != _subsets.end(); ++gi) { - if (!_tree.tag_named(*gi)) { - mayaegg_cat.info() - << "No node matching " << *gi << " found.\n"; - } - } - - } else { - _tree.tag_all(); - } - } - - if (all_ok) { - if (!_excludes.empty()) { - Globs::const_iterator gi; - for (gi = _excludes.begin(); gi != _excludes.end(); ++gi) { - if (!_tree.untag_named(*gi)) { - mayaegg_cat.info() - << "No node matching " << *gi << " found.\n"; - } - } - } - } - - if (all_ok) { - switch (get_animation_convert()) { - case AC_pose: - // pose: set to a specific frame, then get out the static geometry. - mayaegg_cat.info(false) - << "frame " << start_frame << "\n"; - MGlobal::viewFrame(MTime(start_frame, MTime::uiUnit())); - // fall through - - case AC_none: - // none: just get out a static model, no animation. - mayaegg_cat.info() << "ac_none" << endl; - all_ok = convert_hierarchy(get_egg_data()); - break; - - case AC_flip: - case AC_strobe: - // flip or strobe: get out a series of static models, one per frame, - // under a sequence node for AC_flip. - all_ok = convert_flip(start_frame, end_frame, frame_inc, - output_frame_rate); - break; - - case AC_model: - // model: get out an animatable model with joints and vertex membership. - all_ok = convert_char_model(); - break; - - case AC_chan: - // chan: get out a series of animation tables. - all_ok = convert_char_chan(start_frame, end_frame, frame_inc, - output_frame_rate); - break; - - case AC_both: - // both: Put a model and its animation into the same egg file. - _animation_convert = AC_model; - if (!convert_char_model()) { - all_ok = false; - } - _animation_convert = AC_chan; - if (!convert_char_chan(start_frame, end_frame, frame_inc, - output_frame_rate)) { - all_ok = false; - } - break; - - case AC_invalid: - break; - }; - - reparent_decals(get_egg_data()); - } - - if (had_error()) { - all_ok = false; - } - - if (all_ok) { - mayaegg_cat.info() - << "Converted, no errors.\n"; - } else { - mayaegg_cat.info() - << "Errors encountered in conversion.\n"; - } - - return all_ok; -} - -/** - * Attempts to open the Maya API if it was not already open, and returns true - * if successful, or false if there is an error. - */ -bool MayaToEggConverter:: -open_api(bool revert_directory) { - - if (_maya == nullptr || !_maya->is_valid()) { - // maya to egg converter only needs a read license. only egg2maya need - // write lisences. - _maya = MayaApi::open_api(_program_name, true, revert_directory); - } - return _maya->is_valid(); -} - -/** - * Closes the Maya API, if it was previously opened. Caution! Maya appears - * to call exit() when its API is closed. - */ -void MayaToEggConverter:: -close_api() { - // We have to clear the shaders, at least, before we release the Maya API. - clear(); - _maya.clear(); -} - -/** - * Frees all of the Maya pointers kept within this object, in preparation for - * loading a new scene or releasing the Maya API. - */ -void MayaToEggConverter:: -clear() { - _tree.clear(); - _textures.clear(); - _shaders.clear(); -} - -/** - * Converts the animation as a series of models that cycle (flip) from one to - * the next at the appropriate frame rate. This is the most likely to convert - * precisely (since we ask Maya to tell us the vertex position each time) but - * it is the most wasteful in terms of memory utilization (since a complete of - * the model is stored for each frame). - */ -bool MayaToEggConverter:: -convert_flip(double start_frame, double end_frame, double frame_inc, - double output_frame_rate) { - bool all_ok = true; - - EggGroup *sequence_node = new EggGroup(_character_name); - get_egg_data()->add_child(sequence_node); - if (_animation_convert == AC_flip) { - sequence_node->set_switch_flag(true); - sequence_node->set_switch_fps(output_frame_rate); - } - - MTime frame(start_frame, MTime::uiUnit()); - MTime frame_stop(end_frame, MTime::uiUnit()); - while (frame <= frame_stop) { - mayaegg_cat.info(false) - << "frame " << frame.value() << "\n"; - std::ostringstream name_strm; - name_strm << "frame" << frame.value(); - EggGroup *frame_root = new EggGroup(name_strm.str()); - sequence_node->add_child(frame_root); - - MGlobal::viewFrame(frame); - if (!convert_hierarchy(frame_root)) { - all_ok = false; - } - - frame += frame_inc; - } - - return all_ok; -} - -/** - * Converts the file as an animatable character model, with joints and vertex - * membership. - */ -bool MayaToEggConverter:: -convert_char_model() { - if (has_neutral_frame()) { - MTime frame(get_neutral_frame(), MTime::uiUnit()); - mayaegg_cat.info(false) - << "neutral frame " << frame.value() << "\n"; - MGlobal::viewFrame(frame); - } - - // It's also important for us to reset all the blend shape sliders to 0 - // before we get out the model. Otherwise, the model we convert will have - // the current positions of the sliders baked in. - _tree.reset_sliders(); - - EggGroup *char_node = new EggGroup(_character_name); - get_egg_data()->add_child(char_node); - char_node->set_dart_type(EggGroup::DT_default); - - return convert_hierarchy(char_node); -} - -/** - * Converts the animation as a series of tables to apply to the character - * model, as retrieved earlier via AC_model. - */ -bool MayaToEggConverter:: -convert_char_chan(double start_frame, double end_frame, double frame_inc, - double output_frame_rate) { - // MStatus status; - - EggTable *root_table_node = new EggTable(); - get_egg_data()->add_child(root_table_node); - EggTable *bundle_node = new EggTable(_character_name); - bundle_node->set_table_type(EggTable::TT_bundle); - root_table_node->add_child(bundle_node); - EggTable *skeleton_node = new EggTable(""); - bundle_node->add_child(skeleton_node); - EggTable *morph_node = new EggTable("morph"); - bundle_node->add_child(morph_node); - - // Set the frame rate before we start asking for anim tables to be created. - _tree._fps = output_frame_rate; - _tree.clear_egg(get_egg_data(), nullptr, skeleton_node, morph_node); - - // Now we can get the animation data by walking through all of the frames, - // one at a time, and getting the joint angles at each frame. - - // This is just a temporary EggGroup to receive the transform for each joint - // each frame. - PT(EggGroup) tgroup = new EggGroup; - - int num_nodes = _tree.get_num_nodes(); - int num_sliders = _tree.get_num_blend_descs(); - int i; - - MTime frame(start_frame, MTime::uiUnit()); - MTime frame_stop(end_frame, MTime::uiUnit()); - while (frame <= frame_stop) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam(false) - << "frame " << frame.value() << "\n"; - } else { - // We have to write to cerr instead of mayaegg_cat to allow flushing - // without writing a newline. - std::cerr << "." << std::flush; - } - MGlobal::viewFrame(frame); - - for (i = 0; i < num_nodes; i++) { - MayaNodeDesc *node_desc = _tree.get_node(i); - if (node_desc->is_joint()) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() - << "joint " << node_desc->get_name() << "\n"; - } - get_joint_transform(node_desc->get_dag_path(), tgroup); - EggXfmSAnim *anim = _tree.get_egg_anim(node_desc); - if (!anim->add_data(tgroup->get_transform3d())) { - mayaegg_cat.error() - << "Invalid transform on " << node_desc->get_name() - << " frame " << frame.value() << ".\n"; - } - } - } - - for (i = 0; i < num_sliders; i++) { - MayaBlendDesc *blend_desc = _tree.get_blend_desc(i); - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() - << "slider " << blend_desc->get_name() << "\n"; - } - EggSAnimData *anim = _tree.get_egg_slider(blend_desc); - anim->add_data(blend_desc->get_slider()); - } - - frame += frame_inc; - } - - // Now optimize all of the tables we just filled up, for no real good - // reason, except that it makes the resulting egg file a little easier to - // read. - for (i = 0; i < num_nodes; i++) { - MayaNodeDesc *node_desc = _tree.get_node(i); - if (node_desc->is_joint()) { - _tree.get_egg_anim(node_desc)->optimize(); - } - } - - for (i = 0; i < num_sliders; i++) { - MayaBlendDesc *blend_desc = _tree.get_blend_desc(i); - EggSAnimData *anim = _tree.get_egg_slider(blend_desc); - anim->optimize(); - } - - mayaegg_cat.info(false) - << "\n"; - - return true; -} - -/** - * Generates egg structures for each node in the Maya hierarchy. - */ -bool MayaToEggConverter:: -convert_hierarchy(EggGroupNode *egg_root) { - int num_nodes = _tree.get_num_nodes(); - - if (_round_uvs) { - mayaegg_cat.info() << "will round up uv coordinates" << endl; - } - - if (_keep_all_uvsets) { - mayaegg_cat.info() << "will keep_all_uvsets" << endl; - } - if (_polygon_output) { - mayaegg_cat.info() << "will convert NURBS to polys" << endl; - } - if (_convert_cameras) { - mayaegg_cat.info() << "will convert camera nodes to locators" << endl; - } - if (_convert_lights) { - mayaegg_cat.info() << "will convert light nodes to locators" << endl; - } - // give some feedback about whether special options are on - if (_legacy_shader) { - mayaegg_cat.info() << "will disable modern Phong shader path. using legacy" << endl; - } - _tree.clear_egg(get_egg_data(), egg_root, nullptr, nullptr); - for (int i = 0; i < num_nodes; i++) { - MayaNodeDesc *node = _tree.get_node(i); - if (!process_model_node(node)) { - return false; - } - } - return true; -} - -/** - * Converts the indicated Maya node (given a MDagPath, similar in concept to - * Panda's NodePath) to the corresponding Egg structure. Returns true if - * successful, false if an error was encountered. - */ -bool MayaToEggConverter:: -process_model_node(MayaNodeDesc *node_desc) { - if (!node_desc->has_dag_path()) { - // If the node has no Maya equivalent, never mind. - return true; - } - - MDagPath dag_path = node_desc->get_dag_path(); - - MStatus status; - MFnDagNode dag_node(dag_path, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - mayaegg_cat.error() << dag_path.fullPathName().asChar() << "\n"; - return false; - } - - MObject node = dag_path.transform(&status); - if (!status) { - status.perror("dag_path.transform()"); - return false; - } - - string path = dag_path.fullPathName().asChar(); - - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << path << ": " << dag_node.typeName().asChar(); - - if (MAnimUtil::isAnimated(dag_path)) { - mayaegg_cat.debug(false) - << " (animated)"; - } - - mayaegg_cat.debug(false) << "\n"; - } - - if (dag_node.inUnderWorld()) { - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "Ignoring underworld node " << path - << "\n"; - } - - } else if (dag_node.isIntermediateObject()) { - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "Ignoring intermediate object " << path - << "\n"; - } - - } else if (dag_path.hasFn(MFn::kCamera)) { - if (_convert_cameras) { - MFnCamera camera (dag_path, &status); - if ( !status ) { - status.perror("MFnCamera constructor"); - return false; - } - - // Extract some interesting Camera data - if (mayaegg_cat.is_spam()) { - MPoint eyePoint = camera.eyePoint(MSpace::kWorld); - MVector upDirection = camera.upDirection(MSpace::kWorld); - MVector viewDirection = camera.viewDirection(MSpace::kWorld); - mayaegg_cat.spam() << " eyePoint: " << eyePoint.x << " " - << eyePoint.y << " " << eyePoint.z << endl; - mayaegg_cat.spam() << " upDirection: " << upDirection.x << " " - << upDirection.y << " " << upDirection.z << endl; - mayaegg_cat.spam() << " viewDirection: " << viewDirection.x << " " - << viewDirection.y << " " << viewDirection.z << endl; - mayaegg_cat.spam() << " aspectRatio: " << camera.aspectRatio() << endl; - mayaegg_cat.spam() << " horizontalFilmAperture: " - << camera.horizontalFilmAperture() << endl; - mayaegg_cat.spam() << " verticalFilmAperture: " - << camera.verticalFilmAperture() << endl; - } - - EggGroup *egg_group = _tree.get_egg_group(node_desc); - - if (mayaegg_cat.is_debug()) { - mayaegg_cat.warning() - << "Saving camera nodes as a locator: " << path << "\n"; - } - - if (node_desc->is_tagged()) { - // Presumably, the camera's position has some meaning to the end-user, - // so we will implicitly tag it with the DCS flag so it won't get - // flattened out. - if (_animation_convert != AC_model) { - // For now, don't set the DCS flag on cameras within character - // models, since egg-optchar doesn't understand this. Perhaps - // there's no reason to ever change this, since cameras within - // character models may not be meaningful. - egg_group->set_dcs_type(EggGroup::DC_net); - } - get_transform(node_desc, dag_path, egg_group); - make_camera_locator(dag_path, dag_node, egg_group); - } else { - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "Ignoring camera node " << path - << "\n"; - } - } - } - - } else if (dag_path.hasFn(MFn::kLight)) { - if (_convert_lights) { - MFnLight light (dag_path, &status); - if ( !status ) { - status.perror("MFnLight constructor"); - return false; - } - - EggGroup *egg_group = _tree.get_egg_group(node_desc); - - if (mayaegg_cat.is_debug()) { - mayaegg_cat.warning() << "Saving light node as a locator: " << path << endl; - } - - if (node_desc->is_tagged()) { - // Presumably, the lighht's position has some meaning to the end-user, - // so we will implicitly tag it with the DCS flag so it won't get - // flattened out. - if (_animation_convert != AC_model) { - // For now, don't set the DCS flag on lights within character - // models, since egg-optchar doesn't understand this. Perhaps - // there's no reason to ever change this, since lights within - // character models may not be meaningful. - egg_group->set_dcs_type(EggGroup::DC_net); - } - get_transform(node_desc, dag_path, egg_group); - make_light_locator(dag_path, dag_node, egg_group); - } else { - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "Ignoring light node " << path - << "\n"; - } - } - } - - MFnLight light (dag_path, &status); - if ( !status ) { - status.perror("MFnLight constructor"); - mayaegg_cat.error() << "light extraction failed" << endl; - return false; - } - - if (mayaegg_cat.is_info()) { - MString name = dag_path.partialPathName(); - mayaegg_cat.info() << "-- Light found -- tranlations in cm, rotations in rads\n"; - mayaegg_cat.info() << "\"" << name.asChar() << "\" : \n"; - } - - // Get the translationrotationscale data - MObject transformNode = dag_path.transform(&status); - // This node has no transform - i.e., it's the world node - if (!status && status.statusCode () == MStatus::kInvalidParameter) - return false; - MFnDagNode transform (transformNode, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - return false; - } - MTransformationMatrix matrix (transform.transformationMatrix()); - MVector tl = matrix.translation(MSpace::kWorld); - // Stop rediculously small values like -4.43287e-013 - if (tl.x < 0.0001) { - tl.x = 0; - } - if (tl.y < 0.0001) { - tl.y = 0; - } - if (tl.z < 0.0001) { - tl.z = 0; - } - // We swap Y and Z in the next few bits cuz Panda is Z-up by default and - // Maya is Y-up - mayaegg_cat.info() << " \"translation\" : (" << tl.x << ", " << tl.z << ", " << tl.y << ")" - << endl; - double threeDoubles[3]; - MTransformationMatrix::RotationOrder rOrder; - - matrix.getRotation (threeDoubles, rOrder, MSpace::kWorld); - mayaegg_cat.info() << " \"rotation\": (" - << threeDoubles[0] << ", " - << threeDoubles[2] << ", " - << threeDoubles[1] << ")\n"; - matrix.getScale (threeDoubles, MSpace::kWorld); - mayaegg_cat.info() << " \"scale\" : (" - << threeDoubles[0] << ", " - << threeDoubles[2] << ", " - << threeDoubles[1] << ")\n"; - - // Extract some interesting Light data - MColor color; - color = light.color(); - mayaegg_cat.info() << " \"color\" : (" - << color.r << ", " - << color.g << ", " - << color.b << ")\n"; - color = light.shadowColor(); - mayaegg_cat.info() << " \"intensity\" : " << light.intensity() << endl; - - } else if (dag_path.hasFn(MFn::kNurbsSurface)) { - EggGroup *egg_group = _tree.get_egg_group(node_desc); - get_transform(node_desc, dag_path, egg_group); - - if (node_desc->is_tagged()) { - MFnNurbsSurface surface(dag_path, &status); - if (!status) { - mayaegg_cat.info() - << "Error in node " << path - << ":\n" - << " it appears to have a NURBS surface, but does not.\n"; - } else { - make_nurbs_surface(node_desc, dag_path, surface, egg_group); - } - } - } else if (dag_path.hasFn(MFn::kNurbsCurve)) { - // Only convert NurbsCurves if we aren't making an animated model. - // Animated models, as a general rule, don't want these sorts of things in - // them. - if (_animation_convert != AC_model) { - EggGroup *egg_group = _tree.get_egg_group(node_desc); - get_transform(node_desc, dag_path, egg_group); - - if (node_desc->is_tagged()) { - MFnNurbsCurve curve(dag_path, &status); - if (!status) { - mayaegg_cat.info() - << "Error in node " << path << ":\n" - << " it appears to have a NURBS curve, but does not.\n"; - } else { - make_nurbs_curve(dag_path, curve, egg_group); - } - } - } - - } else if (dag_path.hasFn(MFn::kMesh)) { - if (node_desc->is_tagged()) { - EggGroup *egg_group = _tree.get_egg_group(node_desc); - get_transform(node_desc, dag_path, egg_group); - MFnMesh mesh(dag_path, &status); - if (!status) { - mayaegg_cat.info() - << "Error in node " << path << ":\n" - << " it appears to have a polygon mesh, but does not.\n"; - } else { - make_polyset(node_desc, dag_path, mesh, egg_group); - } - } - /* - EggGroup *egg_group = _tree.get_egg_group(node_desc); - get_transform(node_desc, dag_path, egg_group); - - if (node_desc->is_tagged()) { - MFnMesh mesh(dag_path, &status); - if (!status) { - mayaegg_cat.info() - << "Error in node " << path << ":\n" - << " it appears to have a polygon mesh, but does not.\n"; - } else { - make_polyset(node_desc, dag_path, mesh, egg_group); - } - } - */ - } else if (dag_path.hasFn(MFn::kLocator)) { - if (_animation_convert == AC_none) { - if (!node_desc->is_tagged()) { - return true; - } - } - EggGroup *egg_group = _tree.get_egg_group(node_desc); - - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "Locator at " << path << "\n"; - } - - if (node_desc->is_tagged()) { - // Presumably, the locator's position has some meaning to the end-user, - // so we will implicitly tag it with the DCS flag so it won't get - // flattened out. - if (_animation_convert != AC_model) { - // For now, don't set the DCS flag on locators within character - // models, since egg-optchar doesn't understand this. Perhaps there's - // no reason to ever change this, since locators within character - // models may not be meaningful. - egg_group->set_dcs_type(EggGroup::DC_net); - } - get_transform(node_desc, dag_path, egg_group); - make_locator(dag_path, dag_node, egg_group); - } - - } else { - // Just a generic node. - if (_animation_convert == AC_none) { - if (!node_desc->is_tagged()) { - return true; - } - } - EggGroup *egg_group = _tree.get_egg_group(node_desc); - get_transform(node_desc, dag_path, egg_group); - } - - return true; -} - -/** - * Extracts the transform on the indicated Maya node, and applies it to the - * corresponding Egg node. - */ -void MayaToEggConverter:: -get_transform(MayaNodeDesc *node_desc, const MDagPath &dag_path, - EggGroup *egg_group) { - if (_animation_convert == AC_model) { - // When we're getting an animated model, we only get transforms for - // joints, and they get converted in a special way. - - if (node_desc->is_joint()) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() - << "gt: joint " << node_desc->get_name() << "\n"; - } - get_joint_transform(dag_path, egg_group); - } - return; - } - - MStatus status; - MObject transformNode = dag_path.transform(&status); - if (!status && status.statusCode() == MStatus::kInvalidParameter) { - // This node has no transform - i.e., it's the world node - return; - } - - // Billboards always get the transform set. - if (egg_group->get_billboard_type() == EggGroup::BT_none) { - switch (_transform_type) { - case TT_all: - break; - - case TT_model: - if (!egg_group->get_model_flag() && !egg_group->has_dcs_type()) { - return; - } - break; - - case TT_dcs: - if (!egg_group->has_dcs_type()) { - return; - } - break; - - case TT_none: - case TT_invalid: - return; - } - } - - // Extract the matrix from the dag path. - MMatrix mat = dag_path.inclusiveMatrix(&status); - if (!status) { - status.perror("Can't get transform matrix"); - return; - } - LMatrix4d m4d(mat[0][0], mat[0][1], mat[0][2], mat[0][3], - mat[1][0], mat[1][1], mat[1][2], mat[1][3], - mat[2][0], mat[2][1], mat[2][2], mat[2][3], - mat[3][0], mat[3][1], mat[3][2], mat[3][3]); - - // Maya has a rotate pivot, separate from its transform. Usually we care - // more about the rotate pivot than we do about the transform, so get the - // rotate pivot too. - MFnTransform transform(transformNode, &status); - if (!status) { - status.perror("MFnTransform constructor"); - return; - } - MPoint pivot = transform.rotatePivot(MSpace::kObject, &status); - if (!status) { - status.perror("Can't get rotate pivot"); - return; - } - - // We need to convert the pivot to world coordinates. (Maya can only tell - // it to us in local coordinates.) - LPoint3d p3d(pivot[0], pivot[1], pivot[2]); - p3d = p3d * m4d; - - // Now recenter the matrix about the pivot point. - m4d.set_row(3, p3d); - - // Convert the recentered matrix into the group's space and store it. - m4d = m4d * egg_group->get_node_frame_inv(); - if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) { - egg_group->add_matrix4(m4d); - } - return; -} - -/** - * Extracts the transform on the indicated Maya node, as appropriate for a - * joint in an animated character, and applies it to the indicated node. This - * is different from get_transform() in that it does not respect the - * _transform_type flag, and it does not consider the relative transforms - * within the egg file. - */ -void MayaToEggConverter:: -get_joint_transform(const MDagPath &dag_path, EggGroup *egg_group) { - // First, make sure there's not a transform on the group already. - egg_group->clear_transform(); - - MStatus status; - MObject transformNode = dag_path.transform(&status); - // This node has no transform - i.e., it's the world node - if (!status && status.statusCode() == MStatus::kInvalidParameter) { - return; - } - - MFnDagNode transform(transformNode, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - return; - } - - MTransformationMatrix matrix(transform.transformationMatrix()); - - if (mayaegg_cat.is_spam()) { - MVector t = matrix.translation(MSpace::kWorld); - mayaegg_cat.spam() - << " translation: [" - << t[0] << ", " - << t[1] << ", " - << t[2] << "]\n"; - double d[3]; - MTransformationMatrix::RotationOrder rOrder; - - matrix.getRotation(d, rOrder, MSpace::kWorld); - mayaegg_cat.spam() - << " rotation: [" - << d[0] << ", " - << d[1] << ", " - << d[2] << "]\n"; - matrix.getScale(d, MSpace::kWorld); - mayaegg_cat.spam() - << " scale: [" - << d[0] << ", " - << d[1] << ", " - << d[2] << "]\n"; - matrix.getShear(d, MSpace::kWorld); - mayaegg_cat.spam() - << " shear: [" - << d[0] << ", " - << d[1] << ", " - << d[2] << "]\n"; - } - - MMatrix mat = matrix.asMatrix(); - MMatrix ident_mat; - ident_mat.setToIdentity(); - - if (!mat.isEquivalent(ident_mat, 0.0001)) { - egg_group->set_transform3d - (LMatrix4d(mat[0][0], mat[0][1], mat[0][2], mat[0][3], - mat[1][0], mat[1][1], mat[1][2], mat[1][3], - mat[2][0], mat[2][1], mat[2][2], mat[2][3], - mat[3][0], mat[3][1], mat[3][2], mat[3][3])); - } -} - -/** - * Converts the indicated Maya NURBS surface to a corresponding egg structure, - * and attaches it to the indicated egg group. - */ -void MayaToEggConverter:: -make_nurbs_surface(MayaNodeDesc *node_desc, const MDagPath &dag_path, - MFnNurbsSurface &surface, EggGroup *egg_group) { - MStatus status; - string name = surface.name().asChar(); - - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() - << " numCVs: " - << surface.numCVsInU() - << " * " - << surface.numCVsInV() - << "\n"; - mayaegg_cat.spam() - << " numKnots: " - << surface.numKnotsInU() - << " * " - << surface.numKnotsInV() - << "\n"; - mayaegg_cat.spam() - << " numSpans: " - << surface.numSpansInU() - << " * " - << surface.numSpansInV() - << "\n"; - } - MayaShader *shader = _shaders.find_shader_for_node(surface.object(), _legacy_shader); - - if (_polygon_output) { - // If we want polygon output only, tesselate the NURBS and output that. - MTesselationParams params; - params.setFormatType(MTesselationParams::kStandardFitFormat); - params.setOutputType(MTesselationParams::kQuads); - params.setStdFractionalTolerance(_polygon_tolerance); - - // We'll create the tesselation as a sibling of the NURBS surface. That - // way we inherit all of the transformations. - MDagPath polyset_path = dag_path; - MObject polyset_parent = polyset_path.node(); - MObject polyset = - surface.tesselate(params, polyset_parent, &status); - if (!status) { - status.perror("MFnNurbsSurface::tesselate"); - return; - } - - status = polyset_path.push(polyset); - if (!status) { - status.perror("MDagPath::push"); - } - - MFnMesh polyset_fn(polyset, &status); - if (!status) { - status.perror("MFnMesh constructor"); - return; - } - make_polyset(node_desc, polyset_path, polyset_fn, egg_group, shader); - - // Now remove the polyset we created. - MFnDagNode parent_node(polyset_parent, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - return; - } - status = parent_node.removeChild(polyset); - if (!status) { - status.perror("MFnDagNode::removeChild"); - } - - return; - } - - MPointArray cv_array; - status = surface.getCVs(cv_array, MSpace::kWorld); - if (!status) { - status.perror("MFnNurbsSurface::getCVs"); - return; - } - - // Also get out all the alternate blend shapes for the surface by applying - // each morph slider one at a time. - pvector morph_cvs; - if (_animation_convert == AC_model) { - int num_sliders = node_desc->get_num_blend_descs(); - morph_cvs.reserve(num_sliders); - for (int i = 0; i < num_sliders; i++) { - MayaBlendDesc *blend_desc = node_desc->get_blend_desc(i); - - // Temporarily push the slider up to 1.0 so we can see what the surface - // looks like at that value. - blend_desc->set_slider(1.0); - MPointArray cv_array; - status = surface.getCVs(cv_array, MSpace::kWorld); - blend_desc->set_slider(0.0); - - if (!status) { - status.perror("MFnNurbsSurface::getCVs"); - return; - } - morph_cvs.push_back(cv_array); - } - } - - MDoubleArray u_knot_array, v_knot_array; - status = surface.getKnotsInU(u_knot_array); - if (!status) { - status.perror("MFnNurbsSurface::getKnotsInU"); - return; - } - status = surface.getKnotsInV(v_knot_array); - if (!status) { - status.perror("MFnNurbsSurface::getKnotsInV"); - return; - } - - MFnNurbsSurface::Form u_form = surface.formInU(); - MFnNurbsSurface::Form v_form = surface.formInV(); - - int u_degree = surface.degreeU(); - int v_degree = surface.degreeV(); - - int u_cvs = surface.numCVsInU(); - int v_cvs = surface.numCVsInV(); - - // Maya repeats CVS at the end for a periodic surface, and doesn't count - // them in the joint weight array, below. - int maya_u_cvs = (u_form == MFnNurbsSurface::kPeriodic) ? u_cvs - u_degree : u_cvs; - int maya_v_cvs = (v_form == MFnNurbsSurface::kPeriodic) ? v_cvs - v_degree : v_cvs; - - int u_knots = surface.numKnotsInU(); - int v_knots = surface.numKnotsInV(); - - assert(u_knots == u_cvs + u_degree - 1); - assert(v_knots == v_cvs + v_degree - 1); - - string vpool_name = name + ".cvs"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - egg_group->add_child(vpool); - - EggNurbsSurface *egg_nurbs = new EggNurbsSurface(name); - egg_nurbs->setup(u_degree + 1, v_degree + 1, - u_knots + 2, v_knots + 2); - - int i; - - egg_nurbs->set_u_knot(0, u_knot_array[0]); - for (i = 0; i < u_knots; i++) { - egg_nurbs->set_u_knot(i + 1, u_knot_array[i]); - } - egg_nurbs->set_u_knot(u_knots + 1, u_knot_array[u_knots - 1]); - - egg_nurbs->set_v_knot(0, v_knot_array[0]); - for (i = 0; i < v_knots; i++) { - egg_nurbs->set_v_knot(i + 1, v_knot_array[i]); - } - egg_nurbs->set_v_knot(v_knots + 1, v_knot_array[v_knots - 1]); - - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - for (i = 0; i < egg_nurbs->get_num_cvs(); i++) { - int ui = egg_nurbs->get_u_index(i); - int vi = egg_nurbs->get_v_index(i); - int maya_vi = v_cvs * ui + vi; - - double v[4]; - status = cv_array[maya_vi].get(v); - if (!status) { - status.perror("MPoint::get"); - } else { - EggVertex *vert = vpool->add_vertex(new EggVertex, i); - LPoint4d p4d(v[0], v[1], v[2], v[3]); - p4d = p4d * vertex_frame_inv; - vert->set_pos(p4d); - - // Now generate the morph targets for the vertex. - if (!morph_cvs.empty()) { - // Morph deltas are given in 3-d space, not in 4-d homogenous space. - LPoint3d p3d(v[0] / v[3], v[1] / v[3], v[2] / v[3]); - - for (unsigned int si = 0; si < morph_cvs.size(); si++) { - MayaBlendDesc *blend_desc = node_desc->get_blend_desc(si); - status = morph_cvs[si][maya_vi].get(v); - if (!status) { - status.perror("MPoint::get"); - } else { - LPoint3d m3d(v[0] / v[3], v[1] / v[3], v[2] / v[3]); - LVector3d delta = m3d - p3d; - if (!delta.almost_equal(LVector3d::zero())) { - EggMorphVertex dxyz(blend_desc->get_name(), delta); - vert->_dxyzs.insert(dxyz); - } - } - } - } - - egg_nurbs->add_vertex(vert); - } - } - - // Now consider the trim curves, if any. - unsigned num_trims = surface.numRegions(); - int trim_curve_index = 0; - for (unsigned ti = 0; ti < num_trims; ti++) { - unsigned num_loops = surface.numBoundaries(ti); - - if (num_loops > 0) { - egg_nurbs->_trims.push_back(EggNurbsSurface::Trim()); - EggNurbsSurface::Trim &egg_trim = egg_nurbs->_trims.back(); - - for (unsigned li = 0; li < num_loops; li++) { - egg_trim.push_back(EggNurbsSurface::Loop()); - EggNurbsSurface::Loop &egg_loop = egg_trim.back(); - - MFnNurbsSurface::BoundaryType type = - surface.boundaryType(ti, li, &status); - bool keep_loop = false; - - if (!status) { - status.perror("MFnNurbsSurface::BoundaryType"); - } else { - keep_loop = (type == MFnNurbsSurface::kInner || - type == MFnNurbsSurface::kOuter); - } - - if (keep_loop) { - unsigned num_edges = surface.numEdges(ti, li); - for (unsigned ei = 0; ei < num_edges; ei++) { - MObjectArray edge = surface.edge(ti, li, ei, true, &status); - if (!status) { - status.perror("MFnNurbsSurface::edge"); - } else { - unsigned num_segs = edge.length(); - for (unsigned si = 0; si < num_segs; si++) { - MObject segment = edge[si]; - if (segment.hasFn(MFn::kNurbsCurve)) { - MFnNurbsCurve curve(segment, &status); - if (!status) { - mayaegg_cat.error() - << "Trim curve appears to be a nurbs curve, but isn't.\n"; - } else { - // Finally, we have a valid curve! - EggNurbsCurve *egg_curve = - make_trim_curve(curve, name, egg_group, trim_curve_index); - trim_curve_index++; - if (egg_curve != nullptr) { - egg_loop.push_back(egg_curve); - } - } - } else { - mayaegg_cat.error() - << "Trim curve segment is not a nurbs curve.\n"; - } - } - } - } - } - } - } - } - - // We add the NURBS to the group down here, after all of the vpools for the - // trim curves have been added. - egg_group->add_child(egg_nurbs); - - if (shader != nullptr) { - set_shader_attributes(*egg_nurbs, *shader); - } - - // Now try to find the skinning information for the surface. - bool got_weights = false; - - pvector joints; - MFloatArray weights; - if (_animation_convert == AC_model) { - got_weights = - get_vertex_weights(dag_path, surface, joints, weights); - } - - if (got_weights && !joints.empty()) { - int num_joints = joints.size(); - int num_weights = (int)weights.length(); - int num_verts = num_weights / num_joints; - // The number of weights should be an even multiple of verts * joints. - nassertv(num_weights == num_verts * num_joints); - - for (i = 0; i < egg_nurbs->get_num_cvs(); i++) { - int ui = egg_nurbs->get_u_index(i) % maya_u_cvs; - int vi = egg_nurbs->get_v_index(i) % maya_v_cvs; - - int maya_vi = maya_v_cvs * ui + vi; - nassertv(maya_vi < num_verts); - EggVertex *vert = vpool->get_vertex(i); - - for (int ji = 0; ji < num_joints; ++ji) { - PN_stdfloat weight = weights[maya_vi * num_joints + ji]; - if (weight != 0.0f) { - EggGroup *joint = joints[ji]; - if (joint != nullptr) { - joint->ref_vertex(vert, weight); - } - } - } - } - } -} - -/** - * Converts the indicated Maya NURBS trim curve to a corresponding egg - * structure, and returns it, or NULL if there is a problem. - */ -EggNurbsCurve *MayaToEggConverter:: -make_trim_curve(const MFnNurbsCurve &curve, const string &nurbs_name, - EggGroupNode *egg_group, int trim_curve_index) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() - << "Trim curve:\n"; - mayaegg_cat.spam() - << " numCVs: " - << curve.numCVs() - << "\n"; - mayaegg_cat.spam() - << " numKnots: " - << curve.numKnots() - << "\n"; - mayaegg_cat.spam() - << " numSpans: " - << curve.numSpans() - << "\n"; - } - - MStatus status; - - MPointArray cv_array; - status = curve.getCVs(cv_array, MSpace::kWorld); - if (!status) { - status.perror("MFnNurbsCurve::getCVs"); - return nullptr; - } - MDoubleArray knot_array; - status = curve.getKnots(knot_array); - if (!status) { - status.perror("MFnNurbsCurve::getKnots"); - return nullptr; - } - - /* - MFnNurbsCurve::Form form = curve.form(); - */ - - int degree = curve.degree(); - int cvs = curve.numCVs(); - int knots = curve.numKnots(); - - assert(knots == cvs + degree - 1); - - string trim_name = "trim" + format_string(trim_curve_index); - - string vpool_name = nurbs_name + "." + trim_name; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - egg_group->add_child(vpool); - - EggNurbsCurve *egg_curve = new EggNurbsCurve(trim_name); - egg_curve->setup(degree + 1, knots + 2); - - int i; - - egg_curve->set_knot(0, knot_array[0]); - for (i = 0; i < knots; i++) { - egg_curve->set_knot(i + 1, knot_array[i]); - } - egg_curve->set_knot(knots + 1, knot_array[knots - 1]); - - for (i = 0; i < egg_curve->get_num_cvs(); i++) { - double v[4]; - MStatus status = cv_array[i].get(v); - if (!status) { - status.perror("MPoint::get"); - } else { - EggVertex vert; - vert.set_pos(LPoint3d(v[0], v[1], v[3])); - egg_curve->add_vertex(vpool->create_unique_vertex(vert)); - } - } - - return egg_curve; -} - -/** - * Converts the indicated Maya NURBS curve (a standalone curve, not a trim - * curve) to a corresponding egg structure and attaches it to the indicated - * egg group. - */ -void MayaToEggConverter:: -make_nurbs_curve(const MDagPath &, const MFnNurbsCurve &curve, - EggGroup *egg_group) { - MStatus status; - string name = curve.name().asChar(); - - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() - << " numCVs: " - << curve.numCVs() - << "\n"; - mayaegg_cat.spam() - << " numKnots: " - << curve.numKnots() - << "\n"; - mayaegg_cat.spam() - << " numSpans: " - << curve.numSpans() - << "\n"; - } - - MPointArray cv_array; - status = curve.getCVs(cv_array, MSpace::kWorld); - if (!status) { - status.perror("MFnNurbsCurve::getCVs"); - return; - } - MDoubleArray knot_array; - status = curve.getKnots(knot_array); - if (!status) { - status.perror("MFnNurbsCurve::getKnots"); - return; - } - - /* - MFnNurbsCurve::Form form = curve.form(); - */ - - int degree = curve.degree(); - int cvs = curve.numCVs(); - int knots = curve.numKnots(); - - assert(knots == cvs + degree - 1); - - string vpool_name = name + ".cvs"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - egg_group->add_child(vpool); - - EggNurbsCurve *egg_curve = new EggNurbsCurve(name); - egg_group->add_child(egg_curve); - egg_curve->setup(degree + 1, knots + 2); - - int i; - - egg_curve->set_knot(0, knot_array[0]); - for (i = 0; i < knots; i++) { - egg_curve->set_knot(i + 1, knot_array[i]); - } - egg_curve->set_knot(knots + 1, knot_array[knots - 1]); - - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - for (i = 0; i < egg_curve->get_num_cvs(); i++) { - double v[4]; - MStatus status = cv_array[i].get(v); - if (!status) { - status.perror("MPoint::get"); - } else { - EggVertex vert; - LPoint4d p4d(v[0], v[1], v[2], v[3]); - p4d = p4d * vertex_frame_inv; - vert.set_pos(p4d); - egg_curve->add_vertex(vpool->create_unique_vertex(vert)); - } - } - MayaShader *shader = _shaders.find_shader_for_node(curve.object(), _legacy_shader); - if (shader != nullptr) { - set_shader_attributes(*egg_curve, *shader); - } -} - -/** - * given uvsets, round them up or down - */ -int MayaToEggConverter:: -round(double value) { - if (value < 0) - return -(floor(-value + 0.5)); - // or as an alternate use: return ceil ( value - 0.5); - else - return floor( value + 0.5); -} - -/** - * Converts the indicated Maya polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void MayaToEggConverter:: -make_polyset(MayaNodeDesc *node_desc, const MDagPath &dag_path, - const MFnMesh &mesh, EggGroup *egg_group, - MayaShader *default_shader) { - MStatus status; - string name = mesh.name().asChar(); - - MObject mesh_object = mesh.object(); - bool maya_double_sided = false; - get_bool_attribute(mesh_object, "doubleSided", maya_double_sided); - - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() - << " numPolygons: " - << mesh.numPolygons() - << "\n"; - mayaegg_cat.spam() - << " numVertices: " - << mesh.numVertices() - << "\n"; - } - - if (mesh.numPolygons() == 0) { - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "Ignoring empty mesh " << name << "\n"; - } - return; - } - - string vpool_name = name + ".verts"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - egg_group->add_child(vpool); - - // One way to convert the mesh would be to first get out all the vertices in - // the mesh and add them into the vpool, then when we traverse the polygons - // we would only have to index them into the vpool according to their Maya - // vertex index. - - // Unfortunately, since Maya may store multiple normals andor colors for - // each vertex according to which polygon it is in, that approach won't - // necessarily work. In egg, those split-property vertices have to become - // separate vertices. So instead of adding all the vertices up front, we'll - // start with an empty vpool, and add vertices to it on the fly. - - MObject component_obj; - MItMeshPolygon pi(dag_path, component_obj, &status); - if (!status) { - status.perror("MItMeshPolygon constructor"); - return; - } - - MObjectArray shaders; - MIntArray poly_shader_indices; - - status = mesh.getConnectedShaders(dag_path.instanceNumber(), - shaders, poly_shader_indices); - if (!status) { - status.perror("MFnMesh::getConnectedShaders"); - } - - // We will need to transform all vertices from world coordinate space into - // the vertex space appropriate to this node. Usually, this is the same - // thing as world coordinate space, and this matrix will be identity; but if - // the node is under an instance (particularly, for instance, a billboard) - // then the vertex space will be different from world space. - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - // Save these modeling flags for the check below. - bool egg_vertex_color = false; - bool egg_double_sided = false; - if (egg_group->has_user_data(MayaEggGroupUserData::get_class_type())) { - MayaEggGroupUserData *user_data = - DCAST(MayaEggGroupUserData, egg_group->get_user_data()); - egg_vertex_color = user_data->_vertex_color; - egg_double_sided = user_data->_double_sided; - } - - bool double_sided = maya_double_sided; - if (!_respect_maya_double_sided) { - // If this flag is false, we respect the maya double-sided settings only - // if the egg "double-sided" flag is also set. - if (!egg_double_sided) { - double_sided = false; - } - } - - bool keep_all_uvsets = _keep_all_uvsets || node_desc->has_object_type("keep-all-uvsets"); - if (node_desc->has_object_type("keep-all-uvsets")) { - mayaegg_cat.info() << "will keep_all_uvsets" << endl; - } - - _shaders.bind_uvsets(mesh.object()); - - while (!pi.isDone()) { - EggPolygon *egg_poly = new EggPolygon; - egg_group->add_child(egg_poly); - - egg_poly->set_bface_flag(double_sided); - - // Determine the MayaShader for this particular polygon. There appears to - // be two diverging paths for any Maya node with a Material (MayaShader) - // on it This next bit kicks us out into mayaShader et al. to pull - // textures and everything else. - MayaShader *shader = nullptr; - int index = pi.index(); - nassertv(index >= 0 && index < (int)poly_shader_indices.length()); - int shader_index = poly_shader_indices[index]; - - if (shader_index != -1) { - nassertv(shader_index >= 0 && shader_index < (int)shaders.length()); - MObject engine = shaders[shader_index]; - shader = - _shaders.find_shader_for_shading_engine(engine, _legacy_shader); //head out to the other classes - // does this mean if we didn't find a Maya shader give it a default - // value anyway? - } else if (default_shader != nullptr) { - shader = default_shader; - } - - const MayaShaderColorDef *default_color_def = nullptr; - - // And apply the shader properties to the polygon. - if (shader != nullptr) { - set_shader_attributes(*egg_poly, *shader, true); - default_color_def = shader->get_color_def(); - } - - // Should we extract the color from the vertices? Normally, in Maya a - // texture completely replaces the vertex color, so we should ignore the - // vertex color if we have a texture. - - // However, this is an inconvenient property of Maya; sometimes we really - // do want both vertex color and texture applied to the same object. To - // allow this, we define the special egg flag "vertex-color", which when - // set indicates that we should respect the vertex color anyway. - - // Furthermore, if _always_show_vertex_color is true, we pretend that the - // "vertex-color" flag is always set. - bool ignore_vertex_color = false; - if ( default_color_def != nullptr) { - ignore_vertex_color = default_color_def->_has_texture && !(egg_vertex_color || _always_show_vertex_color); - } - - LColor poly_color(1.0f, 1.0f, 1.0f, 1.0f); - if (!ignore_vertex_color) { - // If we're respecting the vertex color, then remove the color - // specification from the polygon (so we can apply it to the vertices). - poly_color = egg_poly->get_color(); - egg_poly->clear_color(); - } - - // Get the vertices for the polygon. - long num_verts = pi.polygonVertexCount(); - long i; - LPoint3d centroid(0.0, 0.0, 0.0); - - if (default_color_def != nullptr && default_color_def->has_projection()) { - // If the shader has a projection, we may need to compute the polygon's - // centroid to avoid seams at the edges. - for (i = 0; i < num_verts; i++) { - MPoint p = pi.point(i, MSpace::kWorld); - LPoint3d p3d(p[0], p[1], p[2]); - p3d = p3d * vertex_frame_inv; - centroid += p3d; - } - centroid /= (double)num_verts; - } - for (i = 0; i < num_verts; i++) { - EggVertex vert; - - MPoint p = pi.point(i, MSpace::kWorld); - LPoint3d p3d(p[0] / p[3], p[1] / p[3], p[2] / p[3]); - p3d = p3d * vertex_frame_inv; - vert.set_pos(p3d); - - MVector n; - status = pi.getNormal(i, n, MSpace::kWorld); - if (!status) { - status.perror("MItMeshPolygon::getNormal"); - } else { - LNormald n3d(n[0], n[1], n[2]); - n3d = n3d * vertex_frame_inv; - vert.set_normal(n3d); - } - - // Go thru all the texture references for this primitive and set uvs - if (mayaegg_cat.is_spam()) { - if (shader != nullptr) { - mayaegg_cat.spam() << "shader->_color.size is " << shader->_color.size() << endl; - } - mayaegg_cat.spam() << "primitive->tref.size is " << egg_poly->get_num_textures() << endl; - } - for (size_t ti=0; ti< _shaders._uvset_names.size(); ++ti) { - // get the eggTexture pointer - string uvset_name(_shaders._uvset_names[ti]); - string panda_uvset_name = uvset_name; - if (panda_uvset_name == "map1") { - panda_uvset_name = "default"; - } - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "--uvset_name :" << uvset_name << endl; - } - - // get the shader color def that matches this EggTexture Asad: - // optimizing uvset: to discard unused uvsets. This for loop figures - // out which ones are unused. - - bool keep_uv = keep_all_uvsets; - bool project_uv = false; - LTexCoordd uv_projection; - - if (shader != nullptr) { - for (size_t tj = 0; tj < shader->_all_maps.size(); ++tj) { - MayaShaderColorDef *def = shader->_all_maps[tj]; - if (def->_uvset_name == uvset_name) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "matched colordef idx: " << tj << endl; - } - keep_uv = true; - if (def->has_projection()) { - project_uv = true; - uv_projection = def->project_uv(p3d, centroid); - } - break; - } - } - } - - // if uvset is not used don't add it to the vertex - if (!keep_uv) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "discarding unused uvset " << uvset_name << endl; - } - continue; - } - - if (project_uv) { - // If the shader has a projection, use it instead of the polygon's - // built-in UV's. - vert.set_uv(panda_uvset_name, uv_projection); - } else { - // Get the UV's from the polygon. - float2 uvs; - MString uv_mstring(uvset_name.c_str()); - if (pi.hasUVs(uv_mstring, &status)) { - status = pi.getUV(i, uvs, &uv_mstring); - if (!status) { - status.perror("MItMeshPolygon::getUV"); - } else { - if (_round_uvs) { - if (uvs[0] > 1.0 || uvs[0] < -1.0) { - // apply upto 11000th precision, but round up - uvs[0] = (long)(uvs[0]*1000); - mayaegg_cat.debug() << "before rounding uvs[0]: " << uvs[0] << endl; - uvs[0] = (double)(round((double)uvs[0]/10.0)*10.0)/1000.0; - mayaegg_cat.debug() << "after rounding uvs[0]: " << uvs[0] << endl; - } - if (uvs[1] > 1.0 || uvs[1] < -1.0) { - uvs[1] = (long)(uvs[1]*1000); - mayaegg_cat.debug() << "before rounding uvs[1]: " << uvs[1] << endl; - uvs[1] = (double)(round((double)uvs[1]/10.0)*10.0)/1000.0; - mayaegg_cat.debug() << "after rounding uvs[1]: " << uvs[1] << endl; - } - } - vert.set_uv(panda_uvset_name, LTexCoordd(uvs[0], uvs[1])); - } - } - } - } - - if (!ignore_vertex_color) { - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "poly_color = " << poly_color << endl; - } - set_vertex_color(vert,pi,i,shader,poly_color); - } - - vert.set_external_index(pi.vertexIndex(i, &status)); - vert.set_external_index2(pi.normalIndex(i, &status)); - - egg_poly->add_vertex(vpool->create_unique_vertex(vert)); - } - - // Also get the face normal for the polygon. - LNormald face_normal; - bool got_face_normal = false; - - MVector n; - status = pi.getNormal(n, MSpace::kWorld); - if (!status) { - status.perror("MItMeshPolygon::getNormal face"); - } else { - face_normal.set(n[0], n[1], n[2]); - face_normal = face_normal * vertex_frame_inv; - got_face_normal = true; - egg_poly->set_normal(face_normal); - } - - // Now, check that the vertex ordering is consistent with the direction of - // the normals. If not, reverse the vertex ordering (since we have seen - // cases where Maya sets this in contradiction to its normals). - LNormald order_normal; - if (got_face_normal && egg_poly->calculate_normal(order_normal)) { - if (order_normal.dot(face_normal) < 0.0) { - egg_poly->reverse_vertex_ordering(); - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "reversing polygon\n"; - } - } - } - - pi.next(); - } - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "done traversing polys" << endl; - } - - // Now that we've added all the polygons (and created all the vertices), go - // back through the vertex pool and set up the appropriate joint membership - // for each of the vertices. - bool got_weights = false; - - pvector joints; - MFloatArray weights; - if (_animation_convert == AC_model) { - got_weights = - get_vertex_weights(dag_path, mesh, joints, weights); - } - - if (got_weights && !joints.empty()) { - int num_joints = joints.size(); - int num_weights = (int)weights.length(); - int num_verts = num_weights / num_joints; - // The number of weights should be an even multiple of verts * joints. - nassertv(num_weights == num_verts * num_joints); - - EggVertexPool::iterator vi; - for (vi = vpool->begin(); vi != vpool->end(); ++vi) { - EggVertex *vert = (*vi); - int maya_vi = vert->get_external_index(); - nassertv(maya_vi >= 0 && maya_vi < num_verts); - - for (int ji = 0; ji < num_joints; ++ji) { - PN_stdfloat weight = weights[maya_vi * num_joints + ji]; - if (weight != 0.0f) { - EggGroup *joint = joints[ji]; - if (joint != nullptr) { - joint->ref_vertex(vert, weight); - } - } - } - } - } - - - // We also need to compute the vertex morphs for the polyset, based on - // whatever blend shapes may be present. This is similar to the code in - // make_nurbs_surface(), except that since we don't have a one-to-one - // relationship of egg vertices to Maya vertices, we have to get the morphs - // down here, after we have added all of the egg vertices. - - if (_animation_convert == AC_model) { - int num_orig_mesh_verts = mesh.numVertices(); - - int num_sliders = node_desc->get_num_blend_descs(); - for (int i = 0; i < num_sliders; i++) { - MayaBlendDesc *blend_desc = node_desc->get_blend_desc(i); - - // Temporarily push the slider up to 1.0 so we can see what the surface - // looks like at that value. - blend_desc->set_slider(1.0); - - // We have to get the mesh object from the dag again after fiddling with - // the slider. - MFnMesh blend_mesh(dag_path, &status); - if (!status) { - mayaegg_cat.warning() - << name << " no longer has a mesh after applying " - << blend_desc->get_name() << "\n"; - - } else { - if (blend_mesh.numVertices() != num_orig_mesh_verts) { - mayaegg_cat.warning() - << "Ignoring " << blend_desc->get_name() << " for " - << name << "; blend shape has " << blend_mesh.numVertices() - << " vertices while original shape has " - << num_orig_mesh_verts << ".\n"; - - } else { - MPointArray verts; - status = blend_mesh.getPoints(verts, MSpace::kWorld); - if (!status) { - status.perror("MFnMesh::getPoints"); - } else { - int num_verts = (int)verts.length(); - EggVertexPool::iterator vi; - for (vi = vpool->begin(); vi != vpool->end(); ++vi) { - EggVertex *vert = (*vi); - int maya_vi = vert->get_external_index(); - nassertv(maya_vi >= 0 && maya_vi < num_verts); - - const MPoint &m = verts[maya_vi]; - LPoint3d m3d(m[0] / m[3], m[1] / m[3], m[2] / m[3]); - m3d = m3d * vertex_frame_inv; - - LVector3d delta = m3d - vert->get_pos3(); - if (!delta.almost_equal(LVector3d::zero())) { - EggMorphVertex dxyz(blend_desc->get_name(), delta); - vert->_dxyzs.insert(dxyz); - } - } - } - - MFloatVectorArray norms; - status = blend_mesh.getNormals(norms, MSpace::kWorld); - if (!status) { - status.perror("MFnMesh::getNormals"); - } else { - int num_norms = (int)norms.length(); - EggVertexPool::iterator vi; - for (vi = vpool->begin(); vi != vpool->end(); ++vi) { - EggVertex *vert = (*vi); - int maya_vi = vert->get_external_index2(); - nassertv(maya_vi >= 0 && maya_vi < num_norms); - - const MFloatVector &m = norms[maya_vi]; - LVector3d m3d(m[0], m[1], m[2]); - m3d = m3d * vertex_frame_inv; - - LNormald delta = m3d - vert->get_normal(); - if (!delta.almost_equal(LVector3d::zero())) { - EggMorphNormal dnormal(blend_desc->get_name(), delta); - vert->_dnormals.insert(dnormal); - } - } - } - } - } - - blend_desc->set_slider(0.0); - } - } -} - -/** - * Locators are used in Maya to indicate a particular position in space to the - * user or the modeler. We represent that in egg with an ordinary Group node, - * which we transform by the locator's position, so that the indicated point - * becomes the origin at this node and below. - */ -void MayaToEggConverter:: -make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group) { - MStatus status; - - unsigned int num_children = dag_node.childCount(); - MObject locator; - bool found_locator = false; - for (unsigned int ci = 0; ci < num_children && !found_locator; ci++) { - locator = dag_node.child(ci); - found_locator = (locator.apiType() == MFn::kLocator); - } - - if (!found_locator) { - mayaegg_cat.error() - << "Couldn't find locator within locator node " - << dag_path.fullPathName().asChar() << "\n"; - return; - } - - LPoint3d p3d; - if (!get_vec3d_attribute(locator, "localPosition", p3d)) { - mayaegg_cat.error() - << "Couldn't get position of locator " - << dag_path.fullPathName().asChar() << "\n"; - return; - } - - // We need to convert the position to world coordinates. For some reason, - // Maya can only tell it to us in local coordinates. - MMatrix mat = dag_path.inclusiveMatrix(&status); - if (!status) { - status.perror("Can't get coordinate space for locator"); - return; - } - LMatrix4d n2w(mat[0][0], mat[0][1], mat[0][2], mat[0][3], - mat[1][0], mat[1][1], mat[1][2], mat[1][3], - mat[2][0], mat[2][1], mat[2][2], mat[2][3], - mat[3][0], mat[3][1], mat[3][2], mat[3][3]); - p3d = p3d * n2w; - - // Now convert the locator point into the group's space. - p3d = p3d * egg_group->get_node_frame_inv(); - - egg_group->add_translate3d(p3d); -} - -/** - * Locators are used in Maya to indicate a particular position in space to the - * user or the modeler. We represent that in egg with an ordinary Group node, - * which we transform by the locator's position, so that the indicated point - * becomes the origin at this node and below. - */ -void MayaToEggConverter:: -make_camera_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group) { - MStatus status; - - unsigned int num_children = dag_node.childCount(); - MObject locator; - bool found_camera = false; - for (unsigned int ci = 0; ci < num_children && !found_camera; ci++) { - locator = dag_node.child(ci); - found_camera = (locator.apiType() == MFn::kCamera); - } - - if (!found_camera) { - mayaegg_cat.error() - << "Couldn't find camera" - << dag_path.fullPathName().asChar() << "\n"; - return; - } - MFnCamera camera (dag_path, &status); - if ( !status ) { - status.perror("MFnCamera constructor"); - return; - } - MPoint eyePoint = camera.eyePoint(MSpace::kWorld); - LPoint3d p3d (eyePoint.x, eyePoint.y, eyePoint.z); - - // Now convert the locator point into the group's space. - p3d = p3d * egg_group->get_node_frame_inv(); - - egg_group->add_translate3d(p3d); -} - - -/** - * Locators are used in Maya to indicate a particular position in space to the - * user or the modeler. We represent that in egg with an ordinary Group node, - * which we transform by the locator's position, so that the indicated point - * becomes the origin at this node and below. - */ -void MayaToEggConverter:: -make_light_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group) { - MStatus status; - - unsigned int num_children = dag_node.childCount(); - MObject locator; - bool found_alight = false; - bool found_dlight = false; - bool found_plight = false; - for (unsigned int ci = 0; ci < num_children && !found_alight && !found_dlight && !found_plight; ci++) { - locator = dag_node.child(ci); - found_alight = (locator.apiType() == MFn::kAmbientLight); - found_dlight = (locator.apiType() == MFn::kDirectionalLight); - found_plight = (locator.apiType() == MFn::kPointLight); - } - - if (!found_alight && !found_dlight && !found_plight) { - mayaegg_cat.error() - << "Couldn't find light within locator node " - << dag_path.fullPathName().asChar() << "\n"; - return; - } - - LPoint3d p3d; - - // We need to convert the position to world coordinates. For some reason, - // Maya can only tell it to us in local coordinates. - MMatrix mat = dag_path.inclusiveMatrix(&status); - if (!status) { - status.perror("Can't get coordinate space for light"); - return; - } - LMatrix4d n2w(mat[0][0], mat[0][1], mat[0][2], mat[0][3], - mat[1][0], mat[1][1], mat[1][2], mat[1][3], - mat[2][0], mat[2][1], mat[2][2], mat[2][3], - mat[3][0], mat[3][1], mat[3][2], mat[3][3]); - p3d = p3d * n2w; - - // Now convert the locator point into the group's space. - p3d = p3d * egg_group->get_node_frame_inv(); - - egg_group->add_translate3d(p3d); -} - - -/** - * - */ -bool MayaToEggConverter:: -get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, - pvector &joints, MFloatArray &weights) { - MStatus status; - - // Since we are working with a mesh the input attribute that creates the - // mesh is named "inMesh" - MObject attr = mesh.attribute("inMesh"); - - // Create the plug to the "inMesh" attribute then use the DG iterator to - // walk through the DG, at the node level. - MPlug history(mesh.object(), attr); - MItDependencyGraph it(history, MFn::kDependencyNode, - MItDependencyGraph::kUpstream, - MItDependencyGraph::kDepthFirst, - MItDependencyGraph::kNodeLevel); - - while (!it.isDone()) { - // We will walk along the node level of the DG until we spot a skinCluster - // node. - MObject c_node = it.thisNode(); - if (c_node.hasFn(MFn::kSkinClusterFilter)) { - // We've found the cluster handle. Try to get the weight data. - MFnSkinCluster cluster(c_node, &status); - if (!status) { - status.perror("MFnSkinCluster constructor"); - return false; - } - - // Get the set of objects that influence the vertices of this mesh. - // Hopefully these will all be joints. - MDagPathArray influence_objects; - cluster.influenceObjects(influence_objects, &status); - if (!status) { - status.perror("MFnSkinCluster::influenceObjects"); - - } else { - // Fill up the vector with the corresponding table of egg groups for - // each joint. - joints.clear(); - for (unsigned oi = 0; oi < influence_objects.length(); oi++) { - MDagPath joint_dag_path = influence_objects[oi]; - MayaNodeDesc *joint_node_desc = _tree.build_node(joint_dag_path); - EggGroup *joint = _tree.get_egg_group(joint_node_desc); - joints.push_back(joint); - } - - // Now use a component object to retrieve all of the weight data in - // one API call. - MFnSingleIndexedComponent sic; - MObject sic_object = sic.create(MFn::kMeshVertComponent); - sic.setCompleteData(mesh.numVertices()); - unsigned influence_count; - - status = cluster.getWeights(dag_path, sic_object, - weights, influence_count); - if (!status) { - status.perror("MFnSkinCluster::getWeights"); - } else { - if (influence_count != influence_objects.length()) { - mayaegg_cat.error() - << "MFnSkinCluster::influenceObjects() returns " - << influence_objects.length() - << " objects, but MFnSkinCluster::getWeights() reports " - << influence_count << " objects.\n"; - - } else { - // We've got the weights and the set of objects. That's all we - // need. - return true; - } - } - } - } else if (c_node.hasFn(MFn::kWeightGeometryFilt)) { - // We've found the joint cluster handle. (rigid Binding) - MFnWeightGeometryFilter cluster(c_node, &status); - if (!status) { - status.perror("MFnWeightGeometryFilter constructor"); - return false; - } - - MPlug matrix_plug = cluster.findPlug("matrix"); - if (!matrix_plug.isNull()) { - MPlugArray matrix_pa; - matrix_plug.connectedTo(matrix_pa, true, false, &status); - if (!status) { - status.perror("Can't find connected Joint"); - } else { - MObject jointObj = matrix_pa[0].node(); - MFnIkJoint jointFn(jointObj, &status); - if (!status) { - status.perror("Can't find connected JointDag"); - } else { - joints.clear(); - MDagPath joint_dag_path = MDagPath(); - status = jointFn.getPath(joint_dag_path); - if (!status) { - status.perror("MFnIkJoint::dagPath"); - } else { - MayaNodeDesc *joint_node_desc = _tree.build_node(joint_dag_path); - EggGroup *joint = _tree.get_egg_group(joint_node_desc); - joints.push_back(joint); - - // Now use a component object to retrieve all of the weight data - // in one API call. - MFnSingleIndexedComponent sic; - MObject sic_object = sic.create(MFn::kMeshVertComponent); - sic.setCompleteData(mesh.numVertices()); - - status = cluster.getWeights(dag_path, sic_object, - weights); - if (!status) { - status.perror("MFnWeightGeometryFilter::getWeights"); - } else { - // We've got the weights and the set of objects. That's all - // we need. - return true; - } - } - } - } - } - } - - it.next(); - } - - // The mesh was not soft-skinned. - return false; -} - -/** - * As above, for a NURBS surface instead of a polygon mesh. - */ -bool MayaToEggConverter:: -get_vertex_weights(const MDagPath &dag_path, const MFnNurbsSurface &surface, - pvector &joints, MFloatArray &weights) { - MStatus status; - - // Since we are working with a NURBS surface the input attribute that - // creates the surface is named "create" - MObject attr = surface.attribute("create"); - - // Create the plug to the "create" attribute then use the DG iterator to - // walk through the DG, at the node level. - MPlug history(surface.object(), attr); - MItDependencyGraph it(history, MFn::kDependencyNode, - MItDependencyGraph::kUpstream, - MItDependencyGraph::kDepthFirst, - MItDependencyGraph::kNodeLevel); - - while (!it.isDone()) { - // We will walk along the node level of the DG until we spot a skinCluster - // node. - MObject c_node = it.thisNode(); - if (c_node.hasFn(MFn::kSkinClusterFilter)) { - // We've found the cluster handle. Try to get the weight data. - MFnSkinCluster cluster(c_node, &status); - if (!status) { - status.perror("MFnSkinCluster constructor"); - return false; - } - - // Get the set of objects that influence the vertices of this surface. - // Hopefully these will all be joints. - MDagPathArray influence_objects; - cluster.influenceObjects(influence_objects, &status); - if (!status) { - status.perror("MFnSkinCluster::influenceObjects"); - - } else { - // Fill up the vector with the corresponding table of egg groups for - // each joint. - joints.clear(); - for (unsigned oi = 0; oi < influence_objects.length(); oi++) { - MDagPath joint_dag_path = influence_objects[oi]; - MayaNodeDesc *joint_node_desc = _tree.build_node(joint_dag_path); - EggGroup *joint = _tree.get_egg_group(joint_node_desc); - joints.push_back(joint); - } - - // Now use a component object to retrieve all of the weight data in - // one API call. - MFnDoubleIndexedComponent dic; - MObject dic_object = dic.create(MFn::kSurfaceCVComponent); - dic.setCompleteData(surface.numCVsInU(), surface.numCVsInV()); - unsigned influence_count; - - status = cluster.getWeights(dag_path, dic_object, - weights, influence_count); - if (!status) { - status.perror("MFnSkinCluster::getWeights"); - } else { - if (influence_count != influence_objects.length()) { - mayaegg_cat.error() - << "MFnSkinCluster::influenceObjects() returns " - << influence_objects.length() - << " objects, but MFnSkinCluster::getWeights() reports " - << influence_count << " objects.\n"; - - } else { - // We've got the weights and the set of objects. That's all we - // need. - return true; - } - } - } - } - - it.next(); - } - - // The surface was not soft-skinned. - return false; -} - -/** - * Applies the known shader attributes to the indicated egg primitive. Note: - * For multi-textures, Maya lists the top most texture in slot 0. But Panda - * puts the base texture at slot 0. Hence I parse the list of textures from - * last to first. - */ -void MayaToEggConverter:: -set_shader_attributes(EggPrimitive &primitive, const MayaShader &shader, - bool mesh) { - if (shader._legacy_mode) { - set_shader_legacy(primitive, shader, mesh); - } else { - set_shader_modern(primitive, shader, mesh); - } -} - -/** - * The modern implementation of set_shader_attributes. - * - * In the modern codepath, the MayaShader is a direct, literal representation - * of a list of EggTextures. All this exporter has to do is translate the - * list without interpretation. All the complex interpretation is handled - * elsewhere, in the MayaShader module. - */ -void MayaToEggConverter:: -set_shader_modern(EggPrimitive &primitive, const MayaShader &shader, - bool mesh) { - - for (size_t idx=0; idx < shader._all_maps.size(); idx++) { - MayaShaderColorDef *def = shader._all_maps[idx]; - if ((def->_is_alpha)&&(def->_opposite != 0)) { - // This texture represents an alpha-filename. It doesn't get its own - // - continue; - } - - EggTexture tex(shader.get_name(), ""); - tex.set_format(def->_is_alpha ? EggTexture::F_alpha : EggTexture::F_rgb); - apply_texture_filename(tex, *def); - if (def->_opposite) { - apply_texture_alpha_filename(tex, *def); - } - apply_texture_uvprops(tex, *def); - apply_texture_blendtype(tex, *def); - tex.set_uv_name(def->get_panda_uvset_name()); - - EggTexture *new_tex = - _textures.create_unique_texture(tex, ~0); - primitive.add_texture(new_tex); - } -} - -/** - * The legacy implementation of set_shader_attributes. The old behavior of - * the exporter is just plain weird. It seems to be a result of an - * inexperienced coder who made some core mistakes, and then patched them up - * with kludges. It seems to produce plausible results in certain specific - * cases, but overall, it doesn't make any sense. Unfortunately, this weird - * behavior cannot be discarded - vast numbers of 3D models have been created - * that rely on this behavior. The solution is to compartmentalize the - * weirdness. The legacy codepath, when activated, implements the old weird - * behavior. A brand-new codepath that shares almost nothing with the legacy - * codepath implements a much more straightforward behavior. - */ -void MayaToEggConverter:: -set_shader_legacy(EggPrimitive &primitive, const MayaShader &shader, - bool mesh) { - - // determine if the base texture or any of the top texture need to be rgb - // only - MayaShaderColorDef *color_def = nullptr; - bool is_rgb = false; - bool is_decal = false; - bool is_interpolate = false; - int i; - // last shader is the base so lets skip it - for (i=0; i<(int)shader._color.size()-1; ++i) { - color_def = shader.get_color_def(i); - if (color_def->_has_texture) { - if ((EggTexture::EnvType)color_def->_interpolate) { - is_interpolate = true; - } - else if ((EggTexture::EnvType)color_def->_blend_type == EggTexture::ET_modulate) { - // Maya's multiply is slightly different than panda's. Unless, - // _keep_alpha is set, we are dropping the alpha. - if (!color_def->_keep_alpha) - is_rgb = true; // modulate forces the alpha to be ignored - } - else if ((EggTexture::EnvType)color_def->_blend_type == EggTexture::ET_decal) { - is_decal = true; - } - } - } - - // we don't want an extra light stage for interpolate mode, it takes care of - // automatically - if (is_interpolate) - is_decal = false; - - // new decal mode needs an extra dummy layers of textureStage - EggTexture *dummy_tex = nullptr; - string dummy_uvset_name; - - // In Maya, a polygon is either textured or colored. The texture, if - // present, replaces the color. Also now there could be multiple textures - const MayaShaderColorDef &trans_def = shader._transparency; - for (i=shader._color.size()-1; i>=0; --i) { - color_def = shader.get_color_def(i); - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "slot " << i << ":got color_def: " << color_def << endl; - } - if (color_def->_has_texture || trans_def._has_texture) { - EggTexture tex(shader.get_name(), ""); - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "got shader name:" << shader.get_name() << endl; - mayaegg_cat.spam() << "ssa:texture name[" << i << "]: " << color_def->_texture_name << endl; - } - - string uvset_name = _shaders.find_uv_link(color_def->_texture_name); - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "ssa:corresponding uvset name is " << uvset_name << endl; - } - - if (color_def->_has_texture) { - // If we have a texture on color, apply it as the filename. if - // (mayaegg_cat.is_debug()) { mayaegg_cat.debug() << "ssa:got texture - // name" << color_def->_texture_filename << endl; } - Filename filename = Filename::from_os_specific(color_def->_texture_filename); - Filename fullpath, outpath; - _path_replace->full_convert_path(filename, get_model_path(), fullpath, outpath); - tex.set_filename(outpath); - tex.set_fullpath(fullpath); - apply_texture_uvprops(tex, *color_def); - - // If we also have a texture on transparency, apply it as the alpha - // filename. - if (trans_def._has_texture) { - if (color_def->_wrap_u != trans_def._wrap_u || - color_def->_wrap_u != trans_def._wrap_u) { - mayaegg_cat.warning() - << "Shader " << shader.get_name() - << " has contradictory wrap modes on color and texture.\n"; - } - - if (!compare_texture_uvprops(tex, trans_def)) { - // Only report each broken shader once. - static pset bad_shaders; - if (bad_shaders.insert(shader.get_name()).second) { - mayaegg_cat.error() - << "Color and transparency texture properties differ on shader " - << shader.get_name() << "\n"; - } - } - // tex.set_format(EggTexture::F_rgba); - - // We should try to be smarter about whether the transparency value - // is connected to the texture's alpha channel or to its grayscale - // channel. However, I'm not sure how to detect this at the moment; - // rather than spending days trying to figure out, for now I'll just - // assume that if the same texture image is used for both color and - // transparency, then the artist meant to use the alpha channel for - // transparency. - if (trans_def._texture_filename == color_def->_texture_filename) { - // That means that we don't need to do anything special: use all - // the channels of the texture. - - } else { - // Otherwise, pull the alpha channel from the other image file. - // Ideally, we should figure out which channel from the other - // image supplies alpha (and specify this via - // set_alpha_file_channel()), but for now we assume it comes from - // the grayscale data. - filename = Filename::from_os_specific(trans_def._texture_filename); - _path_replace->full_convert_path(filename, get_model_path(), - fullpath, outpath); - tex.set_alpha_filename(outpath); - tex.set_alpha_fullpath(fullpath); - } - } else { - // If there is no transparency texture specified, we don't have any - // transparency, so tell the egg format to ignore any alpha channel - // that might be on the color texture. - // tex.set_format(EggTexture::F_rgb); - } - - if (shader._color.size() > 1) { - // if multi-textured, first texture in maya is on top, so last - // shader on the list is the base one, which should always pick up - // the alpha from the texture file. But the top textures may have - // to strip the alpha - if ((size_t)i != shader._color.size() - 1) { - if (!i && is_interpolate) { - // this is the grass path mode where alpha on this texture - // determines whether to show layer1 or layer2. Since by now - // other layers are set lets change those to get this effect - tex.set_combine_mode(EggTexture::CC_rgb, EggTexture::CM_interpolate); - tex.set_combine_source(EggTexture::CC_rgb, 0, EggTexture::CS_previous); - tex.set_combine_operand(EggTexture::CC_rgb, 0, EggTexture::CO_src_color); - tex.set_combine_source(EggTexture::CC_rgb, 1, EggTexture::CS_last_saved_result); - tex.set_combine_operand(EggTexture::CC_rgb, 1, EggTexture::CO_src_color); - tex.set_combine_source(EggTexture::CC_rgb, 2, EggTexture::CS_texture); - tex.set_combine_operand(EggTexture::CC_rgb, 2, EggTexture::CO_src_alpha); - - tex.set_combine_mode(EggTexture::CC_alpha, EggTexture::CM_interpolate); - tex.set_combine_source(EggTexture::CC_alpha, 0, EggTexture::CS_previous); - tex.set_combine_operand(EggTexture::CC_alpha, 0, EggTexture::CO_src_alpha); - tex.set_combine_source(EggTexture::CC_alpha, 1, EggTexture::CS_last_saved_result); - tex.set_combine_operand(EggTexture::CC_alpha, 1, EggTexture::CO_src_alpha); - tex.set_combine_source(EggTexture::CC_alpha, 2, EggTexture::CS_texture); - tex.set_combine_operand(EggTexture::CC_alpha, 2, EggTexture::CO_src_alpha); - } - else { - if (is_interpolate) { - tex.set_combine_mode(EggTexture::CC_rgb, EggTexture::CM_modulate); - tex.set_combine_source(EggTexture::CC_rgb, 0, EggTexture::CS_primary_color); - tex.set_combine_operand(EggTexture::CC_rgb, 0, EggTexture::CO_src_color); - tex.set_combine_source(EggTexture::CC_rgb, 1, EggTexture::CS_texture); - tex.set_combine_operand(EggTexture::CC_rgb, 1, EggTexture::CO_src_color); - } - else { - tex.set_env_type((EggTexture::EnvType)color_def->_blend_type); - if (tex.get_env_type() == EggTexture::ET_modulate) { - if (color_def->_has_alpha_channel) { - // lets caution the artist that they should not be using a - // alpha channel on this texture. - if (mayaegg_cat.is_spam()) { - maya_cat.spam() - << color_def->_texture_name - << " should not have alpha channel in multiply mode: ignoring\n"; - } - } - if (is_rgb) { - // tex.set_alpha_mode(EggRenderMode::AM_off); force - // alpha off - tex.set_format(EggTexture::F_rgb); // Change the format to be rgb only - } - } - } - } - } - else { - if (is_interpolate) { - // base shader need to save result - tex.set_saved_result(true); - } - else if (is_decal) { - // decal in classic time, always overwrote the base color. That - // causes problem when the polygon wants to be lit or wants to - // retain vertexpolygon color In the new decal mode, we achieve - // this with a third dummy layer copy this layer to a new dummy - // layer - EggTexture texDummy(shader.get_name()+".dummy", ""); - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() << "creating dummy shader: " << texDummy.get_name() << endl; - } - texDummy.set_filename(outpath); - texDummy.set_fullpath(fullpath); - apply_texture_uvprops(texDummy, *color_def); - texDummy.set_combine_mode(EggTexture::CC_rgb, EggTexture::CM_modulate); - texDummy.set_combine_source(EggTexture::CC_rgb, 0, EggTexture::CS_primary_color); - texDummy.set_combine_operand(EggTexture::CC_rgb, 0, EggTexture::CO_src_color); - texDummy.set_combine_source(EggTexture::CC_rgb, 1, EggTexture::CS_previous); - texDummy.set_combine_operand(EggTexture::CC_rgb, 1, EggTexture::CO_src_color); - dummy_tex = _textures.create_unique_texture(texDummy, ~0); - - // make this layer ET_replace - tex.set_env_type(EggTexture::ET_replace); - } - } - } - } else { // trans_def._has_texture - // We have a texture on transparency only. Apply it as the primary - // filename, and set the format accordingly. - Filename filename = Filename::from_os_specific(trans_def._texture_filename); - Filename fullpath,outpath; - _path_replace->full_convert_path(filename, get_model_path(), - fullpath, outpath); - tex.set_filename(outpath); - tex.set_fullpath(fullpath); - tex.set_format(EggTexture::F_alpha); - apply_texture_uvprops(tex, trans_def); - } - - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() << "ssa:tref_name:" << tex.get_name() << endl; - } - if (is_rgb && i == (int)shader._color.size()-1) { - // make base layer rgb only - tex.set_format(EggTexture::F_rgb); // Change the format to be rgb only - } - EggTexture *new_tex = - _textures.create_unique_texture(tex, ~0); - - if (mesh) { - if (uvset_name.find("not found") == string::npos) { - primitive.add_texture(new_tex); - color_def->_uvset_name.assign(uvset_name.c_str()); - if (uvset_name != "map1") { - new_tex->set_uv_name(uvset_name); - } - if (i == (int)shader._color.size()-1 && is_decal) { - dummy_uvset_name.assign(color_def->_uvset_name); - } - } - } else { - primitive.add_texture(new_tex); - if (color_def->_uvset_name != "map1") { - new_tex->set_uv_name(color_def->_uvset_name); - } - } - } - } - if (dummy_tex != nullptr) { - primitive.add_texture(dummy_tex); - dummy_tex->set_uv_name(dummy_uvset_name); - } - // Also apply an overall color to the primitive. - LColor rgba = shader.get_rgba(); - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "ssa:rgba = " << rgba << endl; - } - - // The existence of a texture on either color channel completely replaces - // the corresponding flat color. - if (color_def && color_def->_has_texture) { - rgba[0] = 1.0f; - rgba[1] = 1.0f; - rgba[2] = 1.0f; - } - if (trans_def._has_texture) { - rgba[3] = 1.0f; - } - - // But the color gain always gets applied. - if (color_def) { - rgba[0] *= color_def->_color_gain[0]; - rgba[1] *= color_def->_color_gain[1]; - rgba[2] *= color_def->_color_gain[2]; - rgba[3] *= color_def->_color_gain[3]; - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "ssa:rgba = " << rgba << endl; - } - } - - primitive.set_color(rgba); - - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << " set_shader_attributes : end\n"; - } -} - -/** - * Applies all the appropriate texture properties to the EggTexture object, - * including wrap modes and texture matrix. - */ -void MayaToEggConverter:: -apply_texture_uvprops(EggTexture &tex, const MayaShaderColorDef &color_def) { - // Let's mipmap all textures by default. - tex.set_minfilter(EggTexture::FT_linear_mipmap_linear); - tex.set_magfilter(EggTexture::FT_linear); - - EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp; - EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp; - - tex.set_wrap_u(wrap_u); - tex.set_wrap_v(wrap_v); - - LMatrix3d mat = color_def.compute_texture_matrix(); - if (!mat.almost_equal(LMatrix3d::ident_mat())) { - tex.set_transform2d(mat); - } -} - -/** - * Applies the blendtype to the EggTexture. - */ -void MayaToEggConverter:: -apply_texture_blendtype(EggTexture &tex, const MayaShaderColorDef &color_def) { - switch (color_def._blend_type) { - case MayaShaderColorDef::BT_unspecified: - tex.set_env_type(EggTexture::ET_unspecified); - return; - case MayaShaderColorDef::BT_modulate: - tex.set_env_type(EggTexture::ET_modulate); - return; - case MayaShaderColorDef::BT_decal: - tex.set_env_type(EggTexture::ET_decal); - return; - case MayaShaderColorDef::BT_blend: - tex.set_env_type(EggTexture::ET_blend); - return; - case MayaShaderColorDef::BT_replace: - tex.set_env_type(EggTexture::ET_replace); - return; - case MayaShaderColorDef::BT_add: - tex.set_env_type(EggTexture::ET_add); - return; - case MayaShaderColorDef::BT_blend_color_scale: - tex.set_env_type(EggTexture::ET_blend_color_scale); - return; - case MayaShaderColorDef::BT_modulate_glow: - tex.set_env_type(EggTexture::ET_modulate_glow); - return; - case MayaShaderColorDef::BT_modulate_gloss: - tex.set_env_type(EggTexture::ET_modulate_gloss); - return; - case MayaShaderColorDef::BT_normal: - tex.set_env_type(EggTexture::ET_normal); - return; - case MayaShaderColorDef::BT_normal_height: - tex.set_env_type(EggTexture::ET_normal_height); - return; - case MayaShaderColorDef::BT_glow: - tex.set_env_type(EggTexture::ET_glow); - return; - case MayaShaderColorDef::BT_gloss: - tex.set_env_type(EggTexture::ET_gloss); - return; - case MayaShaderColorDef::BT_height: - tex.set_env_type(EggTexture::ET_height); - return; - case MayaShaderColorDef::BT_selector: - tex.set_env_type(EggTexture::ET_selector); - return; - } -} - -/** - * Applies the filename to the EggTexture. - */ -void MayaToEggConverter:: -apply_texture_filename(EggTexture &tex, const MayaShaderColorDef &def) { - Filename filename = Filename::from_os_specific(def._texture_filename); - Filename fullpath, outpath; - _path_replace->full_convert_path(filename, get_model_path(), fullpath, outpath); - tex.set_filename(outpath); - tex.set_fullpath(fullpath); -} - -/** - * Applies the alpha filename to the EggTexture. - */ -void MayaToEggConverter:: -apply_texture_alpha_filename(EggTexture &tex, const MayaShaderColorDef &def) { - if (def._opposite) { - tex.set_format(EggTexture::F_rgba); - if (def._opposite->_texture_filename != def._texture_filename) { - Filename filename = Filename::from_os_specific(def._opposite->_texture_filename); - Filename fullpath, outpath; - _path_replace->full_convert_path(filename, get_model_path(), fullpath, outpath); - tex.set_alpha_filename(outpath); - tex.set_alpha_fullpath(fullpath); - } - } -} - -/** - * Compares the texture properties already on the texture (presumably set by a - * previous call to apply_texture_uvprops()) and returns false if they differ - * from that specified by the indicated color_def object, or true if they - * match. - */ -bool MayaToEggConverter:: -compare_texture_uvprops(EggTexture &tex, - const MayaShaderColorDef &color_def) { - bool okflag = true; - - EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp; - EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp; - - if (wrap_u != tex.determine_wrap_u()) { - // Choose the more general of the two. - if (wrap_u == EggTexture::WM_repeat) { - tex.set_wrap_u(wrap_u); - } - okflag = false; - } - if (wrap_v != tex.determine_wrap_v()) { - if (wrap_v == EggTexture::WM_repeat) { - tex.set_wrap_v(wrap_v); - } - okflag = false; - } - - LMatrix3d m = color_def.compute_texture_matrix(); - LMatrix4d mat4(m(0, 0), m(0, 1), 0.0, m(0, 2), - m(1, 0), m(1, 1), 0.0, m(1, 2), - 0.0, 0.0, 1.0, 0.0, - m(2, 0), m(2, 1), 0.0, m(2, 2)); - if (!mat4.almost_equal(tex.get_transform3d())) { - okflag = false; - } - - return okflag; -} - -/** - * Recursively walks the egg hierarchy, reparenting "decal" type nodes below - * their corresponding "decalbase" type nodes, and setting the flags. - * - * Returns true on success, false if some nodes were incorrect. - */ -bool MayaToEggConverter:: -reparent_decals(EggGroupNode *egg_parent) { - bool okflag = true; - - // First, walk through all children of this node, looking for the one decal - // base, if any. - EggGroup *decal_base = nullptr; - pvector decal_children; - - EggGroupNode::iterator ci; - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroup::get_class_type())) { - EggGroup *child_group = DCAST(EggGroup, child); - if (child_group->has_object_type("decalbase")) { - if (decal_base != nullptr) { - mayaegg_cat.error() - << "Two children of " << egg_parent->get_name() - << " both have decalbase set: " << decal_base->get_name() - << " and " << child_group->get_name() << "\n"; - okflag = false; - } - child_group->remove_object_type("decalbase"); - decal_base = child_group; - - } else if (child_group->has_object_type("decal")) { - child_group->remove_object_type("decal"); - decal_children.push_back(child_group); - } - } - } - - if (decal_base == nullptr) { - if (!decal_children.empty()) { - mayaegg_cat.warning() - << decal_children.front()->get_name() - << " has decal, but no sibling node has decalbase.\n"; - } - - } else { - if (decal_children.empty()) { - mayaegg_cat.warning() - << decal_base->get_name() - << " has decalbase, but no sibling nodes have decal.\n"; - - } else { - // All the decal children get moved to be a child of decal base. This - // usually will not affect the vertex positions, but it could if the - // decal base has a transform and the decal child is an instance node. - // So don't do that. - pvector::iterator di; - for (di = decal_children.begin(); di != decal_children.end(); ++di) { - EggGroup *child_group = (*di); - decal_base->add_child(child_group); - } - - // Also set the decal state on the base. - decal_base->set_decal_flag(true); - } - } - - // Now recurse on each of the child nodes. - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroupNode::get_class_type())) { - EggGroupNode *child_group = DCAST(EggGroupNode, child); - if (!reparent_decals(child_group)) { - okflag = false; - } - } - } - - return okflag; -} - -/** - * Returns the TransformType value corresponding to the indicated string, or - * TT_invalid. - */ -MayaToEggConverter::TransformType MayaToEggConverter:: -string_transform_type(const string &arg) { - if (cmp_nocase(arg, "all") == 0) { - return TT_all; - } else if (cmp_nocase(arg, "model") == 0) { - return TT_model; - } else if (cmp_nocase(arg, "dcs") == 0) { - return TT_dcs; - } else if (cmp_nocase(arg, "none") == 0) { - return TT_none; - } else { - return TT_invalid; - } -} -/** - * Checks to see if we're using legacy or modern shaders and based on the - * result, it passes the vertex color calculations off to either the legacy or - * modern vertex color functions. - */ -void MayaToEggConverter:: -set_vertex_color(EggVertex &vert, MItMeshPolygon &pi, int vert_index, const MayaShader *shader, const LColor &color) { - if (shader == nullptr || shader->_legacy_mode) { - set_vertex_color_legacy(vert, pi, vert_index, shader, color); - } else { - set_vertex_color_modern(vert, pi, vert_index, shader, color); - } -} -/** - * Calls set_color on an EggVertex, determining the correct color values, - * based on the shader, vert_color Maya's vertex & flat color(s). This is the - * original implementation that works only on Lambert shaders/materials in - * Maya. - */ -void MayaToEggConverter:: -set_vertex_color_legacy(EggVertex &vert, MItMeshPolygon &pi, int vert_index, const MayaShader *shader, const LColor &color){ - if (pi.hasColor()) { - MColor c; - MStatus status = pi.getColor(c, vert_index); - if (!status) { - status.perror("MItMeshPolygon::getColor"); - } else { - // I saw instances where the color components exceeded 1.0 so lets clamp - // the values to 0 to 1 - c /= 1.0; - // The vertex color is a color scale that modifies the polygon color, - // not an override that replaces it. - vert.set_color(LColor(c.r * color[0], c.g * color[1], c.b * color[2], c.a * color[3])); - - if (mayaegg_cat.is_spam()) { - mayaegg_cat.spam() << "maya_color = " << c.r << " " << c.g << " " << c.b << " " << c.a << endl; - mayaegg_cat.spam() << "vert_color = " << vert.get_color() << endl; - } - } - } else { - vert.set_color(color); - } - -} -/** - * Calls set_color on an EggVertex, determining the correct color values, - * based on the shader, vert_color Maya's vertex & flat color(s). This - * implementation is designed to work specifically with Phong materials or - * shaders. - */ -void MayaToEggConverter:: -set_vertex_color_modern(EggVertex &vert, MItMeshPolygon &pi, int vert_index, const MayaShader *shader, const LColor &color) { - // If there's an explicit vertex color, output it. - if (pi.hasColor(vert_index)) { - MColor c; - MStatus status = pi.getColor(c, vert_index); - if (status) { - vert.set_color(LColor(c.r, c.g, c.b, c.a)); - return; - } - } - - // If there's no explicit color, use flat color, or white on a textured - // model. - if (shader->_color_maps.empty()) { - const LColord &c = shader->_flat_color; - vert.set_color(LColor((PN_stdfloat)c[0], (PN_stdfloat)c[1], (PN_stdfloat)c[2], (PN_stdfloat)c[3])); - } else { - // there's no explicit color anywhere, must be textured (or blank) - vert.set_color(LColor(1.0f, 1.0f, 1.0f, 1.0f)); - } -} diff --git a/pandatool/src/mayaegg/mayaToEggConverter.h b/pandatool/src/mayaegg/mayaToEggConverter.h deleted file mode 100644 index c2266e00962..00000000000 --- a/pandatool/src/mayaegg/mayaToEggConverter.h +++ /dev/null @@ -1,203 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaToEggConverter.h - * @author drose - * @date 1999-11-10 - */ - -#ifndef MAYATOEGGCONVERTER_H -#define MAYATOEGGCONVERTER_H - -#include "pandatoolbase.h" -#include "somethingToEggConverter.h" -#include "mayaNodeTree.h" - -#include "mayaApi.h" -#include "mayaShaders.h" -#include "mayaShaderColorDef.h" -#include "eggTextureCollection.h" -#include "distanceUnit.h" -#include "coordinateSystem.h" -#include "globPattern.h" -#include "pvector.h" -#include "vector_string.h" - -#include "pre_maya_include.h" -#include -#include -#include "post_maya_include.h" - -class EggData; -class EggGroup; -class EggTable; -class EggVertexPool; -class EggNurbsCurve; -class EggPrimitive; -class EggXfmSAnim; -class MayaShaderColorDef; - -/** - * This class supervises the construction of an EggData structure from a - * single Maya file, or from the data already in the global Maya model space. - * - * Note that since the Maya API presents just one global model space, it is - * not possible to simultaneously load two distinct Maya files. - */ -class MayaToEggConverter : public SomethingToEggConverter { -public: - MayaToEggConverter(const std::string &program_name = ""); - MayaToEggConverter(const MayaToEggConverter ©); - virtual ~MayaToEggConverter(); - - virtual SomethingToEggConverter *make_copy(); - - virtual std::string get_name() const; - virtual std::string get_extension() const; - virtual std::string get_additional_extensions() const; - - virtual bool convert_file(const Filename &filename); - virtual DistanceUnit get_input_units(); - - void clear_subroots(); - void add_subroot(const GlobPattern &glob); - - void clear_subsets(); - void add_subset(const GlobPattern &glob); - - void clear_excludes(); - void add_exclude(const GlobPattern &glob); - - void clear_ignore_sliders(); - void add_ignore_slider(const GlobPattern &glob); - bool ignore_slider(const std::string &name) const; - - void clear_force_joints(); - void add_force_joint(const GlobPattern &glob); - bool force_joint(const std::string &name) const; - - void set_from_selection(bool from_selection); - - bool convert_maya(); - - void clear(); - - bool open_api(bool revert_directory=true); - void close_api(); - -private: - bool convert_flip(double start_frame, double end_frame, - double frame_inc, double output_frame_rate); - - bool convert_char_model(); - bool convert_char_chan(double start_frame, double end_frame, - double frame_inc, double output_frame_rate); - bool convert_hierarchy(EggGroupNode *egg_root); - bool process_model_node(MayaNodeDesc *node_desc); - - void get_transform(MayaNodeDesc *node_desc, const MDagPath &dag_path, - EggGroup *egg_group); - void get_joint_transform(const MDagPath &dag_path, EggGroup *egg_group); - void apply_lod_attributes(EggGroup *egg_group, MFnDagNode &lod_group); - - // I ran into core dumps trying to pass around a MFnMesh object by value. - // From now on, all MFn* objects will be passed around by reference. void - // make_tex_names(const MFnMesh &mesh, const MObject &mesh_object); - - void make_nurbs_surface(MayaNodeDesc *node_desc, - const MDagPath &dag_path, - MFnNurbsSurface &surface, - EggGroup *group); - EggNurbsCurve *make_trim_curve(const MFnNurbsCurve &curve, - const std::string &nurbs_name, - EggGroupNode *egg_group, - int trim_curve_index); - void make_nurbs_curve(const MDagPath &dag_path, - const MFnNurbsCurve &curve, - EggGroup *group); - void make_polyset(MayaNodeDesc *node_desc, const MDagPath &dag_path, - const MFnMesh &mesh, EggGroup *egg_group, - MayaShader *default_shader = nullptr); - void make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group); - void make_camera_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group); - void make_light_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group); - bool get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, - pvector &joints, MFloatArray &weights); - bool get_vertex_weights(const MDagPath &dag_path, const MFnNurbsSurface &surface, - pvector &joints, MFloatArray &weights); - void apply_texture_uvprops(EggTexture &tex, - const MayaShaderColorDef &color_def); - void apply_texture_blendtype(EggTexture &tex, - const MayaShaderColorDef &color_def); - void apply_texture_filename(EggTexture &tex, - const MayaShaderColorDef &color_def); - void apply_texture_alpha_filename(EggTexture &tex, - const MayaShaderColorDef &color_def); - bool compare_texture_uvprops(EggTexture &tex, - const MayaShaderColorDef &color_def); - bool reparent_decals(EggGroupNode *egg_parent); - void set_shader_attributes(EggPrimitive &primitive, const MayaShader &shader, - bool mesh = false); - void set_shader_modern(EggPrimitive &primitive, const MayaShader &shader, - bool mesh); - void set_shader_legacy(EggPrimitive &primitive, const MayaShader &shader, - bool mesh); - void set_vertex_color(EggVertex &vert, MItMeshPolygon &pi, int vert_index, const MayaShader *shader, const LColor &color); - - void set_vertex_color_legacy(EggVertex &vert, MItMeshPolygon &pi, int vert_index, const MayaShader *shader, const LColor &color); - - void set_vertex_color_modern(EggVertex &vert, MItMeshPolygon &pi, int vert_index, const MayaShader *shader, const LColor &color); - - int round(double value); - - std::string _program_name; - - bool _from_selection; - std::string _subroot; - typedef pvector Globs; - Globs _subsets; - Globs _subroots; - Globs _excludes; - Globs _ignore_sliders; - Globs _force_joints; - - MayaNodeTree _tree; - -public: - MayaShaders _shaders; - EggTextureCollection _textures; - PT(MayaApi) _maya; - - bool _polygon_output; - double _polygon_tolerance; - bool _respect_maya_double_sided; - bool _always_show_vertex_color; - bool _keep_all_uvsets; - bool _convert_cameras; - bool _convert_lights; - bool _round_uvs; - bool _legacy_shader; - - - enum TransformType { - TT_invalid, - TT_all, - TT_model, - TT_dcs, - TT_none, - }; - TransformType _transform_type; - - static TransformType string_transform_type(const std::string &arg); -}; - - -#endif diff --git a/pandatool/src/mayaegg/p3mayaegg_composite1.cxx b/pandatool/src/mayaegg/p3mayaegg_composite1.cxx deleted file mode 100644 index 75ab5187af9..00000000000 --- a/pandatool/src/mayaegg/p3mayaegg_composite1.cxx +++ /dev/null @@ -1,6 +0,0 @@ -#include "config_mayaegg.cxx" -#include "mayaEggGroupUserData.cxx" -#include "mayaBlendDesc.cxx" -#include "mayaNodeDesc.cxx" -#include "mayaNodeTree.cxx" -#include "mayaToEggConverter.cxx" diff --git a/pandatool/src/mayaprogs/blend_test.cxx b/pandatool/src/mayaprogs/blend_test.cxx deleted file mode 100644 index ed03fd36613..00000000000 --- a/pandatool/src/mayaprogs/blend_test.cxx +++ /dev/null @@ -1,240 +0,0 @@ - -#include -#include -#include -#include - -#ifndef _BOOL -#define _BOOL 1 -#endif - -#define REQUIRE_IOSTREAM - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::cerr; - -void -scan_nodes() { - MStatus status; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - exit(1); - } - - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - exit(1); - } - - MFnDagNode dag_node(dag_path, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - exit(1); - } - - cerr << dag_node.name() << "\n"; - - dag_iterator.next(); - } -} - -MFnBlendShapeDeformer * -get_slider(MString slider_name) { - MStatus status; - - status = MGlobal::selectByName(slider_name, MGlobal::kReplaceList); - if (!status) { - status.perror(slider_name); - exit(1); - } - MSelectionList list; - status = MGlobal::getActiveSelectionList(list); - if (!status) { - status.perror("MGLobal::getActiveSelectionList"); - exit(1); - } - - unsigned int num_objects = list.length(); - if (num_objects != 1) { - cerr << "Warning: multiple objects match " << slider_name << "\n"; - } - - for (unsigned int i = 0; i < num_objects; i++) { - MObject obj; - status = list.getDependNode(i, obj); - if (!status) { - cerr << "selected element is not a dependency node.\n"; - status.perror("getDependNode"); - } else { - if (obj.hasFn(MFn::kBlendShape)) { - MFnBlendShapeDeformer *slider = new MFnBlendShapeDeformer(obj, &status); - if (!status) { - status.perror("MFnBlendShapeDeformer constructor"); - } else { - cerr << "got slider " << slider->name() << "\n"; - return slider; - } - } - - cerr << "selected element is not a blend shape\n"; - } - } - - cerr << "Couldn't find slider " << slider_name << "\n"; - exit(1); -} - -MFnMesh * -get_mesh(MString mesh_name) { - MStatus status; - - status = MGlobal::selectByName(mesh_name, MGlobal::kReplaceList); - if (!status) { - status.perror(mesh_name); - exit(1); - } - MSelectionList list; - status = MGlobal::getActiveSelectionList(list); - if (!status) { - status.perror("MGLobal::getActiveSelectionList"); - exit(1); - } - - unsigned int num_objects = list.length(); - if (num_objects != 1) { - cerr << "Warning: multiple objects match " << mesh_name << "\n"; - } - - for (unsigned int i = 0; i < num_objects; i++) { - MObject obj; - status = list.getDependNode(i, obj); - if (!status) { - cerr << "selected element is not a dependency node.\n"; - status.perror("getDependNode"); - - } else { - if (obj.hasFn(MFn::kMesh)) { - // Maybe it's a mesh object itself. - MFnMesh *mesh = new MFnMesh(obj, &status); - if (!status) { - status.perror("MFnMesh constructor"); - } else { - cerr << "got mesh " << mesh->name() << "\n"; - return mesh; - } - - } else if (obj.hasFn(MFn::kDagNode)) { - // Maybe it's a dag node. - MDagPath path; - status = MDagPath::getAPathTo(obj, path); - if (!status) { - status.perror("MDagPath::getAPathTo"); - exit(1); - } - if (path.hasFn(MFn::kMesh)) { - MFnMesh *mesh = new MFnMesh(path, &status); - if (!status) { - status.perror("MFnMesh constructor"); - } else { - cerr << "got mesh " << mesh->name() << "\n"; - return mesh; - } - } - } - - cerr << "selected element is not a mesh\n"; - } - } - - cerr << "Couldn't find mesh " << mesh_name << "\n"; - exit(1); -} - -void -output_vertices(const char *filename, MFnMesh &mesh) { - MStatus status; - - MPointArray verts; - // status = mesh.getPoints(verts, MSpace::kObject); - status = mesh.getPoints(verts, MSpace::kWorld); - if (!status) { - status.perror("mesh.getPoints"); - exit(1); - } - - std::ofstream file(filename, std::ios::out | std::ios::trunc); - if (!file) { - cerr << "Couldn't open " << filename << " for output.\n"; - exit(1); - } - - unsigned int num_verts = verts.length(); - cerr << "writing " << num_verts << " vertices to " << filename << "\n"; - for (unsigned int i = 0; i < num_verts; i++) { - file << i << ". " << verts[i] << "\n"; - } -} - -int -main(int argc, char *argv[]) { - cerr << "Initializing Maya\n"; - MStatus status; - status = MLibrary::initialize(argv[0]); - if (!status) { - status.perror("Could not initialize"); - exit(1); - } - - cerr << "Using Maya library version " << MGlobal::mayaVersion() << "\n"; - - if (argc < 4) { - cerr << "\nUsage:\n\nblend_test.cxx file.mb slider_name mesh_name\n\n"; - exit(1); - } - - MString filename = argv[1]; - MString slider_name = argv[2]; - MString mesh_name = argv[3]; - - MFileIO::newFile(true); - - cerr << "Reading " << filename << "\n"; - status = MFileIO::open(filename); - if (!status) { - status.perror(filename); - exit(1); - } - - MFnBlendShapeDeformer *slider = get_slider(slider_name); - MFnMesh *mesh = get_mesh(mesh_name); - - cerr << "\nOriginal slider value is " << slider->weight(0) << "\n"; - - output_vertices("before.txt", *mesh); - - cerr << "Setting slider to 1\n"; - status = slider->setWeight(0, 1.0); - if (!status) { - status.perror("MFnBlendShapeDeformer::setWeight"); - exit(1); - } - - output_vertices("after.txt", *mesh); - - return 0; -} diff --git a/pandatool/src/mayaprogs/config_mayaloader.cxx b/pandatool/src/mayaprogs/config_mayaloader.cxx deleted file mode 100644 index 80ccd1f373a..00000000000 --- a/pandatool/src/mayaprogs/config_mayaloader.cxx +++ /dev/null @@ -1,55 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_mayaloader.cxx - * @author drose - * @date 2003-10-09 - */ - -#ifdef __MACH__ -#define __OPENTRANSPORTPROVIDERS__ -#endif - -#include "pandatoolbase.h" -#include "loaderFileTypePandatool.h" -#include "config_mayaegg.h" -#include "mayaToEggConverter.h" - -#include "dconfig.h" -#include "loaderFileTypeRegistry.h" - -Configure(config_mayaloader); - -void EXPCL_MISC init_libmayaloader(); - -ConfigureFn(config_mayaloader) { - init_libmayaloader(); -} - -/** - * Initializes the library. This must be called at least once before any of - * the functions or classes in this library can be used. Normally it will be - * called by the static initializers and need not be called explicitly, but - * special cases exist. - */ -void -init_libmayaloader() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - - LoaderFileTypePandatool::init_type(); - - LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_global_ptr(); - - init_libmayaegg(); - MayaToEggConverter *maya = new MayaToEggConverter; - reg->register_type(new LoaderFileTypePandatool(maya)); -} diff --git a/pandatool/src/mayaprogs/eggImportOptions.mel b/pandatool/src/mayaprogs/eggImportOptions.mel deleted file mode 100644 index cf75a777a0f..00000000000 --- a/pandatool/src/mayaprogs/eggImportOptions.mel +++ /dev/null @@ -1,110 +0,0 @@ - -global proc int eggImportOptions ( string $parent, - string $action, - string $initialSettings, - string $resultCallback ) -// -// Description: -// This script posts the OBJ file translator options. -// The optionsString is of the form: -// varName1=value1;varName2=value2;... -// -// Parameters: -// $parent - the elf parent layout for this options layout. It is -// always a scrollLayout. -// $action - the action that is to be performed with this invokation -// of this proc. Valid options are: -// "query" - construct the options string and pass it -// to the resultCallback. -// "post" - post all the elf controls. -// $initialSettings - the current options string in effect at the -// time this script is invoked. -// $resultCallback - -// This is the proc to be called with the result string. -// resultCallback ( string $optionsString ) -// -// Returns: -// 1 if successfull. -// 0 otherwise. -// -{ - int $bResult; - string $currentOptions; - string $optionList[]; - string $optionBreakDown[]; - int $index; - - if ($action == "post") { - setParent $parent; - - columnLayout -adj true objTypeCol; - radioButtonGrp - -l "Merge with Current Scene" - -nrb 2 -cw3 175 75 75 - -la2 "On" "Off" objMerge; - radioButtonGrp - -l "Import Model" - -nrb 2 -cw3 175 75 75 - -la2 "On" "Off" objModel; - radioButtonGrp - -l "Import Animation" - -nrb 2 -cw3 175 75 75 - -la2 "On" "Off" objAnim; - - $currentOptions = $initialSettings; - if (size($currentOptions) > 0) { - tokenize($currentOptions, ";", $optionList); - for ($index = 0; $index < size($optionList); $index++) { - tokenize($optionList[$index], "=", $optionBreakDown); - - if ($optionBreakDown[0] == "merge") { - if ($optionBreakDown[1] == "0") { - radioButtonGrp -e -sl 2 objMerge; - } else { - radioButtonGrp -e -sl 1 objMerge; - } - } else if ($optionBreakDown[0] == "model") { - if ($optionBreakDown[1] == "0") { - radioButtonGrp -e -sl 2 objModel; - } else { - radioButtonGrp -e -sl 1 objModel; - } - } else if ($optionBreakDown[0] == "anim") { - if ($optionBreakDown[1] == "0") { - radioButtonGrp -e -sl 2 objAnim; - } else { - radioButtonGrp -e -sl 1 objAnim; - } - } - } - } - $result = 1; - - } else if ($action == "query") { - - if (`radioButtonGrp -q -sl objMerge` == 1) { - $currentOptions = $currentOptions + "merge=1"; - } else { - $currentOptions = $currentOptions + "merge=0"; - } - - if (`radioButtonGrp -q -sl objModel` == 1) { - $currentOptions = $currentOptions + ";model=1"; - } else { - $currentOptions = $currentOptions + ";model=0"; - } - - if (`radioButtonGrp -q -sl objAnim` == 1) { - $currentOptions = $currentOptions + ";anim=1"; - } else { - $currentOptions = $currentOptions + ";anim=0"; - } - - eval($resultCallback+" \""+$currentOptions+"\""); - $result = 1; - } else { - $bResult = 0; - } - - return $bResult; -} diff --git a/pandatool/src/mayaprogs/eggToMaya.cxx b/pandatool/src/mayaprogs/eggToMaya.cxx deleted file mode 100644 index 36be9362db2..00000000000 --- a/pandatool/src/mayaprogs/eggToMaya.cxx +++ /dev/null @@ -1,169 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file eggToMaya.cxx - * @author drose - * @date 2005-08-11 - */ - -#include "eggToMaya.h" -#include "mayaEggLoader.h" -#include "mayaApi.h" -#include "mayaConversionServer.h" - -// We must define this to prevent Maya from doubly-declaring its MApiVersion -// string in this file as well as in libmayaegg. -#define _MApiVersion - -#include "pre_maya_include.h" -#include -#include -#include "post_maya_include.h" - -/** - * - */ -EggToMaya:: -EggToMaya() : - EggToSomething("Maya", ".mb", true, false) -{ - add_units_options(); - - set_binary_output(true); - set_program_brief("convert .egg files to Maya .mb or .ma files"); - set_program_description - ("egg2maya converts files from egg format to Maya .mb or .ma " - "format. It contains support for basic geometry (polygons with textures)." - "It also supports animation for joints."); - - add_option - ("a", "", 0, - "Convert animation tables.", - &EggToMaya::dispatch_none, &_convert_anim); - - add_option - ("m", "", 0, - "Convert polygon models. You may specify both -a and -m at the same " - "time. If you specify neither, the default is -m.", - &EggToMaya::dispatch_none, &_convert_model); - - add_option - ("nv", "", 0, - "respect vertex and polygon normals.", - &EggToMaya::dispatch_none, &_respect_normals); - - add_option("server", "", 0, - "Runs the Maya model conversion server. This server can be used in tandem " - "with the egg2maya_client and maya2egg_client utilities to batch convert " - "both Maya and Panda3D model files.", - &EggToMaya::dispatch_none, &_run_server); - - // Maya files always store centimeters. - _output_units = DU_centimeters; -} - -/** - * Attempts to create the global Maya API. - * Exits the program if unsuccessful. - */ -PT(MayaApi) EggToMaya:: -open_api() { - if (!MayaApi::is_api_valid()) { - nout << "Initializing Maya...\n"; - } - - PT(MayaApi) api = MayaApi::open_api(_program_name, true, true); - - if (!api || !api->is_valid()) { - nout << "Unable to initialize Maya.\n"; - exit(1); - } - - return api; -} - -/** - * Returns true if the model has been successfully converted. - */ -bool EggToMaya:: -run() { - if (!_convert_anim && !_convert_model) { - _convert_model = true; - } - - // Let's convert the output file to a full path before we initialize Maya, - // since Maya now has a nasty habit of changing the current directory. - _output_filename.make_absolute(); - - PT(MayaApi) maya = open_api(); - - MStatus status; - status = MFileIO::newFile(true); - if (!status) { - status.perror("Could not initialize file"); - return false; - } - - // [gjeon] since maya's internal unit is fixed to cm and when we can't - // change UI unit without affecting data all distance data is converted to - // cm we need to convert them back to proper output unit user provided here - // along with UI unit - maya->set_units(_output_units); - - if (_output_units != DU_centimeters && _output_units != DU_invalid) { - nout << "Converting from centimeters" - << " to " << format_long_unit(_output_units) << "\n"; - } - - // Now convert the data. - if (!MayaLoadEggData(_data, true, _convert_model, _convert_anim, _respect_normals)) { - nout << "Unable to convert egg file.\n"; - return false; - } - - if (!maya->write(_output_filename)) { - status.perror("Could not save file"); - return false; - } - - /* - // And write out the resulting Maya file. - string os_specific = _output_filename.to_os_generic(); - const char *file_type = NULL; - if (_output_filename.get_extension() == "mb") { - file_type = "mayaBinary"; - } - status = MFileIO::saveAs(os_specific.c_str(), file_type); - if (!status) { - status.perror("Could not save file"); - return false; - } - */ - - return true; -} - -/** - * Processes the arguments parsed by the program. - * - * If the server flag is specified, the Maya conversion server is started - * up rather than the usual conversion utility functionality. - */ -bool EggToMaya:: -handle_args(ProgramBase::Args &args) { - if (_run_server) { - open_api(); - - MayaConversionServer server; - server.listen(); - exit(0); - return true; - } - - return EggToSomething::handle_args(args); -} diff --git a/pandatool/src/mayaprogs/eggToMaya.h b/pandatool/src/mayaprogs/eggToMaya.h deleted file mode 100644 index d18dc928d11..00000000000 --- a/pandatool/src/mayaprogs/eggToMaya.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file eggToMaya.h - * @author drose - * @date 2005-08-11 - */ - -#ifndef EGGTOMAYA_H -#define EGGTOMAYA_H - -#include "pandatoolbase.h" - -#include "eggToSomething.h" -#include "mayaApi.h" - -#include "programBase.h" - -/** - * A program to read an egg file and write a maya file. - */ -class EggToMaya : public EggToSomething { -public: - EggToMaya(); - - bool run(); - -private: - virtual bool handle_args(ProgramBase::Args &args); - - PT(MayaApi) open_api(); - - bool _convert_anim; - bool _convert_model; - bool _respect_normals; - bool _run_server; -}; - -#endif diff --git a/pandatool/src/mayaprogs/eggToMayaBin.cxx b/pandatool/src/mayaprogs/eggToMayaBin.cxx deleted file mode 100644 index e388255aace..00000000000 --- a/pandatool/src/mayaprogs/eggToMayaBin.cxx +++ /dev/null @@ -1,28 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file eggToMayaBin.cxx - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#include "eggToMaya.h" - -/** - * Entrypoint for egg2maya. - */ -int main(int argc, char *argv[]) { - EggToMaya prog; - prog.parse_command_line(argc, argv); - - if (!prog.run()) { - return 1; - } - - return 0; -} diff --git a/pandatool/src/mayaprogs/eggToMayaClient.cxx b/pandatool/src/mayaprogs/eggToMayaClient.cxx deleted file mode 100644 index e3f95155f45..00000000000 --- a/pandatool/src/mayaprogs/eggToMayaClient.cxx +++ /dev/null @@ -1,22 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file eggToMayaClient.cxx - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#include "mayaConversionClient.h" - -/** - * Entrypoint for egg2maya_client. - */ -int main(int argc, char *argv[]) { - MayaConversionClient client; - return client.main(argc, argv, MayaConversionServer::ConversionType::CT_egg_to_maya); -} diff --git a/pandatool/src/mayaprogs/mayaConversionClient.cxx b/pandatool/src/mayaprogs/mayaConversionClient.cxx deleted file mode 100644 index 83735f3186c..00000000000 --- a/pandatool/src/mayaprogs/mayaConversionClient.cxx +++ /dev/null @@ -1,189 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaConversionClient.cxx - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#include "mayaConversionClient.h" -#include "mayaConversionServer.h" -#include "datagramIterator.h" - -/** - * Initializes the Maya conversion client. - */ -MayaConversionClient:: -MayaConversionClient() : _reader(&_manager, 0), _writer(&_manager, 0) -{ -} - -/** - * Cleans up the Maya conversison client's pending connections. - */ -MayaConversionClient:: -~MayaConversionClient() { - close(); -} - -/** - * Attempts to connect to a Maya conversion server. - * If a connection is already active, it will be removed. - * - * Returns true if the connection was created successfully. - */ -bool MayaConversionClient:: -connect(NetAddress server) { - if (_conn) { - // Remove this connection from the readers list - _reader.remove_connection(_conn); - _conn = nullptr; - } - - // Attempt to open a connection - _conn = _manager.open_TCP_client_connection(server, 0); - - if (!_conn || _conn.is_null()) { - // This connection could not be opened - return false; - } - - // Add this connection to the readers list - _reader.add_connection(_conn); - return true; -} - -/** - * Sends a conversion workload to the Maya conversion server. - * It will be processed as soon as the server's queue is empty. - * - * Specify the working directory in where the models are located, - * the command line arguments, and the conversion type. - * - * Returns true if the workload has been successfully sent. - */ -bool MayaConversionClient:: -queue(Filename working_directory, int argc, char *argv[], MayaConversionServer::ConversionType conversion_type) { - if (!_conn) { - return false; - } - - std::string s_cwd = (std::string) working_directory.to_os_specific(); - NetDatagram datagram; - - // First part of the datagram is the argc - datagram.add_uint8(argc); - - // Add the rest of the arguments as strings to the datagram - for (int i = 0; i < argc; i++) { - datagram.add_string(argv[i]); - } - - // Add the current working dir as a string to the datagram - datagram.add_string(s_cwd); - - // Lastly, add the conversion type - datagram.add_uint8(conversion_type); - - // Send the conversion request - if (!_writer.send(datagram, _conn) || !_conn->flush()) { - nout << "Failed to send workload to server process.\n"; - return false; - } - - // Wait for a response - while (_conn->get_socket()->Active() && !_reader.data_available()) { - _reader.poll(); - } - - if (!_reader.data_available()) { - // No response has been given by the server. - nout << "No response has been given by the conversion server.\n"; - return false; - } - - NetDatagram response; - - // Let's read the response now! - if (!_reader.get_data(response)) { - nout << "The conversion response could not be read.\n"; - return false; - } - - // Iterate through the response. - DatagramIterator response_data(response); - - // Read the first and only argument. - // Did our conversion request succeed? - bool converted = response_data.get_bool(); - - if (!converted) { - nout << "The server reported that the conversion has failed.\n" - << "Please check the server logs for further information.\n"; - return false; - } - - return true; -} - -/** - * Closes the current connection to the Maya conversion server, - * waiting for all currently queued requests to finish. - * - * Does nothing if the connection has not been made yet. - */ -void MayaConversionClient:: -close() { - if (!_conn) { - return; - } - - while (true) { - _reader.data_available(); - - if (_manager.reset_connection_available()) { - PT(Connection) connection; - - if (_manager.get_reset_connection(connection)) { - _manager.close_connection(_conn); - _conn = nullptr; - return; - } - } - - Thread::sleep(0.1); - } -} - -/** - * The entrypoint to this Maya conversion client. - * - * Connects to the default server at port 4242, queues - * one conversion request and waits for its completion. - */ -int MayaConversionClient:: -main(int argc, char *argv[], MayaConversionServer::ConversionType conversion_type) { - NetAddress server; - - // We assume the server is local and on port 4242 - server.set_host("localhost", 4242); - - if (!connect(server)) { - nout << "Failed to open port to server process.\n" - << "Make sure maya2egg -server or egg2maya -server is running on localhost!\n"; - return 1; - } - - if (!queue(ExecutionEnvironment::get_cwd(), argc, argv, conversion_type)) { - return 1; - } - - nout << "Conversion successful!\n"; - close(); - return 0; -} diff --git a/pandatool/src/mayaprogs/mayaConversionClient.h b/pandatool/src/mayaprogs/mayaConversionClient.h deleted file mode 100644 index 2685c7166d7..00000000000 --- a/pandatool/src/mayaprogs/mayaConversionClient.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaConversionClient.h - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#ifndef MAYACONVERSIONCLIENT_H -#define MAYACONVERSIONCLIENT_H - -#include "queuedConnectionManager.h" -#include "queuedConnectionReader.h" -#include "connectionWriter.h" -#include "netAddress.h" -#include "filename.h" -#include "mayaConversionServer.h" - -/** - * The Maya conversion client sends batch conversion - * requests to the Maya conversion server. - * - * These utilities rely on the Maya conversion server. - * Use egg2maya or maya2egg to boot up the Maya conversion server. - * Use egg2maya_client and maya2egg_client as a replacement for - * - * Very useful in case you need to batch convert models. - * The regular utilities can only convert one model at a time. -*/ -class MayaConversionClient { -public: - MayaConversionClient(); - ~MayaConversionClient(); - - bool connect(NetAddress server); - bool queue(Filename working_directory, int argc, char *argv[], MayaConversionServer::ConversionType conversion_type); - void close(); - - int main(int argc, char *argv[], MayaConversionServer::ConversionType conversion_type); - -private: - QueuedConnectionManager _manager; - QueuedConnectionReader _reader; - ConnectionWriter _writer; - PT(Connection) _conn; -}; - -#endif diff --git a/pandatool/src/mayaprogs/mayaConversionServer.cxx b/pandatool/src/mayaprogs/mayaConversionServer.cxx deleted file mode 100644 index 3557082ace5..00000000000 --- a/pandatool/src/mayaprogs/mayaConversionServer.cxx +++ /dev/null @@ -1,220 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaConversionServer.cxx - * @author cbrunner - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#ifdef _WIN32 -#include // for chdir -#endif - -#include "mayaConversionServer.h" -#include "mayaToEgg.h" -#include "eggToMaya.h" -#include "virtualFileSystem.h" -#include "filename.h" - -/** - * Initializes the Maya conversion server. - */ -MayaConversionServer:: -MayaConversionServer() : _listener(&_manager, 0), _reader(&_manager, 0), - _writer(&_manager, 0) { -} - -/** - * Checks for any network activity and handles it, if appropriate, and then - * returns. This must be called periodically - */ -void MayaConversionServer:: -poll() { - // Listen for new connections - _listener.poll(); - - // If we have a new connection from a client create a new connection pointer - // and add it to the reader list - if (_listener.new_connection_available()) { - PT(Connection) rendezvous; - PT(Connection) connection; - NetAddress address; - - if (_listener.get_new_connection(rendezvous, address, connection)) { - _reader.add_connection(connection); - _clients.insert(connection); - } - } - - // Check for reset clients - if (_manager.reset_connection_available()) { - PT(Connection) connection; - - if (_manager.get_reset_connection(connection)) { - _clients.erase(connection); - _manager.close_connection(connection); - } - } - - // Poll the readers (created above) and if they have data process it - _reader.poll(); - - if (_reader.data_available()) { - // Grab the incoming data and unpack it - NetDatagram datagram; - - if (_reader.get_data(datagram)) { - DatagramIterator data(datagram); - - // First data should be the "argc" (argument count) from the client - int argc = data.get_uint8(); - - // Now we have to get clever because the rest of the data comes as - // strings and parse_command_line() expects arguments of the standard - // argc, argv*[] variety. First, we need a string vector to hold all - // the strings from the datagram. We also need a char * array to keep - // track of all the pointers we're gonna malloc. Needed later for - // cleanup. - vector_string vargv; - std::vector buffers; - - // Get the strings from the datagram and put them into the string vector - for (int i = 0; i < argc; i++) { - vargv.push_back(data.get_string().c_str()); - } - - // Last string is the current directory the client was run from. Not - // part of the argument list, but we still need it - std::string cwd = data.get_string(); - - // We allocate some memory to hold the pointers to the pointers we're - // going to pass in to parse_command_line(). - char **cargv = (char**) malloc(sizeof(char**) * argc); - - // Loop through the string arguments we got from the datagram and - // convert them to const char *'s. parse_command_line() expects char - // *'s, so we have to copy these const versions into fresh char *, since - // there is no casting from const char * to char *. - for (int i = 0; i < argc; i++) { - // string to const char * - const char *cptr = vargv[i].c_str(); - // memory allocated for a new char * of size of the string - char *buffer = (char *) malloc(vargv[i].capacity() + 1); - - // Copy the const char * to the char * - strcpy(buffer, cptr); - // put this into the arry we defined above. This is what will - // eventually be passed to parse_command_line() - cargv[i] = buffer; - // keep track of the pointers to the allocated memory for cleanup - // later - buffers.push_back(buffer); - } - - // Change to the client's current dir -#ifdef _WIN64 - _chdir(cwd.c_str()); -#else - chdir(cwd.c_str()); -#endif - - // Change the VirtualFileSystem's current dir as well - VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); - vfs->chdir(Filename::from_os_specific(cwd)); - - // Next, we'll need to read the conversion type. - // Are we converting from egg to maya or from maya to egg? - int conversion_type = data.get_uint8(); - bool converted = false; - - switch (conversion_type) { - case ConversionType::CT_maya_to_egg: - { - MayaToEgg egg; - - // Pass in the 'new' argc and argv we got from the client - if (egg.parse_command_line(argc, cargv, false) == ProgramBase::ExitCode::EC_not_exited) { - // Actually run the damn thing - converted = egg.run(); - } - - break; - } - case ConversionType::CT_egg_to_maya: - { - EggToMaya maya; - maya.set_exit_on_failure(false); - - // Pass in the 'new' argc and argv we got from the client - if (maya.parse_command_line(argc, cargv, false) == ProgramBase::ExitCode::EC_not_exited) { - // Actually run the damn thing - converted = maya.run(); - } - - break; - } - } - - // Let's send the result back to the client - NetDatagram response; - - // The first and only part of the response is the success value - response.add_bool(converted); - - // Send the response - if (!_writer.send(response, datagram.get_connection())) { - // Looks like we couldn't send the response - nout << "Could not send response to the client.\n"; - } - - std::cout.flush(); - - // Cleanup first, release the string vector - vargv.clear(); - // No, iterate through the char * vector and cleanup the malloc'd - // pointers - std::vector::iterator vi; - for ( vi = buffers.begin() ; vi != buffers.end(); vi++) { - free(*vi); - } - // Clean up the malloc'd pointer pointer - free(cargv); - } // qReader.get_data - - Clients::iterator ci; - for (ci = _clients.begin(); ci != _clients.end(); ++ci) { - _manager.close_connection(*ci); - } - } // qReader.data_available -} // poll - -/** - * Blocks the current thread and listens to conversion requests. - */ -void MayaConversionServer:: -listen() { - // Open a rendezvous port for receiving new connections from the client - PT(Connection) rend = _manager.open_TCP_server_rendezvous(4242, 100); - - if (rend.is_null()) { - nout << "Port opening failed!\n"; - return; - } - - nout << "Server opened on port 4242, waiting for requests...\n"; - - // Add this connection to the listeners list - _listener.add_connection(rend); - - // Main loop. Keep polling for connections, but don't eat up all the CPU. - while (true) { - this->poll(); - Thread::force_yield(); - } -} diff --git a/pandatool/src/mayaprogs/mayaConversionServer.h b/pandatool/src/mayaprogs/mayaConversionServer.h deleted file mode 100644 index c5d89910e0b..00000000000 --- a/pandatool/src/mayaprogs/mayaConversionServer.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaConversionServer.h - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#ifndef MAYACONVERSIONSERVER_H -#define MAYACONVERSIONSERVER_H - -#include "queuedConnectionManager.h" -#include "queuedConnectionListener.h" -#include "queuedConnectionReader.h" -#include "connectionWriter.h" - -/** - * The Maya conversion server listens for incoming requests to - * handle maya-to-egg and egg-to-maya model conversions. - * - * This server listens to port 4242 after being started with - * egg2maya -server or maya2egg -server. - * - * Use egg2maya_client and maya2egg_client as a replacement for - * the egg2maya and maya2egg utilities after starting the server. - * - * Very useful in case you need to batch convert models. - * The regular utilities can only convert one model at a time. -*/ -class MayaConversionServer { -public: - enum ConversionType { - CT_maya_to_egg = 0, - CT_egg_to_maya = 1 - }; - - MayaConversionServer(); - - void listen(); - void poll(); - -protected: - typedef pset< PT(Connection) > Clients; - Clients _clients; - - QueuedConnectionManager _manager; - QueuedConnectionListener _listener; - QueuedConnectionReader _reader; - ConnectionWriter _writer; -}; - -#endif diff --git a/pandatool/src/mayaprogs/mayaEggImport.cxx b/pandatool/src/mayaprogs/mayaEggImport.cxx deleted file mode 100644 index 5e382715172..00000000000 --- a/pandatool/src/mayaprogs/mayaEggImport.cxx +++ /dev/null @@ -1,166 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaEggImport.cxx - * @author jyelon - * @date 2005-07-20 - * - * This is the wrapper code for the maya importer plugin. - * It includes: - * - * - user interface dialogs and popups - * - plugin initialization/registration - * - * It does not include the actual code to traverse the EggData. - */ - -#include -#include - -#include "dtoolbase.h" - -// We must define this to prevent Maya from doubly-declaring its MApiVersion -// string in this file as well as in libmayaegg. -#define _MApiVersion - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -#include "mayaEggLoader.h" -#include "notifyCategoryProxy.h" - - -class MayaEggImporter : public MPxFileTranslator -{ -public: - MayaEggImporter () {}; - virtual ~MayaEggImporter () {}; - static void* creator(); - - MStatus reader ( const MFileObject& file, - const MString& optionsString, - FileAccessMode mode); - - MStatus writer ( const MFileObject& file, - const MString& optionsString, - FileAccessMode mode ); - - bool haveReadMethod () const { return true; } - bool haveWriteMethod () const { return false; } - MString defaultExtension () const { return "egg"; } - MFileKind identifyFile ( const MFileObject& fileName, - const char* buffer, - short size) const; -}; - - -void* MayaEggImporter::creator() -{ - return new MayaEggImporter(); -} - -MStatus MayaEggImporter::reader ( const MFileObject& file, - const MString& options, - FileAccessMode mode) -{ - MString fileName = file.fullName(); - bool model=false; - bool anim=false; - - if (options.length() > 0) { - const MString flagModel("model"); - const MString flagAnim("anim"); - - // Start parsing. - MStringArray optionList; - MStringArray theOption; - options.split(';', optionList); - - unsigned nOptions = optionList.length(); - for (unsigned i = 0; i < nOptions; i++) { - - theOption.clear(); - optionList[i].split('=', theOption); - if (theOption.length() < 1) { - continue; - } - - if (theOption[0] == flagModel && theOption.length() > 1) { - model = atoi(theOption[1].asChar()) ? true:false; - } else if (theOption[0] == flagAnim && theOption.length() > 1) { - anim = atoi(theOption[1].asChar()) ? true:false; - } - } - } - - if ((mode != kImportAccessMode)&&(mode != kOpenAccessMode)) - return MS::kFailure; - - bool merge = (mode == kImportAccessMode); - std::ostringstream log; - Notify::ptr()->set_ostream_ptr(&log, false); - bool ok = MayaLoadEggFile(fileName.asChar(), merge, model, anim, false); - std::string txt = log.str(); - if (txt != "") { - MGlobal::displayError(txt.c_str()); - } else { - if (!ok) MGlobal::displayError("Cannot import Egg file, unknown reason"); - } - return ok ? MS::kSuccess : MS::kFailure; -} - -MStatus MayaEggImporter::writer ( const MFileObject& file, - const MString& options, - FileAccessMode mode ) - -{ - fprintf(stderr, "MayaEggImporter::writer called in error\n"); - return MS::kFailure; -} - -MPxFileTranslator::MFileKind MayaEggImporter::identifyFile ( - const MFileObject& fileName, - const char* buffer, - short size) const -{ - const char * name = fileName.name().asChar(); - int nameLength = strlen(name); - - if ((nameLength > 4) && !strcmp(name+nameLength-4, ".egg")) - return kCouldBeMyFileType; - else - return kNotMyFileType; -} - -EXPCL_MISC MStatus initializePlugin( MObject obj ) -{ - MFnPlugin plugin( obj, "Alias", "3.0", "Any"); - - // Register the translator with the system - return plugin.registerFileTranslator( "Panda3D Egg Import", "none", - MayaEggImporter::creator, - - "eggImportOptions", - "merge=1;model=1;anim=0;"); -} - -EXPCL_MISC MStatus uninitializePlugin( MObject obj ) -{ - MFnPlugin plugin( obj ); - return plugin.deregisterFileTranslator( "Panda3D Egg Import" ); -} diff --git a/pandatool/src/mayaprogs/mayaPview.cxx b/pandatool/src/mayaprogs/mayaPview.cxx deleted file mode 100644 index 1c956672b3c..00000000000 --- a/pandatool/src/mayaprogs/mayaPview.cxx +++ /dev/null @@ -1,335 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaPview.cxx - * @author drose - * @date 2003-03-10 - */ - -#ifdef __MACH__ -#define __OPENTRANSPORTPROVIDERS__ -#endif - -#include "mayaPview.h" -#include "mayaToEggConverter.h" -#include "eggData.h" -#include "load_egg_file.h" -#include "config_putil.h" -#include "config_chan.h" -#include "config_gobj.h" -#include "textNode.h" -#include "multiplexStream.h" -#include "distanceUnit.h" -#include "configVariableEnum.h" - -// We must define this to prevent Maya from doubly-declaring its MApiVersion -// string in this file as well as in libmayaegg. -#define _MApiVersion - -#include "pre_maya_include.h" -#include -#include -#include -#include -#include -#include -#include -#include "post_maya_include.h" - -// On Windows, we have code to fork pview as a separate process, which seems -// to be better for Maya. -#ifdef _WIN32 -#include -#include -#define SEPARATE_PVIEW 1 -#endif // _WIN32 - -/** - * - */ -MayaPview:: -MayaPview() { -} - -/** - * Called when the plugin command is invoked. - */ -MStatus MayaPview:: -doIt(const MArgList &args) { - MStatus result; - - // First, parse the plugin arguments. - MSyntax syntax; - syntax.addFlag("a", "animate"); - - MArgParser parser(syntax, args, &result); - if (!result) { - result.perror("arguments"); - return result; - } - - bool animate = parser.isFlagSet("a", &result); - if (!result) { - result.perror("isFlagSet"); - return result; - } - - if (!MProgressWindow::reserve()) { - nout << "Couldn't reserve progress window.\n"; - return MS::kFailure; - } - MProgressWindow::setTitle("Sending to pview"); - MProgressWindow::setInterruptable(false); - MProgressWindow::setProgressRange(0, 3); - MProgressWindow::setProgressStatus("Converting scene"); - MProgressWindow::startProgress(); - -#ifdef SEPARATE_PVIEW - // We'll write the bam file to a temporary file first. - Filename bam_filename = Filename::temporary("", "pview"); - bam_filename.set_extension("bam"); - - // Since we're just writing to a bam file in this process, and running pview - // in a separate process, we don't actually need to load textures at this - // point. Disable the loading of textures. - textures_header_only = true; - - NodePath root("root"); - if (!convert(root, animate)) { - nout << "failure in conversion.\n"; - MProgressWindow::endProgress(); - return MS::kFailure; - } - - MProgressWindow::setProgressStatus("Writing bam file"); - MProgressWindow::advanceProgress(1); - - if (!root.write_bam_file(bam_filename)) { - nout << "Couldn't write to " << bam_filename << ".\n"; - MProgressWindow::endProgress(); - return MS::kFailure; - } - - MProgressWindow::setProgressStatus("Spawning pview"); - MProgressWindow::advanceProgress(1); - - // Now spawn a pview instance to view this temporary file. - std::string pview_args = "-clD"; - if (animate) { - pview_args = "-clDa"; - } - - // On Windows, we use the spawn function to run pview asynchronously. - std::string quoted = std::string("\"") + bam_filename.get_fullpath() + std::string("\""); - nout << "pview " << pview_args << " " << quoted << "\n"; - int retval = _spawnlp(_P_DETACH, "pview", - "pview", pview_args.c_str(), quoted.c_str(), nullptr); - if (retval == -1) { - bam_filename.unlink(); - MProgressWindow::endProgress(); - return MS::kFailure; - } - - nout << "pview running.\n"; - MProgressWindow::endProgress(); - -#else // SEPARATE_PVIEW - // We'll run PandaFramework directly within this process. - - // Maya seems to run each invocation of the plugin in a separate thread. To - // minimize conflict in our not-yet-completely-thread-safe Panda, we'll - // create a separate PandaFramework for each invocation, even though in - // principle we could be sharing one framework for all of them. - int argc = 0; - char **argv = nullptr; - PandaFramework framework; - framework.open_framework(argc, argv); - framework.set_window_title("Panda Viewer"); - framework.enable_default_keys(); - - PT(WindowFramework) window; - window = framework.open_window(); - if (window == nullptr) { - // Couldn't open a window. - nout << "Couldn't open a window!\n"; - MProgressWindow::endProgress(); - return MS::kFailure; - } - - // We've successfully opened a window. - - // Put up a "loading" message for the user's benefit. - NodePath aspect_2d = window->get_aspect_2d(); - PT(TextNode) loading = new TextNode("loading"); - NodePath loading_np = aspect_2d.attach_new_node(loading); - loading_np.set_scale(0.125f); - loading->set_text_color(1.0f, 1.0f, 1.0f, 1.0f); - loading->set_shadow_color(0.0f, 0.0f, 0.0f, 1.0f); - loading->set_shadow(0.04, 0.04); - loading->set_align(TextNode::A_center); - loading->set_text("Loading..."); - - // Allow a couple of frames to go by so the window will be fully created and - // the text will be visible. - framework.do_frame(Thread::get_current_thread()); - framework.do_frame(Thread::get_current_thread()); - - window->enable_keyboard(); - window->setup_trackball(); - framework.get_models().instance_to(window->get_render()); - - if (!convert(framework.get_models(), animate)) { - nout << "failure in conversion.\n"; - MProgressWindow::endProgress(); - return MS::kFailure; - } - - nout << "successfully converted.\n"; - - loading_np.remove_node(); - window->center_trackball(framework.get_models()); - window->loop_animations(); - - if (animate) { - window->set_anim_controls(true); - } - - MProgressWindow::endProgress(); - framework.main_loop(); -#endif // SEPARATE_PVIEW - - return MS::kSuccess; -} - -/** - * This is used to create a new instance of the plugin. - */ -void *MayaPview:: -creator() { - return new MayaPview; -} - -/** - * Actually converts the Maya selection to Panda geometry, and parents it to - * the indicated NodePath. - */ -bool MayaPview:: -convert(const NodePath &parent, bool animate) { - // Now make a converter to get all the Maya structures. - MayaToEggConverter converter("plug-in"); - - // We always want polygon output since we want to be able to see the - // results. - converter._polygon_output = true; - converter._polygon_tolerance = 0.01; - - if (animate) { - // We also want to get the animation if there is any. - converter.set_animation_convert(AC_both); - - // Don't compress animation channels; that can introduce confusing - // artifacts. - compress_channels = false; - } - - PathReplace *path_replace = converter.get_path_replace(); - - // Accept relative pathnames in the Maya file. - Filename source_file = - Filename::from_os_specific(MFileIO::currentFile().asChar()); - std::string source_dir = source_file.get_dirname(); - if (!source_dir.empty()) { - path_replace->_path.append_directory(source_dir); - } - - // Also search along the model path. - path_replace->_path.append_path(get_model_path()); - - PT(EggData) egg_data = new EggData; - converter.set_egg_data(egg_data); - converter.set_from_selection(true); - converter.set_neutral_frame(-1); - - if (!converter.convert_maya()) { - nout << "Errors in conversion.\n"; - return false; - } - - MProgressWindow::setProgressStatus("Converting to bam"); - MProgressWindow::advanceProgress(1); - - // Now the converter has filled up our egg structure with data, so convert - // this egg data to Panda data for immediate viewing. - DistanceUnit input_units = converter.get_input_units(); - ConfigVariableEnum ptloader_units("ptloader-units", DU_invalid); - if (input_units != DU_invalid && ptloader_units != DU_invalid && - input_units != ptloader_units) { - // Convert the file to the units specified by the ptloader-units Configrc - // variable. - nout - << "Converting from " << format_long_unit(input_units) - << " to " << format_long_unit(ptloader_units) << "\n"; - double scale = convert_units(input_units, ptloader_units); - egg_data->transform(LMatrix4d::scale_mat(scale)); - } - - egg_data->set_coordinate_system(CS_default); - PT(PandaNode) result = load_egg_data(egg_data); - - if (result == nullptr) { - nout << "Unable to load converted egg data.\n"; - return false; - } - - parent.attach_new_node(result); - return true; -} - - - - -/** - * Called by Maya when the plugin is loaded. - */ -EXPCL_MISC MStatus -initializePlugin(MObject obj) { - // This code is just for debugging, to cause Notify to write its output to a - // log file we can inspect, so we can see the error messages output by DX7 - // or DX8 just before it does a panic exit (and thereby shuts down Maya and - // its output window). - /* - MultiplexStream *local_nout = new MultiplexStream(); - Notify::ptr()->set_ostream_ptr(local_nout, 0); - local_nout->add_file(Filename::expand_from("$TEMP/libmayapview.log")); - local_nout->add_standard_output(); - */ - - MFnPlugin plugin(obj, "VR Studio", "1.0"); - MStatus status; - status = plugin.registerCommand("pview", MayaPview::creator); - if (!status) { - status.perror("registerCommand"); - } - - return status; -} - -/** - * Called by Maya when the plugin is unloaded. - */ -EXPCL_MISC MStatus -uninitializePlugin(MObject obj) { - MFnPlugin plugin(obj); - MStatus status; - status = plugin.deregisterCommand("pview"); - - if (!status) { - status.perror("deregisterCommand"); - } - return status; -} diff --git a/pandatool/src/mayaprogs/mayaPview.h b/pandatool/src/mayaprogs/mayaPview.h deleted file mode 100644 index 79cff017f21..00000000000 --- a/pandatool/src/mayaprogs/mayaPview.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaPview.h - * @author drose - * @date 2003-03-11 - */ - -#ifndef MAYAPVIEW_H -#define MAYAPVIEW_H - -#include "pandatoolbase.h" -#include "pandaFramework.h" - -#include "pre_maya_include.h" -#include -#include -#include -#include "post_maya_include.h" - -/** - * This class serves as a plug-in to Maya to allow viewing the current Maya - * selection as it will be converted to Panda. - */ -class MayaPview : public MPxCommand { -public: - MayaPview(); - virtual MStatus doIt(const MArgList &args); - - static void *creator(); - -private: - bool convert(const NodePath &parent, bool animate); -}; - -EXPCL_MISC MStatus initializePlugin(MObject obj); -EXPCL_MISC MStatus uninitializePlugin(MObject obj); - - -#endif diff --git a/pandatool/src/mayaprogs/mayaSavePview.cxx b/pandatool/src/mayaprogs/mayaSavePview.cxx deleted file mode 100644 index 65a29236f3c..00000000000 --- a/pandatool/src/mayaprogs/mayaSavePview.cxx +++ /dev/null @@ -1,133 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaSavePview.cxx - * @author drose - * @date 2003-10-27 - */ - -#include "mayaSavePview.h" - -#include -#include -#include -#include -#include -#include - -#include - -#ifdef _WIN32 -#include -#endif - -/** - * - */ -MayaSavePview:: -MayaSavePview() { -} - -/** - * Called when the plugin command is invoked. - */ -MStatus MayaSavePview:: -doIt(const MArgList &args) { - MStatus result; - - // First, parse the plugin arguments. - MSyntax syntax; - syntax.addFlag("a", "animate"); - - MArgParser parser(syntax, args, &result); - if (!result) { - result.perror("arguments"); - return result; - } - - bool animate = parser.isFlagSet("a", &result); - if (!result) { - result.perror("isFlagSet"); - return result; - } - - // Now make sure the current buffer is saved. - result = MFileIO::save(false); - if (result != MS::kSuccess) { - return result; - } - - MString filename = MFileIO::currentFile(); - - MString pview_args = "-cl"; - if (animate) { - pview_args = "-cla"; - } - -#ifdef _WIN32 - // On Windows, we use the spawn function to run pview asynchronously. - MString quoted = MString("\"") + filename + MString("\""); - intptr_t retval = _spawnlp(_P_DETACH, "pview", - "pview", pview_args.asChar(), quoted.asChar(), nullptr); - if (retval == -1) { - return MS::kFailure; - } - -#else // _WIN32 - // On non-Windows (e.g. Unix), we just use the system function, which runs - // synchronously. We could fork a process, but no one's asked for this yet. - MString command = MString("pview " + pview_args + MString(" \"") + filename + MString("\"")); - - int command_result = system(command.asChar()); - if (command_result != 0) { - return MS::kFailure; - } -#endif // _WIN32 - - return MS::kSuccess; -} - -/** - * This is used to create a new instance of the plugin. - */ -void *MayaSavePview:: -creator() { - return new MayaSavePview; -} - - - -/** - * Called by Maya when the plugin is loaded. - */ -EXPCL_MISC MStatus -initializePlugin(MObject obj) { - MFnPlugin plugin(obj, "VR Studio", "1.0"); - MStatus status; - status = plugin.registerCommand("pview", MayaSavePview::creator); - if (!status) { - status.perror("registerCommand"); - } - - return status; -} - -/** - * Called by Maya when the plugin is unloaded. - */ -EXPCL_MISC MStatus -uninitializePlugin(MObject obj) { - MFnPlugin plugin(obj); - MStatus status; - status = plugin.deregisterCommand("pview"); - - if (!status) { - status.perror("deregisterCommand"); - } - return status; -} diff --git a/pandatool/src/mayaprogs/mayaSavePview.h b/pandatool/src/mayaprogs/mayaSavePview.h deleted file mode 100644 index 56a84bf14cb..00000000000 --- a/pandatool/src/mayaprogs/mayaSavePview.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaSavePview.h - * @author drose - * @date 2003-10-27 - */ - -#ifndef MAYASAVEPVIEW_H -#define MAYASAVEPVIEW_H - -// We don't want to include pre_maya_include.h here, since that would -// necessitate linking with Pandatool's libmaya.dll, which would in turn bring -// in a lot of stuff from panda that we don't really need. Instead, we'll -// just define the Maya symbols we require here. - -// Maya will try to typedef bool unless this symbol is defined. -#ifndef _BOOL -#define _BOOL 1 -#endif - -#ifdef __MACH__ -#define OSMac_ 1 -// This defines MAYA_API_VERSION -#include -#if MAYA_API_VERSION < 201600 -#include -#endif -#endif - -// Even though we don't include any Panda headers, it's safe to include this -// one, since it only defines some macros that we need to make this program -// platform-independent. -#include "dtool_config.h" - -#ifdef PHAVE_IOSTREAM -// This will ask Maya 5.0 or better to use the new library instead -// of the old library. -#define REQUIRE_IOSTREAM -#endif // PHAVE_IOSTREAM - -#include -#include -#include - -/** - * This class serves as a plug-in to Maya to save the scene and view it using - * the external pview program, rather than linking in any part of Panda to a - * Maya plugin. - * - * Since it does not link with any Panda code, and hence is a very lean - * plugin, it is less likely than MayaPview to cause interoperability problems - * within Maya. However, it does force a save-to-disk and a spawning of a - * separate executable, including a complete reloading of all of the Maya - * libraries, so it is quite a bit slower to execute. And the potential for - * interactive control is substantially reduced. - */ -class MayaSavePview : public MPxCommand { -public: - MayaSavePview(); - virtual MStatus doIt(const MArgList &args); - - static void *creator(); -}; - -// Since we don't include any of the Panda headers (other than -// dtool_config.h), we have to define this macro ourselves, to tell Windows to -// export the following functions from the DLL. -#ifdef _WIN32 - #define EXPCL_MISC __declspec(dllexport) -#else - #define EXPCL_MISC -#endif - -EXPCL_MISC MStatus initializePlugin(MObject obj); -EXPCL_MISC MStatus uninitializePlugin(MObject obj); - - -#endif diff --git a/pandatool/src/mayaprogs/mayaToEgg.cxx b/pandatool/src/mayaprogs/mayaToEgg.cxx deleted file mode 100644 index 10a09d17981..00000000000 --- a/pandatool/src/mayaprogs/mayaToEgg.cxx +++ /dev/null @@ -1,383 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaToEgg.cxx - * @author drose - * @date 2000-02-15 - * - * Additional Maintenance by the PandaSE team - * Carnegie Mellon Entertainment Technology Center - * Spring '10 - * Team Members: - * Deepak Chandraskeran - producer / programmer - * Andrew Gartner - programmer/technical artist - * Federico Perazzi - programmer - * Shuying Feng - programmer - * Wei-Feng Huang - programmer - * (Egger additions by Andrew Gartner and Wei-Feng Huang) - * The egger can now support vertex color in a variety - * of combinations with flat color and file color textures - * (see set_vertex_color). Also, there are two new - * command line options "legacy-shaders" and "texture-copy". - * The first treats any Maya material/shader as if it were - * a legacy shader. Passing it through the legacy codepath. - * This feature was originally intended to fix a bug where - * flat-color was being ignored in the modern (Phong) codepath - * However, with the new vertex and flat color functions it - * may not be necessary. Still, until the newer color functions - * have been tried and tested more, the feature has been left in - * to anticipate any problems that may arise. The texture copy - * feature was added to provide a way to resolve build path issues - * and can support both relative and absolute paths. The feature - * will copy any file maps/textures to the specified directory - * and update the egg file accordingly. - */ - -#include "mayaToEgg.h" -#include "mayaToEggConverter.h" -#include "config_mayaegg.h" -#include "config_maya.h" // for maya_cat -#include "globPattern.h" -#include "mayaConversionServer.h" - -/** - * - */ -MayaToEgg:: -MayaToEgg() : - SomethingToEgg("Maya", ".mb") -{ - add_path_replace_options(); - add_path_store_options(); - add_animation_options(); - add_units_options(); - add_normals_options(); - add_transform_options(); - - set_program_brief("convert Maya model files to .egg"); - set_program_description - ("This program converts Maya model files to egg. Static and animatable " - "models can be converted, with polygon or NURBS output. Animation tables " - "can also be generated to apply to an animatable model."); - - add_option - ("p", "", 0, - "Generate polygon output only. Tesselate all NURBS surfaces to " - "polygons via the built-in Maya tesselator. The tesselation will " - "be based on the tolerance factor given by -ptol.", - &MayaToEgg::dispatch_none, &_polygon_output); - - add_option - ("ptol", "tolerance", 0, - "Specify the fit tolerance for Maya polygon tesselation. The smaller " - "the number, the more polygons will be generated. The default is " - "0.01.", - &MayaToEgg::dispatch_double, nullptr, &_polygon_tolerance); - - add_option - ("bface", "", 0, - "Respect the Maya \"double sided\" rendering flag to indicate whether " - "polygons should be double-sided or single-sided. Since this flag " - "is set to double-sided by default in Maya, it is often better to " - "ignore this flag (unless your modelers are diligent in turning it " - "off where it is not desired). If this flag is not specified, the " - "default is to treat all polygons as single-sided, unless an " - "egg object type of \"double-sided\" is set.", - &MayaToEgg::dispatch_none, &_respect_maya_double_sided); - - add_option - ("suppress-vcolor", "", 0, - "Ignore vertex color for geometry that has a texture applied. " - "(This is the way Maya normally renders internally.) The egg flag " - "'vertex-color' may be applied to a particular model to override " - "this setting locally.", - &MayaToEgg::dispatch_none, &_suppress_vertex_color); - - add_option - ("convert-cameras", "", 0, - "Convert all camera nodes to locators. Will preserve position and rotation.", - &MayaToEgg::dispatch_none, &_convert_cameras); - - add_option - ("convert-lights", "", 0, - "Convert all light nodes to locators. Will preserve position and rotation only.", - &MayaToEgg::dispatch_none, &_convert_lights); - - add_option - ("keep-uvs", "", 0, - "Convert all UV sets on all vertices, even those that do not appear " - "to be referenced by any textures.", - &MayaToEgg::dispatch_none, &_keep_all_uvsets); - - add_option - ("round-uvs", "", 0, - "round up uv coordinates to the nearest 1/100th. i.e. -0.001 becomes" - "0.0; 0.444 becomes 0.44; 0.778 becomes 0.78.", - &MayaToEgg::dispatch_none, &_round_uvs); - - add_option - ("copytex", "dir", 41, - "Legacy option. Same as -pc.", - &MayaToEgg::dispatch_filename, &_legacy_copytex, &_legacy_copytex_dir); - - add_option("server", "", 0, - "Runs the Maya model conversion server. This server can be used in tandem " - "with the egg2maya_client and maya2egg_client utilities to batch convert " - "both Maya and Panda3D model files.", - &MayaToEgg::dispatch_none, &_run_server); - - add_option - ("trans", "type", 0, - "Specifies which transforms in the Maya file should be converted to " - "transforms in the egg file. The option may be one of all, model, " - "dcs, or none. The default is model, which means only transforms on " - "nodes that have the model flag or the dcs flag are preserved.", - &MayaToEgg::dispatch_transform_type, nullptr, &_transform_type); - - add_option - ("subroot", "name", 0, - "Specifies that only a subroot of the geometry in the Maya file should " - "be converted; specifically, the geometry under the node or nodes whose " - "name matches the parameter (which may include globbing characters " - "like * or ?). This parameter may be repeated multiple times to name " - "multiple roots. If it is omitted altogether, the entire file is " - "converted.", - &MayaToEgg::dispatch_vector_string, nullptr, &_subroots); - - add_option - ("subset", "name", 0, - "Specifies that only a subset of the geometry in the Maya file should " - "be converted; specifically, the geometry under the node or nodes whose " - "name matches the parameter (which may include globbing characters " - "like * or ?). This parameter may be repeated multiple times to name " - "multiple roots. If it is omitted altogether, the entire file is " - "converted.", - &MayaToEgg::dispatch_vector_string, nullptr, &_subsets); - - add_option - ("exclude", "name", 0, - "Specifies that a subset of the geometry in the Maya file should " - "not be converted; specifically, the geometry under the node or nodes whose " - "name matches the parameter (which may include globbing characters " - "like * or ?). This parameter may be repeated multiple times to name " - "multiple roots.", - &MayaToEgg::dispatch_vector_string, nullptr, &_excludes); - - add_option - ("ignore-slider", "name", 0, - "Specifies the name of a slider (blend shape deformer) that maya2egg " - "should not process. The slider will not be touched during conversion " - "and it will not become a part of the animation. This " - "parameter may including globbing characters, and it may be repeated " - "as needed.", - &MayaToEgg::dispatch_vector_string, nullptr, &_ignore_sliders); - - add_option - ("force-joint", "name", 0, - "Specifies the name of a DAG node that maya2egg " - "should treat as a joint, even if it does not appear to be a Maya joint " - "and does not appear to be animated.", - &MayaToEgg::dispatch_vector_string, nullptr, &_force_joints); - - add_option - ("v", "", 0, - "Increase verbosity. More v's means more verbose.", - &MayaToEgg::dispatch_count, nullptr, &_verbose); - - add_option - ("legacy-shaders", "", 0, - "Use this flag to turn off modern (Phong) shader generation" - "and treat all shaders as if they were Lamberts (legacy).", - &MayaToEgg::dispatch_none, &_legacy_shader); - - // Unfortunately, the Maya API doesn't allow us to differentiate between - // relative and absolute pathnames--everything comes out as an absolute - // pathname, even if it is stored in the Maya file as a relative path. So - // we can't support -noabs. - remove_option("noabs"); - - _verbose = 0; - _polygon_tolerance = 0.01; - _transform_type = MayaToEggConverter::TT_model; - _got_tbnauto = true; -} - -/** - * - */ -MayaToEgg:: -~MayaToEgg() { -} - -/** - * Attempts to create the global Maya API. - * Exits the program if unsuccessful. - */ -PT(MayaApi) MayaToEgg:: -open_api() { - if (!MayaApi::is_api_valid()) { - nout << "Initializing Maya...\n"; - } - - PT(MayaApi) api = MayaApi::open_api(_program_name, true, true); - - if (!api || !api->is_valid()) { - nout << "Unable to initialize Maya.\n"; - exit(1); - } - - return api; -} - -/** - * Returns true if the model has been successfully converted. - */ -bool MayaToEgg:: -run() { - // Set the verbose level by using Notify. - if (_verbose >= 3) { - maya_cat->set_severity(NS_spam); - mayaegg_cat->set_severity(NS_spam); - } else if (_verbose >= 2) { - maya_cat->set_severity(NS_debug); - mayaegg_cat->set_severity(NS_debug); - } else if (_verbose >= 1) { - maya_cat->set_severity(NS_info); - mayaegg_cat->set_severity(NS_info); - } - - if (_legacy_copytex && !_path_replace->_copy_files) { - _path_replace->_copy_files = true; - _path_replace->_copy_into_directory = _legacy_copytex_dir; - } - - // Let's convert the output file to a full path before we initialize Maya, - // since Maya now has a nasty habit of changing the current directory. - if (_got_output_filename) { - _output_filename.make_absolute(); - _path_replace->_path_directory.make_absolute(); - } - - open_api(); - MayaToEggConverter converter(_program_name); - - // Copy in the command-line parameters. - converter._polygon_output = _polygon_output; - converter._polygon_tolerance = _polygon_tolerance; - converter._respect_maya_double_sided = _respect_maya_double_sided; - converter._always_show_vertex_color = !_suppress_vertex_color; - converter._keep_all_uvsets = _keep_all_uvsets; - converter._convert_cameras = _convert_cameras; - converter._convert_lights = _convert_lights; - converter._round_uvs = _round_uvs; - converter._transform_type = _transform_type; - converter._legacy_shader = _legacy_shader; - - vector_string::const_iterator si; - if (!_subroots.empty()) { - converter.clear_subroots(); - for (si = _subroots.begin(); si != _subroots.end(); ++si) { - converter.add_subroot(GlobPattern(*si)); - } - } - - if (!_subsets.empty()) { - converter.clear_subsets(); - for (si = _subsets.begin(); si != _subsets.end(); ++si) { - converter.add_subset(GlobPattern(*si)); - } - } - - if (!_excludes.empty()) { - converter.clear_excludes(); - for (si = _excludes.begin(); si != _excludes.end(); ++si) { - converter.add_exclude(GlobPattern(*si)); - } - } - - if (!_ignore_sliders.empty()) { - converter.clear_ignore_sliders(); - for (si = _ignore_sliders.begin(); si != _ignore_sliders.end(); ++si) { - converter.add_ignore_slider(GlobPattern(*si)); - } - } - - if (!_force_joints.empty()) { - converter.clear_force_joints(); - for (si = _force_joints.begin(); si != _force_joints.end(); ++si) { - converter.add_force_joint(GlobPattern(*si)); - } - } - - // Copy in the path and animation parameters. - apply_parameters(converter); - - // Set the coordinate system to match Maya's. - if (!_got_coordinate_system) { - _coordinate_system = converter._maya->get_coordinate_system(); - } - _data->set_coordinate_system(_coordinate_system); - - converter.set_egg_data(_data); - - if (!converter.convert_file(_input_filename)) { - nout << "Errors in conversion.\n"; - return false; - } - - // Use the standard Maya units, if the user didn't specify otherwise. This - // always returns centimeters, which is the way all Maya files are stored - // internally (and is the units returned by all of the API functions called - // here). - if (_input_units == DU_invalid) { - _input_units = converter.get_input_units(); - } - - // Write output file - write_egg_file(); - close_output(); - return true; -} - -/** - * Dispatches a parameter that expects a MayaToEggConverter::TransformType - * option. - */ -bool MayaToEgg:: -dispatch_transform_type(const std::string &opt, const std::string &arg, void *var) { - MayaToEggConverter::TransformType *ip = (MayaToEggConverter::TransformType *)var; - (*ip) = MayaToEggConverter::string_transform_type(arg); - - if ((*ip) == MayaToEggConverter::TT_invalid) { - nout << "Invalid type for -" << opt << ": " << arg << "\n" - << "Valid types are all, model, dcs, and none.\n"; - return false; - } - - return true; -} - -/** - * Processes the arguments parsed by the program. - * - * If the server flag is specified, the Maya conversion server is started - * up rather than the usual conversion utility functionality. - */ -bool MayaToEgg:: -handle_args(ProgramBase::Args &args) { - if (_run_server) { - open_api(); - - MayaConversionServer server; - server.listen(); - exit(0); - return true; - } - - return SomethingToEgg::handle_args(args); -} diff --git a/pandatool/src/mayaprogs/mayaToEgg.h b/pandatool/src/mayaprogs/mayaToEgg.h deleted file mode 100644 index 237266f04ec..00000000000 --- a/pandatool/src/mayaprogs/mayaToEgg.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaToEgg.h - * @author drose - * @date 2000-02-15 - */ - -#ifndef MAYATOEGG_H -#define MAYATOEGG_H - -#include "pandatoolbase.h" -#include "somethingToEgg.h" -#include "mayaToEggConverter.h" -#include "mayaApi.h" - -#include "programBase.h" - -/** - * - */ -class MayaToEgg : public SomethingToEgg { -public: - MayaToEgg(); - ~MayaToEgg(); - - bool run(); - -protected: - static bool dispatch_transform_type(const std::string &opt, const std::string &arg, void *var); - virtual bool handle_args(ProgramBase::Args &args); - - PT(MayaApi) open_api(); - - int _verbose; - bool _polygon_output; - double _polygon_tolerance; - bool _respect_maya_double_sided; - bool _suppress_vertex_color; - bool _keep_all_uvsets; - bool _convert_cameras; - bool _convert_lights; - bool _round_uvs; - bool _legacy_shader; - bool _legacy_copytex; - Filename _legacy_copytex_dir; - - MayaToEggConverter::TransformType _transform_type; - vector_string _subroots; - vector_string _subsets; - vector_string _excludes; - vector_string _ignore_sliders; - vector_string _force_joints; - -public: - bool _run_server; -}; - -#endif diff --git a/pandatool/src/mayaprogs/mayaToEggBin.cxx b/pandatool/src/mayaprogs/mayaToEggBin.cxx deleted file mode 100644 index d65bdcae249..00000000000 --- a/pandatool/src/mayaprogs/mayaToEggBin.cxx +++ /dev/null @@ -1,28 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaToEggBin.cxx - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#include "mayaToEgg.h" - -/** - * Entrypoint for maya2egg. - */ -int main(int argc, char *argv[]) { - MayaToEgg prog; - prog.parse_command_line(argc, argv); - - if (!prog.run()) { - return 1; - } - - return 0; -} diff --git a/pandatool/src/mayaprogs/mayaToEggClient.cxx b/pandatool/src/mayaprogs/mayaToEggClient.cxx deleted file mode 100644 index 066b41ae317..00000000000 --- a/pandatool/src/mayaprogs/mayaToEggClient.cxx +++ /dev/null @@ -1,22 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayaToEggClient.cxx - * @author Derzsi Dániel - * @date 2020-10-01 - */ - -#include "mayaConversionClient.h" - -/** - * Entrypoint for maya2egg_client. - */ -int main(int argc, char *argv[]) { - MayaConversionClient client; - return client.main(argc, argv, MayaConversionServer::ConversionType::CT_maya_to_egg); -} diff --git a/pandatool/src/mayaprogs/mayapath.cxx b/pandatool/src/mayaprogs/mayapath.cxx deleted file mode 100644 index 4cbf19324fa..00000000000 --- a/pandatool/src/mayaprogs/mayapath.cxx +++ /dev/null @@ -1,474 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file mayapath.cxx - * @author drose - * @date 2008-04-07 - */ - -// This program works as a stub to launch maya2egg, egg2maya, and similar -// programs that invoke OpenMaya and require certain environment variables to -// be set first. - -// It used to duplicate code in mayaWrapper.cxx, but now the functionality for -// these two separate programs are unified here. - -// If MAYAVERSION is defined at the time this is compiled, then that -// particular version of Maya is insisted upon, and the desired Maya location -// is found in the Registry; otherwise, we require that $MAYA_LOCATION be set -// at runtime and points to the desired Maya installation. - -/* - * If MAYAVERSION is defined and $MAYA_LOCATION is also set, then we check - * that definition of $MAYA_LOCATION is reasonable, which we define as - * pointing to the same version of OpenMaya.dll. If so, then we use the - * runtime $MAYA_LOCATION, allowing the user to (slightly) override the - * runtime Maya directory. If $MAYA_LOCATION is set but points to a different - * version of OpenMaya.dll, we ignore it altogether and replace it with our - * registry data, which allows the user to have MAYA_LOCATION pointing to a - * different version of Maya without interfering with this program. - */ - -#include "dtoolbase.h" -#include "filename.h" -#include "globPattern.h" -#include "dSearchPath.h" -#include "executionEnvironment.h" -#include "hashVal.h" -#include - -#if defined(_WIN32) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#else -#include -#endif - -using std::cerr; -using std::endl; -using std::string; - -#define QUOTESTR(x) #x -#define TOSTRING(x) QUOTESTR(x) - -// Searches for python26.zip or whatever version it is. -static Filename -find_pyzip(const Filename &maya_location) { - // This is where python26.zip appears on Windows. Should it be in other - // locations on other platforms? - Filename dirname(maya_location, "bin"); - - vector_string results; - GlobPattern glob("python*.zip"); - if (glob.match_files(results, dirname) != 0) { - return Filename(dirname, results[0]); - } - - return Filename(); -} - -struct MayaVerInfo { - const char *ver, *key; -}; - -struct MayaVerInfo maya_versions[] = { - { "MAYA6", "6.0" }, - { "MAYA65", "6.5" }, - { "MAYA7", "7.0" }, - { "MAYA8", "8.0" }, - { "MAYA85", "8.5" }, - { "MAYA2008", "2008"}, - { "MAYA2009", "2009"}, - { "MAYA2010", "2010"}, - { "MAYA2011", "2011"}, - { "MAYA2012", "2012"}, - { "MAYA2013", "2013"}, - { "MAYA20135", "2013.5"}, - { "MAYA2014", "2014"}, - { "MAYA2015", "2015"}, - { "MAYA2016", "2016"}, - { "MAYA20165", "2016.5"}, - { "MAYA2017", "2017"}, - { "MAYA2018", "2018"}, - { "MAYA2019", "2019"}, - { "MAYA2020", "2020"}, - { "MAYA2022", "2022"}, - { 0, 0 }, -}; - -static const char * -get_version_number(const char *ver) { - for (int i = 0; maya_versions[i].ver != 0; ++i) { - if (strcmp(maya_versions[i].ver, ver) == 0) { - return maya_versions[i].key; - } - } - return 0; -} - -static Filename -get_openmaya_filename(const Filename &maya_location) { -#ifdef _WIN32 - // Note: Filename::dso_filename changes .so to .dll automatically. - // Maya 2022 has two versions of OpenMaya.dll, one for Python 3 and - // one for Python 2, in bin3 and bin2 folders. - Filename bin3 = Filename(maya_location, "bin3"); - Filename bin3_openmaya = Filename::dso_filename(maya_location / "bin3/OpenMaya.so"); - if (bin3_openmaya.is_regular_file()) { - return bin3_openmaya; - } - return Filename::dso_filename(maya_location / "bin/OpenMaya.so"); -#elif defined(IS_OSX) - return Filename::dso_filename(maya_location / "MacOS/libOpenMaya.dylib"); -#else - return Filename::dso_filename(maya_location / "lib/libOpenMaya.so"); -#endif // _WIN32 -} - -#if defined(_WIN32) -static void -get_maya_location(const char *ver, string &loc) { - char fullkey[1024]; - const char *developer; - LONG res; - - for (int dev=0; dev<3; dev++) { - switch (dev) { - case 0: developer="Alias|Wavefront"; break; - case 1: developer="Alias"; break; - case 2: developer="Autodesk"; break; - } - sprintf(fullkey, "SOFTWARE\\%s\\Maya\\%s\\Setup\\InstallPath", developer, ver); - for (int hive=0; hive<2; hive++) { - HKEY hkey; - res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | (hive ? 256:0), &hkey); - if (res == ERROR_SUCCESS) { - DWORD dtype; - DWORD size = 4096; - char result[4096 + 1]; - res = RegQueryValueEx(hkey, "MAYA_INSTALL_LOCATION", nullptr, &dtype, (LPBYTE)result, &size); - if ((res == ERROR_SUCCESS)&&(dtype == REG_SZ)) { - result[size] = 0; - loc = result; - } - RegCloseKey(hkey); - } - } - } -} - -#elif defined(__APPLE__) -static void -get_maya_location(const char *ver, string &loc) { - char mpath[64]; - sprintf(mpath, "/Applications/Autodesk/maya%s/Maya.app/Contents", ver); - struct stat st; - if(stat(mpath, &st) == 0) { - loc = mpath; - } -} - -#else // _WIN32 -static void -get_maya_location(const char *ver, string &loc) { - char mpath[64]; -#if __WORDSIZE == 64 - sprintf(mpath, "/usr/autodesk/maya%s-x64", ver); -#else - sprintf(mpath, "/usr/autodesk/maya%s", ver); -#endif - struct stat st; - if(stat(mpath, &st) == 0) { - loc = mpath; - } else { -#if __WORDSIZE == 64 - sprintf(mpath, "/usr/aw/maya%s-x64", ver); -#else - sprintf(mpath, "/usr/aw/maya%s", ver); -#endif - if(stat(mpath, &st) == 0) { - loc = mpath; - } - } -} - -#endif // _WIN32 - - -int -main(int argc, char *argv[]) { - // First, get the command line and append _bin, so we will actually run - // maya2egg_bin.exe, egg2maya_bin.exe, etc. - Filename command = ExecutionEnvironment::get_binary_name(); - - if (command.empty() || command == "unknown" || !command.exists()) { - command = Filename::from_os_specific(argv[0]); - - if (!command.is_fully_qualified()) { - DSearchPath path; - path.append_path(ExecutionEnvironment::get_environment_variable("PATH")); - #ifdef _WIN32 - command.set_extension("exe"); - #endif - command.resolve_filename(path); - } - } - - command.set_basename_wo_extension(command.get_basename_wo_extension() + "_bin"); - string os_command = command.to_os_specific(); - - // First start with $PANDA_MAYA_LOCATION. If it is set, it overrides - // everything else. - Filename maya_location = Filename::expand_from("$PANDA_MAYA_LOCATION"); - if (!maya_location.empty()) { - // Reset maya_location to its full long name, because Maya requires this. - maya_location.make_canonical(); - maya_location = Filename::from_os_specific(maya_location.to_os_long_name()); - - } else { - // $PANDA_MAYA_LOCATION wasn't set, so check the normal locations. First, - // we get the standard location, as a point of reference. - Filename standard_maya_location; -#ifdef MAYAVERSION - const char *key = get_version_number(TOSTRING(MAYAVERSION)); - if (key == nullptr) { - cerr << "Unknown Maya version: " << TOSTRING(MAYAVERSION) << "\n"; - } else { - string loc; - get_maya_location(key, loc); - if (loc.empty()) { - cerr << "Cannot locate " << TOSTRING(MAYAVERSION) << ": it does not appear to be installed.\n"; - } else { - standard_maya_location = Filename::from_os_specific(loc); - } - } - if (!standard_maya_location.empty()) { - // Reset standard_maya_location to its full long name, so we can compare - // reliably to the given version. - standard_maya_location.make_canonical(); - standard_maya_location = Filename::from_os_specific(standard_maya_location.to_os_long_name()); - } -#endif // MAYAVERSION - - // Now check if $MAYA_LOCATION is set. If it is, and it's consistent with - // the standard location, we respect it. - maya_location = Filename::expand_from("$MAYA_LOCATION"); - if (!maya_location.empty()) { - // Reset maya_location to its full long name, so we can compare it - // reliably to the standard location; and also because Maya requires - // this. - maya_location.make_canonical(); - maya_location = Filename::from_os_specific(maya_location.to_os_long_name()); - } - - if (maya_location.empty()) { - // If it is not set, we use the standard version instead. - maya_location = standard_maya_location; - - } else if (maya_location != standard_maya_location) { - // If it *is* set, we verify that OpenMaya.dll matches the standard - // version. - Filename openmaya_given = get_openmaya_filename(maya_location); - Filename openmaya_standard = get_openmaya_filename(standard_maya_location); - - if (openmaya_given != openmaya_standard) { - // Check the md5 hashes of the DLL. - HashVal hash_given, hash_standard; - if (!hash_standard.hash_file(openmaya_standard)) { - // Couldn't read the standard file, so use the given one. - - } else { - if (!hash_given.hash_file(openmaya_given)) { - // Couldn't even read the given file; use the standard one - // instead. - maya_location = standard_maya_location; - - } else { - if (hash_standard != hash_given) { - // No match; it must be the wrong version. - cerr << "$MAYA_LOCATION points to wrong version; using standard location instead.\n"; - maya_location = standard_maya_location; - } else { - // The hash matches; keep the given MAYA_LOCATION setting. - } - } - } - } - } - } - - if (maya_location.empty()) { - cerr << "$MAYA_LOCATION is not set!\n"; - exit(1); - } - - cerr << "MAYA_LOCATION: " << maya_location.to_os_specific() << endl; - if (!maya_location.is_directory()) { - cerr << "The directory referred to by $MAYA_LOCATION does not exist!\n"; - exit(1); - } - - // Look for OpenMaya.dll as a sanity check. - Filename openmaya = get_openmaya_filename(maya_location); - if (!openmaya.is_regular_file()) { - cerr << "Could not find OpenMaya library in $MAYA_LOCATION!\n"; - exit(1); - } - - // Re-set MAYA_LOCATION to its properly sanitized form. - { - string putenv_str = "MAYA_LOCATION=" + maya_location.to_os_specific(); - char *putenv_cstr = strdup(putenv_str.c_str()); - putenv(putenv_cstr); - } - -#ifdef _WIN32 - string sep = ";"; -#else - string sep = ":"; -#endif - - // Now set PYTHONHOME & PYTHONPATH. Maya2008 requires this to be set and - // pointing within $MAYA_LOCATION, or it might get itself confused with - // another Python installation (e.g. Panda's). - Filename python = Filename(maya_location, "Python"); - if (python.is_directory()) { - { - string putenv_str = "PYTHONHOME=" + python.to_os_specific(); - char *putenv_cstr = strdup(putenv_str.c_str()); - putenv(putenv_cstr); - } - { - string putenv_str = "PYTHONPATH=" + python.to_os_specific(); - - Filename pyzip = find_pyzip(maya_location); - if (!pyzip.empty() && pyzip.exists()) { - putenv_str += sep; - putenv_str += pyzip.to_os_specific(); - } - - Filename site_packages(python, "lib/site-packages"); - if (site_packages.is_directory()) { - putenv_str += sep; - putenv_str += site_packages.to_os_specific(); - } - - char *putenv_cstr = strdup(putenv_str.c_str()); - putenv(putenv_cstr); - } - } - - // Also put the Maya bin directory on the PATH. -#ifdef IS_OSX - Filename bin = Filename(maya_location, "MacOS"); -#else - Filename bin = Filename(maya_location, "bin"); -#endif - if (bin.is_directory()) { - const char *path = getenv("PATH"); - if (path == nullptr) { - path = ""; - } - string putenv_str = "PATH="; - - // On Windows, there may also be a bin3 or bin2 directory, we should - // add either one to the PATH. -#ifdef _WIN32 - Filename bin3 = Filename(maya_location, "bin3"); - if (bin3.is_directory()) { - putenv_str += bin3.to_os_specific() + sep; - } -#endif - putenv_str += bin.to_os_specific() + sep + path; - - char *putenv_cstr = strdup(putenv_str.c_str()); - putenv(putenv_cstr); - } - -#ifdef IS_OSX - // And on DYLD_LIBRARY_PATH. - if (bin.is_directory()) { - const char *path = getenv("DYLD_LIBRARY_PATH"); - if (path == nullptr) { - path = ""; - } - string sep = ":"; - string putenv_str = "DYLD_LIBRARY_PATH=" + bin.to_os_specific() + sep + path; - char *putenv_cstr = strdup(putenv_str.c_str()); - putenv(putenv_cstr); - } - - // We also have to give it a way to find the Maya frameworks. - Filename fw_dir = Filename(maya_location, "Frameworks"); - if (fw_dir.is_directory()) { - const char *path = getenv("DYLD_FALLBACK_FRAMEWORK_PATH"); - if (path == nullptr) { - path = ""; - } - string sep = ":"; - string putenv_str = "DYLD_FALLBACK_FRAMEWORK_PATH=" + fw_dir.to_os_specific() + sep + path; - char *putenv_cstr = strdup(putenv_str.c_str()); - putenv(putenv_cstr); - } - -#elif !defined(_WIN32) - // Linux (or other non-Windows OS) gets it added to LD_LIBRARY_PATH. - if (bin.is_directory()) { - const char *path = getenv("LD_LIBRARY_PATH"); - if (path == nullptr) { - path = ""; - } - string sep = ":"; - string putenv_str = "LD_LIBRARY_PATH=" + bin.to_os_specific() + sep + path; - char *putenv_cstr = strdup(putenv_str.c_str()); - putenv(putenv_cstr); - } - -#endif // IS_OSX - - // Now that we have set up the environment variables properly, chain to the - // actual maya2egg_bin (or whichever) executable. - -#ifdef _WIN32 - // Windows case. - char *command_line = strdup(GetCommandLine()); - STARTUPINFO startup_info; - PROCESS_INFORMATION process_info; - GetStartupInfo(&startup_info); - BOOL result = CreateProcess(os_command.c_str(), - command_line, - nullptr, nullptr, true, 0, - nullptr, nullptr, - &startup_info, - &process_info); - if (result) { - WaitForSingleObject(process_info.hProcess, INFINITE); - DWORD exit_code = 0; - - if (GetExitCodeProcess(process_info.hProcess, &exit_code)) { - if (exit_code != 0) { - cerr << "Program exited with status " << exit_code << "\n"; - } - } - - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - exit(exit_code); - } - cerr << "Couldn't execute " << command << ": " << GetLastError() << "\n"; - -#else - // Unix case. - execvp(os_command.c_str(), argv); -#endif - - // Couldn't execute for some reason. - return 1; -} diff --git a/pandatool/src/mayaprogs/normal_test.cxx b/pandatool/src/mayaprogs/normal_test.cxx deleted file mode 100644 index 41680254de0..00000000000 --- a/pandatool/src/mayaprogs/normal_test.cxx +++ /dev/null @@ -1,289 +0,0 @@ - -#include -#include -#include -#include - -#ifndef _BOOL -#define _BOOL 1 -#endif - -#define REQUIRE_IOSTREAM - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using std::cerr; -using std::endl; - -void -scan_nodes() { - MStatus status; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - exit(1); - } - - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - exit(1); - } - - MFnDagNode dag_node(dag_path, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - exit(1); - } - - cerr << dag_node.name() << "\n"; - - dag_iterator.next(); - } -} - -MFnBlendShapeDeformer * -get_slider(MString slider_name) { - MStatus status; - - status = MGlobal::selectByName(slider_name, MGlobal::kReplaceList); - if (!status) { - status.perror(slider_name); - exit(1); - } - MSelectionList list; - status = MGlobal::getActiveSelectionList(list); - if (!status) { - status.perror("MGLobal::getActiveSelectionList"); - exit(1); - } - - unsigned int num_objects = list.length(); - if (num_objects != 1) { - cerr << "Warning: multiple objects match " << slider_name << "\n"; - } - - for (unsigned int i = 0; i < num_objects; i++) { - MObject obj; - status = list.getDependNode(i, obj); - if (!status) { - cerr << "selected element is not a dependency node.\n"; - status.perror("getDependNode"); - } else { - if (obj.hasFn(MFn::kBlendShape)) { - MFnBlendShapeDeformer *slider = new MFnBlendShapeDeformer(obj, &status); - if (!status) { - status.perror("MFnBlendShapeDeformer constructor"); - } else { - cerr << "got slider " << slider->name() << "\n"; - return slider; - } - } - - cerr << "selected element is not a blend shape\n"; - } - } - - cerr << "Couldn't find slider " << slider_name << "\n"; - exit(1); -} - -MFnMesh * -get_mesh(MString mesh_name) { - MStatus status; - - status = MGlobal::selectByName(mesh_name, MGlobal::kReplaceList); - if (!status) { - status.perror(mesh_name); - exit(1); - } - MSelectionList list; - status = MGlobal::getActiveSelectionList(list); - if (!status) { - status.perror("MGLobal::getActiveSelectionList"); - exit(1); - } - - unsigned int num_objects = list.length(); - if (num_objects != 1) { - cerr << "Warning: multiple objects match " << mesh_name << "\n"; - } - - for (unsigned int i = 0; i < num_objects; i++) { - MObject obj; - status = list.getDependNode(i, obj); - if (!status) { - cerr << "selected element is not a dependency node.\n"; - status.perror("getDependNode"); - - } else { - if (obj.hasFn(MFn::kMesh)) { - // Maybe it's a mesh object itself. - MFnMesh *mesh = new MFnMesh(obj, &status); - if (!status) { - status.perror("MFnMesh constructor"); - } else { - cerr << "got mesh " << mesh->name() << "\n"; - return mesh; - } - - } else if (obj.hasFn(MFn::kDagNode)) { - // Maybe it's a dag node. - MDagPath path; - status = MDagPath::getAPathTo(obj, path); - if (!status) { - status.perror("MDagPath::getAPathTo"); - exit(1); - } - if (path.hasFn(MFn::kMesh)) { - MFnMesh *mesh = new MFnMesh(path, &status); - if (!status) { - status.perror("MFnMesh constructor"); - } else { - cerr << "got mesh " << mesh->name() << "\n"; - return mesh; - } - } - } - - cerr << "selected element is not a mesh\n"; - } - } - - cerr << "Couldn't find mesh " << mesh_name << "\n"; - exit(1); -} - -void -output_vertices(const char *filename, MFnMesh &mesh) { - MStatus status; - - MPointArray verts; - // status = mesh.getPoints(verts, MSpace::kObject); - status = mesh.getPoints(verts, MSpace::kWorld); - if (!status) { - status.perror("mesh.getPoints"); - exit(1); - } - - std::ofstream file(filename, std::ios::out | std::ios::trunc); - if (!file) { - cerr << "Couldn't open " << filename << " for output.\n"; - exit(1); - } - - unsigned int num_verts = verts.length(); - cerr << "writing " << num_verts << " vertices to " << filename << "\n"; - for (unsigned int i = 0; i < num_verts; i++) { - file << i << ". " << verts[i] << "\n"; - } -} - -void -output_normals() { - MStatus status; - MDagPath dagPath, *_dag_path; - MObject component; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - exit(1); - } - - while (!dag_iterator.isDone()) { - status = dag_iterator.getPath(dagPath); - if (!status) { - status.perror("MItDag::getPath"); - exit(1); - } - - _dag_path = new MDagPath(dagPath); - - MFnDagNode dag_node(*_dag_path, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - exit(1); - } - - cerr << dag_node.name() << "\n"; - - if (_dag_path->hasFn(MFn::kMesh)) { - unsigned int numShapes; - status = _dag_path->numberOfShapesDirectlyBelow(numShapes); - cerr << "----numShapes: " << numShapes << "\n"; - /* - if (numShapes == 1) { - _dag_path->extendToShape(); - } - */ - } - - MItMeshPolygon faceIter(*_dag_path, component, &status); - if( !status ) cerr << "Error at MItMeshPolygon" << endl; - - MFnMesh meshFn(*_dag_path); - - // Traverse the polygonal face - for (; !faceIter.isDone();faceIter.next()) { - int nVerts = faceIter.polygonVertexCount(); - - // Traverse the vertices to get their indexes and print out the normals - for (int i = 0;iget_thread_data(_thread_index); if (!thread_data->is_empty()) { - int frame_number = thread_data->get_latest_frame_number(); - if (frame_number != _current_frame) { - _current_frame = frame_number; + if (_frame_number >= 0) { + if (thread_data->has_frame(_frame_number)) { + if (_current_frame != _frame_number) { + _current_frame = _frame_number; + update_data(); + } + } + } else { + int frame_number = thread_data->get_latest_frame_number(); + if (frame_number != _current_frame) { + _current_frame = frame_number; - update_data(); + update_data(); + } } } } @@ -88,6 +98,8 @@ update() { /** * Changes the collector represented by this flame graph. This may force a * redraw. + * + * Leaves the history stack untouched. */ void PStatFlameGraph:: set_collector_index(int collector_index) { @@ -117,6 +129,168 @@ set_collector_index(int collector_index) { } } +/** + * Goes to a different collector, but remembers the previous collector. + */ +void PStatFlameGraph:: +push_collector_index(int collector_index) { + if (_collector_index != collector_index) { + _history.push_back(_collector_index); + set_collector_index(collector_index); + } +} + +/** + * Goes to the previous visited collector. Returns true if the history stack + * was non-empty. + */ +bool PStatFlameGraph:: +pop_collector_index() { + if (!_history.empty()) { + int collector_index = _history.back(); + _history.pop_back(); + set_collector_index(collector_index); + return true; + } + return false; +} + +/** + * Changes the frame number shown by this flame graph. This may force a redraw. + */ +void PStatFlameGraph:: +set_frame_number(int frame_number) { + if (_frame_number != frame_number) { + _frame_number = frame_number; + _current_frame = frame_number; + _title_unknown = true; + _stack.clear(); + update_data(); + + if (_average_mode) { + _stack.update_averages(_average_cursor); + _time_width = _stack.get_net_value(true); + if (_time_width == 0.0) { + _time_width = 1.0 / pstats_target_frame_rate; + } + normal_guide_bars(); + } + } +} + +/** + * Sets the frame number to the oldest available frame. + */ +bool PStatFlameGraph:: +first_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int oldest = thread_data->get_oldest_frame_number(); + if (_frame_number != oldest && thread_data->has_frame(oldest)) { + set_frame_number(oldest); + return true; + } + return false; +} + +/** + * Advances to the next available frame. Returns true if the frame number was + * changed after a call to this method. + */ +bool PStatFlameGraph:: +next_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int latest = thread_data->get_latest_frame_number(); + if (_frame_number < 0 || _frame_number > latest) { + set_frame_number(latest); + return true; + } + + for (int i = _frame_number + 1; i <= latest; ++i) { + if (thread_data->has_frame(i)) { + set_frame_number(i); + return true; + } + } + + return false; +} + +/** + * Reverts to the previous frame. Returns true if the frame number was changed + * after a call to this method. + */ +bool PStatFlameGraph:: +prev_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int oldest = thread_data->get_oldest_frame_number(); + + int i; + if (_frame_number < 0) { + i = thread_data->get_latest_frame_number(); + } else { + i = _frame_number - 1; + } + while (i >= oldest) { + if (thread_data->has_frame(i)) { + set_frame_number(i); + return true; + } + --i; + } + + return false; +} + +/** + * Sets the frame number to the latest available frame. + */ +bool PStatFlameGraph:: +last_frame() { + const PStatClientData *client_data = _monitor->get_client_data(); + if (client_data == nullptr) { + return false; + } + + const PStatThreadData *thread_data = client_data->get_thread_data(_thread_index); + if (thread_data == nullptr || thread_data->is_empty()) { + return false; + } + + int latest = thread_data->get_latest_frame_number(); + if (_frame_number != latest && thread_data->has_frame(latest)) { + set_frame_number(latest); + return true; + } + return false; +} + /** * Returns the text suitable for the title label on the top line. */ @@ -150,6 +324,10 @@ get_title_text() { _title_unknown = true; } + if (_frame_number >= 0) { + text += " (frame " + format_string(_frame_number) + ")"; + } + return text; } diff --git a/pandatool/src/pstatserver/pStatFlameGraph.h b/pandatool/src/pstatserver/pStatFlameGraph.h index 721651e43dc..5e742383b26 100644 --- a/pandatool/src/pstatserver/pStatFlameGraph.h +++ b/pandatool/src/pstatserver/pStatFlameGraph.h @@ -36,7 +36,7 @@ class PStatFrameData; class PStatFlameGraph : public PStatGraph { public: PStatFlameGraph(PStatMonitor *monitor, - int thread_index, int collector_index, + int thread_index, int collector_index, int frame_number, int xsize, int ysize); virtual ~PStatFlameGraph(); @@ -45,6 +45,17 @@ class PStatFlameGraph : public PStatGraph { INLINE int get_thread_index() const; INLINE int get_collector_index() const; void set_collector_index(int collector_index); + void push_collector_index(int collector_index); + bool pop_collector_index(); + INLINE void clear_history(); + INLINE size_t get_history_depth() const; + + INLINE int get_frame_number() const; + void set_frame_number(int collector_index); + bool first_frame(); + bool next_frame(); + bool prev_frame(); + bool last_frame(); INLINE double get_horizontal_scale() const; @@ -123,12 +134,15 @@ class PStatFlameGraph : public PStatGraph { int _thread_index; int _collector_index; int _orig_collector_index; + int _frame_number; bool _average_mode; size_t _average_cursor; double _time_width; int _current_frame; bool _title_unknown; + + std::vector _history; }; #include "pStatFlameGraph.I" diff --git a/pandatool/src/pstatserver/pStatMonitor.cxx b/pandatool/src/pstatserver/pStatMonitor.cxx index 86390d5ab74..cbc49a71403 100644 --- a/pandatool/src/pstatserver/pStatMonitor.cxx +++ b/pandatool/src/pstatserver/pStatMonitor.cxx @@ -654,7 +654,7 @@ open_strip_chart(int thread_index, int collector_index, bool show_level) { * Opens a new flame graph showing the indicated data. */ PStatGraph *PStatMonitor:: -open_flame_graph(int thread_index, int collector_index) { +open_flame_graph(int thread_index, int collector_index, int frame_number) { return nullptr; } diff --git a/pandatool/src/pstatserver/pStatMonitor.h b/pandatool/src/pstatserver/pStatMonitor.h index 5e71be4b535..d98ce2b9b09 100644 --- a/pandatool/src/pstatserver/pStatMonitor.h +++ b/pandatool/src/pstatserver/pStatMonitor.h @@ -104,7 +104,7 @@ class PStatMonitor : public ReferenceCount { virtual PStatGraph *open_timeline(); virtual PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - virtual PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + virtual PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); virtual PStatGraph *open_piano_roll(int thread_index); void write_datagram(Datagram &dg) const; diff --git a/pandatool/src/pstatserver/pStatThreadData.cxx b/pandatool/src/pstatserver/pStatThreadData.cxx index 39957916c19..f7bf9e2c5fa 100644 --- a/pandatool/src/pstatserver/pStatThreadData.cxx +++ b/pandatool/src/pstatserver/pStatThreadData.cxx @@ -235,7 +235,7 @@ get_frame_number_after(double time, int start_at) const { while (end < time) { ++i; - if (i >= _frames.size()) { + if ((size_t)i >= _frames.size()) { break; } if (_frames[i] != nullptr) { diff --git a/pandatool/src/scripts/MayaPandaTool.mel b/pandatool/src/scripts/MayaPandaTool.mel deleted file mode 100644 index 0d80c2ffcad..00000000000 --- a/pandatool/src/scripts/MayaPandaTool.mel +++ /dev/null @@ -1,1362 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Panda3D Exporter Tool // -// Carnegie Mellon University ETC (Entertainment Technology Center) Panda3D Team // -// Author: Shao Zhang // -// 04/14/2005 // -// // -// This tool will allow an artist to export and view assets directly from maya. // -// // -// To run this mel script, drag and drop it (the .mel file) into your current // -// maya workspace. // -/////////////////////////////////////////////////////////////////////////////////// -// -// EDIT HISTORY -// -// 06/26/06: ynjh_jo - Major edits; described in http://panda3d.net/phpbb2/viewtopic.php?t=2503 -// 07/03/06: Mark Tomczak (fixermark@gmail.com) - Added "Actor" option to export with -a model option - -global proc pandaExporterUI() -{ - if ( `window -exists PandaExporter2` ) - deleteUI -window PandaExporter2; - - string $unit=`currentUnit -q -linear`; - string $unitFull=`currentUnit -q -linear -fullName`; - - // Window is locked for image dimensions: 280×575 - // (add a few pixels to compensate for title bar and borders) - window - -title "Panda Exporter" - -width 280 - -height 575 - -sizeable 0 - PandaExporter2; - - // Use a formLayout so you control the overlap of the controls - formLayout - -numberOfDivisions 575 - -width 275 - -height 550 - mainForm; - - // First add controls - button - -label "--- E X P O R T ---" - -command "exportButton" - exportButton; - - button - -label "Browse" - -enable 0 - -command ( "browseForFolder \"texPath\"" ) - browseTexPathButton; - - button - -label "Browse" - -enable 0 - -command ( "browseForFolder \"outputPath\"" ) - browseOutputPathButton; - - button - -label "..." - -enable 0 - -command ( "browseForFile \"outputPath\"" ) - browseFilenameButton; - - button - -label "Select a file to Pview" - -command "getFile2Pview" - pviewButton; - - button - -label "Select a file to EGG" - -command "getFile2Egg" - eggButton; - - button - -label "Select a file to BAM" - -command "getFile2Bam" - bamButton; - - button - -label "www.panda3d.org" - -command "openBrowser" - webButton; - - checkBox - -label "Export selected objects" - -value 0 - selectedCB; - - checkBox - -label "Double sided faces" - -value 0 - bfaceCB; - - checkBox - -label "Overwrite if file exists" - -value 1 - overwriteCB; - - checkBox - -label "Run Pview after export" - -value 0 - pviewCB; - - radioCollection exportOptionsRC; - radioButton - -label "Mesh" - -select - -onCommand ( "exportOptionsUI" ) - chooseMeshRB; - radioButton - -label "Actor" - -onCommand ( "exportOptionsUI" ) - chooseActorRB; - radioButton - -label "Animation" - -onCommand ( "exportOptionsUI" ) - chooseAnimationRB; - radioButton - -label "Both" - -onCommand ( "exportOptionsUI" ) - chooseBothRB; - radioButton - -label "Pose" - -onCommand ( "exportOptionsUI" ) - choosePoseRB; - setParent ..; //drop out of exportOptionsRC - - radioCollection animationOptionsRC; - radioButton - -label "Full Range" - -enable 0 - -onCommand ( "animationOptionsUI" ) - chooseFullRangeRB; - radioButton - -label "Custom Range" - -enable 0 - -onCommand ( "animationOptionsUI" ) - chooseCustomRangeRB; - setParent ..; //drop out of animationOptionsRC - - radioCollection outputFileOptionsRC; - radioButton - -label "EGG (ASCII)" - -select - chooseEggRB; - radioButton - -label "BAM (binary)" - -enable 0 - chooseBamRB; - radioButton - -label "Both" - chooseEggBamRB; - setParent ..; //drop out of outputFileOptionsRC - - radioCollection texPathOptionsRC; - radioButton - -label "Reference textures relative to maya file (default)" - -select - -onCommand ( "texPathOptionsUI" ) - chooseDefaultTexPathRB; - radioButton - -label "Reference textures relative to custom path" - -onCommand ( "texPathOptionsUI" ) - chooseCustomTexPathRB; - setParent ..; //drop out of texPathOptionsRC - - radioCollection outputPathOptionsRC; - radioButton - -label "Export to root directory of source file (default)" - -select - -onCommand ( "outputPathOptionsUI" ) - chooseDefaultOutputPathRB; - radioButton - -label "Export to other directory:" - -onCommand ( "outputPathOptionsUI" ) - chooseCustomOutputPathRB; - setParent ..; //drop out of outputPathOptionsRC - - radioCollection outputFilenameOptionsRC; - radioButton - -label "Use original filename" - -select - -onCommand ( "outputFilenameOptionsUI" ) - chooseOriginalFilenameRB; - radioButton - -label "Use alternate filename" - -onCommand ( "outputFilenameOptionsUI" ) - chooseCustomFilenameRB; - setParent ..; //drop out of outputFilenameOptionsRC - - radioCollection transformModeRC; - radioButton - -label "all" - -select - -onCommand ( "transformModeUI" ) - chooseTransformAllRB; - radioButton - -label "model/DCS flag" - -onCommand ( "transformModeUI" ) - chooseTransformModelRB; - setParent ..; //drop out of transformModeRC - - text - -label "Maya Panda Exporter v.1.3 CMU/ETC Panda3D Team" - -font "plainLabelFont" - titleText; - - text - -label "Output File Options:" - -font "plainLabelFont" - outputFileOptionsText; - - text - -label "Texture Path Options:" - -font "plainLabelFont" - texPathOptionsText; - - text - -label "Specify alternate directory:" - -font "plainLabelFont" - customTexPathText; - - text - -label "Output directory Options:" - -font "plainLabelFont" - outputPathOptionsText; - - text - -label "Specify alternate directory:" - -font "plainLabelFont" - customOutputPathText; - - text - -label "Output filename Options:" - -font "plainLabelFont" - outputFilenameOptionsText; - - text - -label "Save transform:" - -font "plainLabelFont" - transformModeText; - - text - -label ("Convert unit from ( "+$unitFull+" ) to : ") - -align "right" - -font "boldLabelFont" - convertUnitText; - - textField - -editable 1 - -enable 0 - customTexPathTF; - - textField - -editable 1 - -enable 0 - customOutputPathTF; - - textField - -editable 1 - -enable 0 - customFilenameTF; - - optionMenu - unitMenu; - menuItem -label "mm"; - menuItem -label "cm"; - menuItem -label "m"; - menuItem -label "km"; - menuItem -label "in"; - menuItem -label "ft"; - menuItem -label "yd"; - menuItem -label "nmi"; - menuItem -label "mi"; - - - frameLayout - -label "Export Options:" - -font "plainLabelFont" - -labelIndent 2 - -collapsable 0 - -collapse 0 - -borderStyle "etchedOut" - leftFrame; - setParent ..; //drop out of leftFrame - - frameLayout - -label "" - -collapsable 0 - -collapse 0 - -borderStyle "etchedOut" - leftMiddleFrame; - setParent ..; //drop out of leftFrame - - frameLayout - -label "" - -collapsable 0 - -collapse 0 - -borderStyle "etchedOut" - leftBottomFrame; - setParent ..; //drop out of leftFrame - - frameLayout - -label "Animation Options:" - -font "plainLabelFont" - -labelIndent 2 - -collapsable 0 - -collapse 0 - -borderStyle "etchedOut" - rightFrame; - - columnLayout - -columnAttach "left" 0 - -rowSpacing 0 - -columnWidth 60 - leftFrameColumn; - - text -label "\n\n"; - text -label "Start Frame:"; - textField - -editable 1 - -enable 0 - -width 108 - startFrameTF; - - text -label "End Frame:"; - textField - -editable 1 - -enable 0 - -width 108 - endFrameTF; - - setParent ..; //drop out of leftFrameColumn - setParent ..; //drop out of rightFrame - - frameLayout - -label "Extra Tools" - -font "plainLabelFont" - -labelIndent 28 - -collapsable 0 - -collapse 0 - -borderStyle "etchedOut" - extraToolsFrame; - setParent ..; //drop out of extraToolsFrame - - frameLayout - -label "" - -collapsable 0 - -collapse 0 - -borderStyle "etchedIn" - exportButtonFrame; - setParent ..; //drop out of extraToolsFrame - - setParent ..; //drop out of "mainForm" - - // Now edit the layout of the controls in "mainForm - formLayout -edit - - - /* text */ - -ap titleText "top" 0 2 - -ap titleText "left" 0 5 - -ap titleText "right" 0 575 - - -ap outputFileOptionsText "top" 0 188 - -ap outputFileOptionsText "left" 0 10 - -ap outputFileOptionsText "right" 0 210 - - -ap texPathOptionsText "top" 0 226 - -ap texPathOptionsText "left" 0 10 - -ap texPathOptionsText "right" 0 210 - - -ap customTexPathText "top" 0 280 - -ap customTexPathText "left" 0 10 - -ap customTexPathText "right" 0 300 - - -ap outputPathOptionsText "top" 0 324 - -ap outputPathOptionsText "left" 0 10 - -ap outputPathOptionsText "right" 0 300 - - -ap customOutputPathText "top" 0 378 - -ap customOutputPathText "left" 0 10 - -ap customOutputPathText "right" 0 300 - - -ap convertUnitText "top" 0 165 - -ap convertUnitText "left" 0 10 - -ap convertUnitText "right" 0 460 - - -ap outputFilenameOptionsText "top" 0 422 - -ap outputFilenameOptionsText "left" 0 10 - -ap outputFilenameOptionsText "right" 0 290 - - -ap transformModeText "top" 0 505 - -ap transformModeText "left" 0 10 - -ap transformModeText "right" 0 290 - - - /* textfields */ - -ap customTexPathTF "top" 0 298 - -ap customTexPathTF "left" 0 10 - -ap customTexPathTF "right" 0 480 - - -ap customOutputPathTF "top" 0 396 - -ap customOutputPathTF "left" 0 10 - -ap customOutputPathTF "right" 0 480 - - -ap customFilenameTF "top" 0 480 - -ap customFilenameTF "left" 0 10 - -ap customFilenameTF "right" 0 284 - - - -ap unitMenu "top" 0 160 - -ap unitMenu "left" 0 460 - - - /* frames */ - -ap leftFrame "top" 0 20 - -ap leftFrame "bottom" 0 80 - -ap leftFrame "left" 0 4 - -ap leftFrame "right" 0 330 - - -ap leftMiddleFrame "top" 0 80 - -ap leftMiddleFrame "bottom" 0 158 - -ap leftMiddleFrame "left" 0 4 - -ap leftMiddleFrame "right" 0 330 - - -ap leftBottomFrame "top" 0 158 - -ap leftBottomFrame "bottom" 0 188 - -ap leftBottomFrame "left" 0 4 - -ap leftBottomFrame "right" 0 574 - - -ap rightFrame "top" 0 20 - -ap rightFrame "bottom" 0 158 - -ap rightFrame "left" 0 334 - -ap rightFrame "right" 0 574 - - -ap extraToolsFrame "top" 0 425 - -ap extraToolsFrame "bottom" 0 542 - -ap extraToolsFrame "left" 0 335 - -ap extraToolsFrame "right" 0 574 - - -ap exportButtonFrame "top" 0 542 - -ap exportButtonFrame "bottom" 0 573 - -ap exportButtonFrame "left" 0 2 - -ap exportButtonFrame "right" 0 574 - - - - /* checkboxes */ - -ap selectedCB "top" 0 82 - -ap selectedCB "left" 0 12 - - -ap bfaceCB "top" 0 101 - -ap bfaceCB "left" 0 12 - - -ap overwriteCB "top" 0 120 - -ap overwriteCB "left" 0 12 - - -ap pviewCB "top" 0 139 - -ap pviewCB "left" 0 12 - - - - /* exportOptionsRC */ - -ap chooseMeshRB "top" 0 21 - -ap chooseMeshRB "left" 0 170 - - -ap chooseActorRB "top" 0 40 - -ap chooseActorRB "left" 0 20 - - -ap chooseBothRB "top" 0 59 - -ap chooseBothRB "left" 0 20 - - -ap chooseAnimationRB "top" 0 40 - -ap chooseAnimationRB "left" 0 170 - - -ap choosePoseRB "top" 0 59 - -ap choosePoseRB "left" 0 170 - - - - /* animationOptionsRC */ - -ap chooseFullRangeRB "top" 0 40 - -ap chooseFullRangeRB "left" 0 346 - - -ap chooseCustomRangeRB "top" 0 59 - -ap chooseCustomRangeRB "left" 0 346 - - - - /* outputFileOptionsRC */ - -ap chooseEggRB "top" 0 205 - -ap chooseEggRB "left" 0 10 - - -ap chooseBamRB "top" 0 205 - -ap chooseBamRB "left" 0 196 - - -ap chooseEggBamRB "top" 0 205 - -ap chooseEggBamRB "left" 0 380 - - - - /* texPathOptionsRC */ - -ap chooseDefaultTexPathRB "top" 0 244 - -ap chooseDefaultTexPathRB "left" 0 10 - - -ap chooseCustomTexPathRB "top" 0 264 - -ap chooseCustomTexPathRB "left" 0 10 - - - - /* outputPathOptionsRC */ - -ap chooseDefaultOutputPathRB "top" 0 342 - -ap chooseDefaultOutputPathRB "left" 0 10 - - -ap chooseCustomOutputPathRB "top" 0 362 - -ap chooseCustomOutputPathRB "left" 0 10 - - - - /* outputFilenameOptionsRC */ - -ap chooseOriginalFilenameRB "top" 0 440 - -ap chooseOriginalFilenameRB "left" 0 10 - - -ap chooseCustomFilenameRB "top" 0 460 - -ap chooseCustomFilenameRB "left" 0 10 - - /* transformModeRC */ - -ap chooseTransformAllRB "top" 0 525 - -ap chooseTransformAllRB "left" 0 10 - - -ap chooseTransformModelRB "top" 0 525 - -ap chooseTransformModelRB "left" 0 120 - - - /* browseTexPathButton */ - -ap browseTexPathButton "top" 0 298 - -ap browseTexPathButton "left" 0 485 - -ap browseTexPathButton "right" 0 575 - - - /* browseOutputPathButton */ - -ap browseOutputPathButton "top" 0 396 - -ap browseOutputPathButton "left" 0 485 - -ap browseOutputPathButton "right" 0 575 - - - /* browseFilenameButton */ - -ap browseFilenameButton "top" 0 480 - -ap browseFilenameButton "left" 0 285 - -ap browseFilenameButton "right" 0 330 - - - - /* extra buttons */ - -ap pviewButton "top" 0 445 - -ap pviewButton "left" 0 340 - -ap pviewButton "right" 0 565 - - -ap eggButton "top" 0 468 - -ap eggButton "left" 0 340 - -ap eggButton "right" 0 565 - - -ap bamButton "top" 0 492 - -ap bamButton "left" 0 340 - -ap bamButton "right" 0 565 - - -ap webButton "top" 0 515 - -ap webButton "left" 0 340 - -ap webButton "right" 0 565 - - - - /* exportButton */ - -ap exportButton "top" 0 545 - -ap exportButton "bottom" 0 570 - -ap exportButton "left" 0 8 - -ap exportButton "right" 0 565 - - - mainForm; //End of layout - - // defining the current unit value - optionMenu -edit -value $unit unitMenu; - - showWindow PandaExporter2; -} - - -//Automatically start the tool -pandaExporterUI(); - -/////////////////////////////////////////////////////////// -// Process: openBrowser // -// Opens the default browser at the panda3d url // -/////////////////////////////////////////////////////////// -global proc openBrowser() -{ - print "\nGoing to www.panda3d.org...\n"; - - launch -webPage "www.panda3d.org"; -} - -/////////////////////////////////////////////////////////// -// Process: exportOptionsUI // -// Updates the UI when a radio button is chosen // -/////////////////////////////////////////////////////////// -global proc exportOptionsUI() -{ - string $selectedRB = `radioCollection -query -select exportOptionsRC`; - - switch ($selectedRB) - { - case "chooseMeshRB": - print("Export Mesh Chosen\n"); - textField -edit -enable 0 startFrameTF; - textField -edit -enable 0 endFrameTF; - radioButton -edit -enable 0 chooseFullRangeRB; - radioButton -edit -enable 0 chooseCustomRangeRB; - break; - case "chooseActorRB": - print("Export Actor Chosen\n"); - textField -edit -enable 0 startFrameTF; - textField -edit -enable 0 endFrameTF; - radioButton -edit -enable 0 chooseFullRangeRB; - radioButton -edit -enable 0 chooseCustomRangeRB; - break; - case "chooseAnimationRB": - print("Export Animation Chosen\n"); - radioButton -edit -enable 1 -select chooseFullRangeRB; - radioButton -edit -enable 1 chooseCustomRangeRB; - animationOptionsUI(); - break; - case "chooseBothRB": - print("Export Meshes and Animation Chosen\n"); - radioButton -edit -enable 1 -select chooseFullRangeRB; - radioButton -edit -enable 1 chooseCustomRangeRB; - animationOptionsUI(); - break; - case "choosePoseRB": - print("Export Pose Chosen\n"); - textField -edit -enable 1 startFrameTF; - textField -edit -enable 0 endFrameTF; - radioButton -edit -enable 0 chooseFullRangeRB; - radioButton -edit -enable 1 -select chooseCustomRangeRB; - break; - } -} - -/////////////////////////////////////////////////////////// -// Process: animationOptionsUI // -// Updates the UI when a radio button is chosen // -/////////////////////////////////////////////////////////// -global proc animationOptionsUI() -{ - string $selectedRB = `radioCollection -query -select animationOptionsRC`; - - switch ($selectedRB) - { - case "chooseFullRangeRB": - print("Animation Full Range Chosen\n"); - textField -edit -enable 0 startFrameTF; - textField -edit -enable 0 endFrameTF; - break; - case "chooseCustomRangeRB": - print("Animation Custom Range Chosen\n"); - textField -edit -enable 1 startFrameTF; - textField -edit -enable 1 endFrameTF; - break; - } -} - -/////////////////////////////////////////////////////////// -// Process: texPathOptionsUI // -// Updates the UI when a radio button is chosen // -/////////////////////////////////////////////////////////// -global proc texPathOptionsUI() -{ - string $selectedRB = `radioCollection -query -select texPathOptionsRC`; - - switch ($selectedRB) - { - case "chooseDefaultTexPathRB": - print("Default Texture Path Chosen\n"); - textField -edit -enable 0 customTexPathTF; - button -edit -enable 0 browseTexPathButton; - break; - case "chooseCustomTexPathRB": - print("Custom Texture Path Chosen\n"); - textField -edit -enable 1 customTexPathTF; - button -edit -enable 1 browseTexPathButton; - break; - } -} - -/////////////////////////////////////////////////////////// -// Process: outputPathOptionsUI // -// Updates the UI when a radio button is chosen // -/////////////////////////////////////////////////////////// -global proc outputPathOptionsUI() -{ - string $selectedRB = `radioCollection -query -select outputPathOptionsRC`; - - switch ($selectedRB) - { - case "chooseDefaultOutputPathRB": - print("Default File Path Chosen\n"); - textField -edit -enable 0 customOutputPathTF; - button -edit -enable 0 browseOutputPathButton; - break; - case "chooseCustomOutputPathRB": - print("Custom File Path Chosen\n"); - textField -edit -enable 1 customOutputPathTF; - button -edit -enable 1 browseOutputPathButton; - break; - } -} - -/////////////////////////////////////////////////////////// -// Process: outputFilenameOptionsUI // -// Updates the UI when a radio button is chosen // -/////////////////////////////////////////////////////////// -global proc outputFilenameOptionsUI() -{ - string $selectedRB = `radioCollection -query -select outputFilenameOptionsRC`; - - switch ($selectedRB) - { - case "chooseOriginalFilenameRB": - print("Default Filename Chosen\n"); - textField -edit -enable 0 customFilenameTF; - button -edit -enable 0 browseFilenameButton; - break; - case "chooseCustomFilenameRB": - print("Custom Filename Chosen\n"); - textField -edit -enable 1 customFilenameTF; - button -edit -enable 1 browseFilenameButton; - break; - } -} - -/////////////////////////////////////////////////////////// -// Process: transformModeUI // -// Updates the UI when a radio button is chosen // -/////////////////////////////////////////////////////////// -global proc transformModeUI() -{ - string $selectedRB = `radioCollection -query -select transformModeRC`; - - switch ($selectedRB) - { - case "chooseTransformModelRB": - print("Save transform of objects which have model- or DCS-flag only, CLEARS local pivot, orientation, scale, and shear of the other objects (all transform will be frozen to the vertices and will be 0 when loaded into Panda3D)\n"); - break; - case "chooseTransformAllRB": - print("Save transform of all objects, PRESERVES local pivot, orientation, scale, and shear (all transform will remain when loaded into Panda3D)\n"); - break; - } -} - -/////////////////////////////////////////////////////////////// -// Process: browseForFolder // -// Browses for a directory and returns the path as a string // -/////////////////////////////////////////////////////////////// -global proc browseForFolder(string $destination) -{ - fileBrowserDialog - -mode 4 - -fileCommand ( "browseForFolderCallback \"" + $destination + "\"" ) - -actionName "Pick a Folder"; -} - -global proc browseForFolderCallback(string $destination, string $result, string $type ) -{ - // Do whatever you need to with the $result - print ( "Folder selection: " + $result + "\n" ); - - if ( $destination == "texPath") - { - textField -edit -text $result customTexPathTF; - } - else - { - textField -edit -text $result customOutputPathTF; - } -} - -/////////////////////////////////////////////////////////////// -// Process: browseForFile // -// Browses for a file // -/////////////////////////////////////////////////////////////// -global proc browseForFile(string $destination) -{ - fileBrowserDialog - -mode 0 - -fileType "*.EGG" - -fileCommand ( "browseForFileCallback \"" + $destination + "\"" ) - -actionName "Pick a file"; -} - -global proc browseForFileCallback(string $destination, string $result, string $type ) -{ - $result=filePart($result); - $result=match( "[^.]*", $result ); - print ( "File name: " + $result + "\n" ); - - textField -edit -text $result customFilenameTF; -} - -/////////////////////////////////////////////////////////// -// Process: filePart // -// Extracts the file portion of an absolute filepath. // -// Input: e.g. "D:/projects/default/scenes/myScene.mb" // -// Result: e.g. "myScene.mb" // -// Filepath can be delimited with // -// either slash ("/" or "\") // -/////////////////////////////////////////////////////////// -global proc string filePart( string $path ) -{ - string $filePart = match( "[^/\\]*$", $path ); - - return $filePart; -} - -//////////////////////////////////////////////////////////// -// Process: pathPart // -// Extracts the path portion of an absolute filepath. // -// Input: e.g. "D:/projects/default/scenes/myScene.mb" // -// Result: e.g. "D:/projects/default/scenes" // -// Note: Requires that the filepath be delimited with // -// _forward_ slashes ("/") // -//////////////////////////////////////////////////////////// -global proc string pathPart( string $path ) -{ - string $dir = match( "^.*/", $path ); - - // Strip off trailing '/' - // int $sz = size( $dir ); - // if ( ( $sz > 1 ) && ( substring( $dir, $sz, $sz ) == "/" ) ) - // { - // $dir = substring( $dir, 1, ($sz - 1) ); - // } - return $dir; -} - -/////////////////////////////////////////////////////////////// -// Process: exportScene // -// exports the entire scene/selected objects // -/////////////////////////////////////////////////////////////// -global proc string exportScene( string $selection ) -{ - print "Exporting scene...\n"; - - string $sceneFilePath = `file -q -sceneName`; //get scene filename and path - - if ( $sceneFilePath == "" ) - { - error "You have not yet saved this scene.\nPlease save your scene or specify a custom output directory and filename.\n"; - return "failed"; - } - - string $scenePath = pathPart($sceneFilePath); - string $sceneFile = filePart($sceneFilePath); - string $fileName = `match "^[^\.]*" $sceneFile`; //cut off the file extension - string $tempScenePath = ($scenePath + $fileName + "_temp.mb"); - - if ( $selection == "all") - { - file -op "v=1" -typ "mayaBinary" -ea $tempScenePath; //export the whole scene - print ("Saved entire scene as temporary file: " + $fileName + "_temp.mb\n"); - } - else - { - file -op "v=1" -typ "mayaBinary" -es $tempScenePath; //export only selected objects - print ("Saved selected objects as temporary file: " + $fileName + "_temp.mb\n"); - } - - return $tempScenePath; -} - -/////////////////////////////////////////////////////////////// -// Process: argsBuilder // -// constructs the arguments to pass to maya2egg // -/////////////////////////////////////////////////////////////// -global proc string argsBuilder() -{ - string $args = "maya2egg"; - - //get the version of maya and append it to the maya2egg call - string $mayaVersionLong = `getApplicationVersionAsFloat`; - string $mayaVersionShort = substituteAllString($mayaVersionLong, ".", ""); - print ("MAYA VERSION : "+$mayaVersionShort+"\n"); - //only strips the zeroes if the version number is less than 4 - if (`size($mayaVersionShort)`<4) - { - $mayaVersionShort = substituteAllString($mayaVersionShort, "0", ""); - } - - $args += $mayaVersionShort; - - $args += " "; - - // We always want polygons, never nurbs. - $args += "-p "; - - //check back face culling - if ( `checkBox -query -value bfaceCB` ) - { - $args += "-bface "; - } - - //check animation options - string $exportOptionsARGS = `radioCollection -query -select exportOptionsRC`; - - switch ($exportOptionsARGS) - { - case "chooseMeshRB": - $args += "-a none "; - break; - case "chooseActorRB": - $args += "-a model "; - break; - case "chooseAnimationRB": - $args += "-a chan "; - - //set the start frames **Does not check if start frame < end frame **Does not support negative values **Does not check if start/end frame is within bounds of the scene - if ( `radioCollection -query -select animationOptionsRC` == "chooseCustomRangeRB" ) - { - string $startFrameARGS = `textField -query -text startFrameTF`; - string $endFrameARGS = `textField -query -text endFrameTF`; - - //start frame - if ( `match "[0-9]+" $startFrameARGS` == $startFrameARGS && $startFrameARGS != "") - { - $args += ( "-sf " + `match "[0-9]+" $startFrameARGS` + " " ); - } - else - { - error "Start Frame entered data is the wrong format. Should be an integer.\n"; - return "failed"; - } - - //end frame - if ( `match "[0-9]+" $endFrameARGS` == $endFrameARGS && $endFrameARGS != "") - { - $args += ( "-ef " + `match "[0-9]+" $endFrameARGS` + " " ); - } - else - { - error "End Frame entered data is the wrong format. Should be an integer.\n"; - return "failed"; - } - } - break; - case "chooseBothRB": - $args += "-a both "; - - //set the start frames **Does not check if start frame < end frame **Does not support negative values **Does not check if start/end frame is within bounds of the scene - if ( `radioCollection -query -select animationOptionsRC` == "chooseCustomRangeRB" ) - { - string $startFrameARGS = `textField -query -text startFrameTF`; - string $endFrameARGS = `textField -query -text endFrameTF`; - - //start frame - if ( `match "[0-9]+" $startFrameARGS` == $startFrameARGS && $startFrameARGS != "") - { - $args += ( "-sf " + `match "[0-9]+" $startFrameARGS` + " " ); - } - else - { - error "Start Frame entered data is the wrong format. Should be an integer.\n"; - return "failed"; - } - - //end frame - if ( `match "[0-9]+" $endFrameARGS` == $endFrameARGS && $endFrameARGS != "") - { - $args += ( "-ef " + `match "[0-9]+" $endFrameARGS` + " " ); - } - else - { - error "End Frame entered data is the wrong format. Should be an integer.\n"; - return "failed"; - } - } - - - break; - case "choosePoseRB": - $args += "-a pose "; - - //set the start frames **Does not check if start frame < end frame **Does not support negative values **Does not check if start/end frame is within bounds of the scene - //start frame - string $startFrameARGS = `textField -query -text startFrameTF`; - - if ( `match "[0-9]+" $startFrameARGS` == $startFrameARGS && $startFrameARGS != "") - { - $args += ( "-sf " + `match "[0-9]+" $startFrameARGS` + " " ); - } - else - { - error "Start Frame entered data is the wrong format. Should be an integer.\n"; - return "failed"; - } - break; - } - - //Relative path check - if ( `radioCollection -query -select texPathOptionsRC` == "chooseCustomTexPathRB" ) - { - $args += ( "-pd " + "\"" + `textField -query -text customTexPathTF` + "\"" + " " ); - } - - print ( "Using these arguments: " + $args + "[END]\n" ); - - return $args; -} - -/////////////////////////////////////////////////////////// -// Process: export2Egg // -/////////////////////////////////////////////////////////// -global proc string export2Egg ( string $mbfile, string $destPath, string $destFilename, string $transformMode, string $ARGS) -{ - string $pandaEnvSetup = "set PATH=%MAYA_LOCATION%\\bin;%PATH% & "; - - //Check if there is a valid maya binary file to operate on - if ( $mbfile == "" ) - { - error "Not a valid Maya Binary file."; - - return "failed"; - } - //Start export process - else - { - //make the final egg path - string $eggFile = ( $destPath + $destFilename ); - string $up=`upAxis -q -axis`; - string $unit=`optionMenu -q -value unitMenu`; - - $ARGS += " -cs " + $up+"-up"; - $ARGS += " -uo " + $unit; - $ARGS += " -trans " + $transformMode; - - print ("Your scene will be saved as this egg file: " + $destFilename + "\n" ); - - print ("In this directory: " + $destPath + "\n" ); - - //Check if overwriting is enabled - if ( `checkBox -query -value overwriteCB` ) - { - //Overwrite - print "!!Overwrite enabled!!\n"; - string $result = - system - ( - $pandaEnvSetup + $ARGS - + " -o " - + "\"" + $eggFile + "\"" - + " " - + "\"" + $mbfile + "\"" - ); - - print ($result + "\n"); - } - else - { - //Don't overwrite - string $result = - system - ( - $pandaEnvSetup + $ARGS - + "\"" + $mbfile + "\"" - + " " - + "\"" + $eggFile + "\"" - ); - - print ($result + "\n"); - } - - string $unit=`optionMenu -q -value unitMenu`; - print ("Finished exporting (.mb -> .egg), unit : "+$unit+"\n"); - return $eggFile; - } -} - -/////////////////////////////////////////////////////////// -// Process: exportButton // -/////////////////////////////////////////////////////////// -global proc int exportButton () -{ - //We need to do before calling export2EGG/BAM/Pview: - //-Export a temporary MB - //-Get the destination path - //-Get the filename - //-Get the custom arguments - - //Export the scene as a temporary file - string $tempMBFile = ""; - if ( `checkBox -query -value selectedCB` ) - { - $tempMBFile = exportScene( "selected" ); - if ( $tempMBFile == "failed" ) - { - return 0; - } - } - else - { - $tempMBFile = exportScene( "all" ); - if ( $tempMBFile == "failed" ) - { - return 0; - } - } - - //get the original scene name - string $origFileName = filePart ( `file -q -sceneName` ); - $origFileName = `match "^[^\.]*" $origFileName`; //cut off the file extension - - //-Get the destination path - //-Get the filename - //-Get the custom arguments - - string $eggFile = exportPrep ( $tempMBFile, $origFileName ); - - if ( $eggFile == "failed" ) - { - return 0; - } - else - { - return 1; - } -} - -/////////////////////////////////////////////////////////// -// Process: send2Pview // -/////////////////////////////////////////////////////////// -global proc send2Pview( string $file ) -{ - print "\nStarting pview...\n"; - - string $result = - system - ( - "shell pview -l -c " - + "\"" + $file + "\"" - ); - - print ($result + "\n"); -} - -/////////////////////////////////////////////////////////// -// Process: getFile2Pview // -/////////////////////////////////////////////////////////// -global proc getFile2Pview() -{ - string $selectedFile = `fileDialog -directoryMask "*.egg;*.bam"`; - - string $origFileName = filePart ( $selectedFile ); - $origFileName = `match "^[^\.]*" $origFileName`; //cut off the file extension - - if ( $selectedFile == "") - { - error ( "No file selected\n" ); - } - else - { - send2Pview ( $selectedFile ); - } -} - -/////////////////////////////////////////////////////////// -// Process: getFile2Bam // -/////////////////////////////////////////////////////////// -global proc getFile2Bam() -{ - string $selectedFile = `fileDialog -directoryMask "*.egg"`; - - if ( $selectedFile == "") - { - error ( "No file selected\n" ); - } - else - { - export2Bam ( $selectedFile ); - } -} - -/////////////////////////////////////////////////////////// -// Process: getFile2Egg // -/////////////////////////////////////////////////////////// -global proc getFile2Egg() -{ - string $selectedFile = `fileDialog -directoryMask "*.mb"`; - - string $fileName = filePart ( $selectedFile ); - $fileName = `match "^[^\.]*" $fileName`; //cut off the file extension - - if ( $selectedFile == "") - { - error ( "No file selected\n" ); - } - else - { - exportPrep ( $selectedFile, $fileName ); - } -} -/////////////////////////////////////////////////////////// -// Process: exportPrep // -/////////////////////////////////////////////////////////// -global proc string exportPrep( string $workFile, string $fileName ) -{ - //Get the destination path - string $destPath = ""; - if ( `radioCollection -query -select outputPathOptionsRC` == "chooseDefaultOutputPathRB" ) - { - $destPath = pathPart($workFile); - } - else - { - if ( `textField -query -text customOutputPathTF` == "") - { - error "Output directory field is empty"; - return "failed"; - } - else - { - $destPath = `textField -query -text customOutputPathTF` + "/"; - } - } - - //Get the filename - string $destFilename = ""; - if ( `radioCollection -query -select outputFilenameOptionsRC` == "chooseOriginalFilenameRB" ) - { - $destFilename = $fileName + ".egg"; - } - else - { - if ( `textField -query -text customFilenameTF` == "") - { - error "Custom filename field is empty"; - return "failed"; - } - else - { - $destFilename = `textField -query -text customFilenameTF` + ".egg"; - } - } - - //Get the transform mode - string $transformMode = ""; - if ( `radioCollection -query -select transformModeRC` == "chooseTransformModelRB" ) - { - $transformMode = "model"; - } - else - { - $transformMode = "all"; - } - - //-Get the custom arguments - string $ARGS = argsBuilder(); - - if ( $ARGS == "failed" ) - { - return "failed"; - } - - //export the egg - string $eggFile = export2Egg ( $workFile, $destPath, $destFilename, $transformMode, $ARGS); - - if ( $eggFile == "failed" ) - { - return "failed"; - } - - //run pview if option is selected - if ( `checkBox -query -value pviewCB` ) - { - send2Pview ( $eggFile ); - } - - if ( `radioCollection -query -select outputFileOptionsRC` == "chooseEggBamRB" ) - { - export2Bam ( $eggFile ); - } - - return $eggFile; -} - -/////////////////////////////////////////////////////////// -// Process: export2Bam // -/////////////////////////////////////////////////////////// -global proc export2Bam ( string $eggFile ) -{ - //Check if there is a valid egg file to operate on - if ( $eggFile == "" ) - { - //Cannot operate without an egg first - //throw error if the scene has no associated egg file - error "Invalid egg file"; - } - //Call egg2bam - else - { - string $bamFile = ""; - string $fileName = filePart($eggFile); - string $filePath = pathPart($eggFile); - - //Use either the original fileName or a new fileName for the output - if ( `radioCollection -query -select outputFilenameOptionsRC` == "chooseCustomFilenameRB" ) - { - $bamFile = $filePath + `textField -query -text customFilenameTF` + ".bam"; - } - else - { - $bamFile = $filePath + `match "^[^\.]*" $fileName` + ".bam"; - } - - print ("Your file is: " + $fileName + "\nFound in path: " + $filePath + "\n\n"); - - print ("Your file will be saved as this bam file: " + $bamFile + "\n"); - - //Check if overwriting is enabled - if ( `checkBox -query -value overwriteCB` ) - { - //Overwrite - string $result = - system - ( - "egg2bam -o " - + "\"" + $bamFile + "\"" - + " " - + "\"" + $eggFile + "\"" - ); - - print ($result + "\n"); - } - else - { - //Don't overwrite - string $result = - system - ( - "egg2bam " - + "\"" + $eggFile + "\"" - + " " - + "\"" + $bamFile + "\"" - ); - - print ($result + "\n"); - } - } - - string $unit=`optionMenu -q -value unitMenu`; - print ("Finished exporting (.egg -> .bam), unit : "+$unit+"\n"); -} diff --git a/pandatool/src/scripts/TagSelectedObjects.ms b/pandatool/src/scripts/TagSelectedObjects.ms deleted file mode 100644 index 31136abe27b..00000000000 --- a/pandatool/src/scripts/TagSelectedObjects.ms +++ /dev/null @@ -1,64 +0,0 @@ ---created by Andrew Gartner andrewgartner@gmail.com ---PandaSE team Spring semester 2010 ---Carnegie Mellon Entertainment Technology Center ---TagSelectedObjects.ms ---creates a CF and CS type for any selected object ---in a max scene in order for the egger to apply ---a collision tag of that type based on the script's rollouts - -( -global TagSelectedObjects -try(destroyDialog TagSelectedObjects)catch() -rollout TagSelectedObjects "Tag Selected Objects" -( ---key = #("Test","Test2") ---val = #("Test") -dropdownlist dlist_CStype "Collision Solid Type" items:#("plane","polyset","polygon","sphere","invsphere","tube","floormesh") -dropdownlist dlist_CFtype "Collision Flag Type" items:#("descend","keep","event","solid","center","intangible","level","turnstile") -button btn_tag "Tag Objects" width:140 height:30 -button btn_remTag "Remove Tag" width:140 height:30 - - -fn tagObjects = -( -theObjs = for obj in geometry collect obj -for obj in theObjs do -( - - key = dlist_CStype.selected - val = dlist_CFtype.selected - print key - print val - setUserProp obj key 1 - setUserProp obj val 1 - --obj.wirecolor = gray - -)--for -)--fn - -fn removeTags = -( -theObjs = for obj in geometry collect obj -for obj in theObjs do -( - Cs_type = #("plane","polyset","polygon","sphere","invsphere","tube","floormesh") - Cf_type = #("descend","keep","event","solid","center","intangible","level","turnstile") - for cs_type in Cs_type do - ( - key = cs_type as string - if getUserProp obj key != undefined do - setUserProp obj key 0 - ) - for cf_type in Cf_type do - ( - key2 = cf_type as string - if getUserProp obj key2 != undefined do - setUserProp obj key2 0 - ) -) -) -on btn_tag pressed do tagObjects() -on btn_remTag pressed do removeTags() -)--rollout -createDialog TagSelectedObjects -)--globals \ No newline at end of file diff --git a/pandatool/src/text-stats/CMakeLists.txt b/pandatool/src/text-stats/CMakeLists.txt index 155b9013f31..a2c976d2f04 100644 --- a/pandatool/src/text-stats/CMakeLists.txt +++ b/pandatool/src/text-stats/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT HAVE_NET) return() endif() diff --git a/pandatool/src/vrmlprogs/CMakeLists.txt b/pandatool/src/vrmlprogs/CMakeLists.txt index 82a5e78bd3d..9f92833cd18 100644 --- a/pandatool/src/vrmlprogs/CMakeLists.txt +++ b/pandatool/src/vrmlprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(vrml-trans vrmlTrans.cxx vrmlTrans.h) target_link_libraries(vrml-trans p3progbase p3vrml) install(TARGETS vrml-trans EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/pandatool/src/win-stats/CMakeLists.txt b/pandatool/src/win-stats/CMakeLists.txt index 4e5d607948a..8c5a0a0f5cc 100644 --- a/pandatool/src/win-stats/CMakeLists.txt +++ b/pandatool/src/win-stats/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + if(NOT WIN32 OR NOT HAVE_NET) return() endif() diff --git a/pandatool/src/win-stats/winStatsFlameGraph.cxx b/pandatool/src/win-stats/winStatsFlameGraph.cxx index 3b1f991dba0..9c4d2f67ee7 100644 --- a/pandatool/src/win-stats/winStatsFlameGraph.cxx +++ b/pandatool/src/win-stats/winStatsFlameGraph.cxx @@ -29,9 +29,9 @@ const char * const WinStatsFlameGraph::_window_class_name = "flame"; */ WinStatsFlameGraph:: WinStatsFlameGraph(WinStatsMonitor *monitor, int thread_index, - int collector_index) : + int collector_index, int frame_number) : PStatFlameGraph(monitor, - thread_index, collector_index, + thread_index, collector_index, frame_number, monitor->get_pixel_scale() * default_flame_graph_width / 4, monitor->get_pixel_scale() * default_flame_graph_height / 4), WinStatsGraph(monitor) @@ -127,7 +127,21 @@ set_time_units(int unit_mask) { */ void WinStatsFlameGraph:: on_click_label(int collector_index) { - set_collector_index(collector_index); + if (collector_index != get_collector_index()) { + if (collector_index == -1) { + clear_history(); + set_collector_index(-1); + } else { + push_collector_index(collector_index); + } + + if (is_title_unknown()) { + std::string window_title = get_title_text(); + if (!is_title_unknown()) { + SetWindowText(_window, window_title.c_str()); + } + } + } } /** @@ -159,22 +173,6 @@ on_leave_label(int collector_index) { } } -/** - * Changes the collector represented by this flame graph. This may force a - * redraw. - */ -void WinStatsFlameGraph:: -set_collector_index(int collector_index) { - PStatFlameGraph::set_collector_index(collector_index); - - if (is_title_unknown()) { - std::string window_title = get_title_text(); - if (!is_title_unknown()) { - SetWindowText(_window, window_title.c_str()); - } - } -} - /** * Calls update_guide_bars with parameters suitable to this kind of graph. */ @@ -349,6 +347,7 @@ LONG WinStatsFlameGraph:: window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_LBUTTONDOWN: + SetFocus(_window); if (_potential_drag_mode == DM_new_guide_bar) { set_drag_mode(DM_new_guide_bar); SetCapture(_graph_window); @@ -372,7 +371,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { break; case 101: - set_collector_index(_popup_index); + on_click_label(_popup_index); return 0; case 102: @@ -393,6 +392,51 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } break; + case WM_KEYDOWN: + { + bool changed = false; + switch (wparam) { + case VK_LEFT: + changed = prev_frame(); + break; + case VK_RIGHT: + changed = next_frame(); + break; + case VK_HOME: + changed = first_frame(); + break; + case VK_END: + changed = last_frame(); + break; + } + if (changed) { + std::string window_title = get_title_text(); + SetWindowText(_window, window_title.c_str()); + return 0; + } + } + break; + + case WM_SYSKEYDOWN: + if (((lparam >> 16) & KF_ALTDOWN) != 0 && wparam == VK_LEFT) { + if (pop_collector_index()) { + std::string window_title = get_title_text(); + SetWindowText(_window, window_title.c_str()); + } + return 0; + } + break; + + case WM_APPCOMMAND: + if (GET_APPCOMMAND_LPARAM(lparam) == APPCOMMAND_BROWSER_BACKWARD) { + if (pop_collector_index()) { + std::string window_title = get_title_text(); + SetWindowText(_window, window_title.c_str()); + } + return TRUE; + } + break; + default: break; } @@ -407,6 +451,7 @@ LONG WinStatsFlameGraph:: graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch (msg) { case WM_LBUTTONDOWN: + SetFocus(_window); if (_potential_drag_mode == DM_guide_bar && _drag_guide_bar >= 0) { set_drag_mode(DM_guide_bar); int16_t x = LOWORD(lparam); @@ -479,7 +524,7 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // that collector. int16_t x = LOWORD(lparam); int16_t y = HIWORD(lparam); - set_collector_index(get_bar_collector(pixel_to_depth(y), x)); + on_click_label(get_bar_collector(pixel_to_depth(y), x)); return 0; } break; @@ -518,6 +563,19 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } break; + case WM_MOUSEHWHEEL: + { + int delta = GET_WHEEL_DELTA_WPARAM(wparam); + if (delta != 0) { + if (delta > 0 ? next_frame() : prev_frame()) { + std::string window_title = get_title_text(); + SetWindowText(_window, window_title.c_str()); + } + } + return 0; + } + break; + default: break; } @@ -760,6 +818,8 @@ create_window() { // Ensure that the window is on top of the stack. SetWindowPos(_window, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + + SetFocus(_window); } /** diff --git a/pandatool/src/win-stats/winStatsFlameGraph.h b/pandatool/src/win-stats/winStatsFlameGraph.h index 950f046b17f..6edae514ce7 100644 --- a/pandatool/src/win-stats/winStatsFlameGraph.h +++ b/pandatool/src/win-stats/winStatsFlameGraph.h @@ -28,7 +28,7 @@ class WinStatsLabel; class WinStatsFlameGraph : public PStatFlameGraph, public WinStatsGraph { public: WinStatsFlameGraph(WinStatsMonitor *monitor, int thread_index, - int collector_index=-1); + int collector_index=-1, int frame_number=-1); virtual ~WinStatsFlameGraph(); virtual void new_data(int thread_index, int frame_number); @@ -40,8 +40,6 @@ class WinStatsFlameGraph : public PStatFlameGraph, public WinStatsGraph { virtual void on_enter_label(int collector_index); virtual void on_leave_label(int collector_index); - void set_collector_index(int collector_index); - protected: virtual void normal_guide_bars(); diff --git a/pandatool/src/win-stats/winStatsGraph.cxx b/pandatool/src/win-stats/winStatsGraph.cxx index a363a91805e..d8d4118717b 100644 --- a/pandatool/src/win-stats/winStatsGraph.cxx +++ b/pandatool/src/win-stats/winStatsGraph.cxx @@ -413,6 +413,13 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { close(); break; + case WM_APPCOMMAND: + if (GET_APPCOMMAND_LPARAM(lparam) == APPCOMMAND_CLOSE) { + close(); + return TRUE; + } + break; + case WM_GETMINMAXINFO: { WINDOWINFO winfo; diff --git a/pandatool/src/win-stats/winStatsMonitor.cxx b/pandatool/src/win-stats/winStatsMonitor.cxx index 18623f5c664..410d638884e 100644 --- a/pandatool/src/win-stats/winStatsMonitor.cxx +++ b/pandatool/src/win-stats/winStatsMonitor.cxx @@ -332,8 +332,8 @@ open_strip_chart(int thread_index, int collector_index, bool show_level) { * Opens a new flame graph showing the indicated data. */ PStatGraph *WinStatsMonitor:: -open_flame_graph(int thread_index, int collector_index) { - WinStatsFlameGraph *graph = new WinStatsFlameGraph(this, thread_index, collector_index); +open_flame_graph(int thread_index, int collector_index, int frame_number) { + WinStatsFlameGraph *graph = new WinStatsFlameGraph(this, thread_index, collector_index, frame_number); add_graph(graph); return graph; } diff --git a/pandatool/src/win-stats/winStatsMonitor.h b/pandatool/src/win-stats/winStatsMonitor.h index 34338dc1a06..1fed3f9a9fa 100644 --- a/pandatool/src/win-stats/winStatsMonitor.h +++ b/pandatool/src/win-stats/winStatsMonitor.h @@ -84,7 +84,7 @@ class WinStatsMonitor : public PStatMonitor { PStatGraph *open_timeline(); PStatGraph *open_strip_chart(int thread_index, int collector_index, bool show_level); - PStatGraph *open_flame_graph(int thread_index, int collector_index = -1); + PStatGraph *open_flame_graph(int thread_index, int collector_index = -1, int frame_number = -1); PStatGraph *open_piano_roll(int thread_index); void choose_collector_color(int collector_index); diff --git a/pandatool/src/win-stats/winStatsServer.cxx b/pandatool/src/win-stats/winStatsServer.cxx index 90faef49afe..dd77cfbf0dd 100644 --- a/pandatool/src/win-stats/winStatsServer.cxx +++ b/pandatool/src/win-stats/winStatsServer.cxx @@ -858,6 +858,18 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } break; + case WM_APPCOMMAND: + switch (GET_APPCOMMAND_LPARAM(lparam)) { + case APPCOMMAND_OPEN: + open_session(); + return TRUE; + + case APPCOMMAND_SAVE: + save_session(); + return TRUE; + } + break; + case WM_COMMAND: if (HIWORD(wparam) <= 1) { int menu_id = LOWORD(wparam); diff --git a/pandatool/src/win-stats/winStatsTimeline.cxx b/pandatool/src/win-stats/winStatsTimeline.cxx index 6a534152532..a9c3f6688ac 100644 --- a/pandatool/src/win-stats/winStatsTimeline.cxx +++ b/pandatool/src/win-stats/winStatsTimeline.cxx @@ -463,7 +463,7 @@ graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { return 0; case 103: - WinStatsGraph::_monitor->open_flame_graph(_popup_bar._thread_index, _popup_bar._collector_index); + WinStatsGraph::_monitor->open_flame_graph(_popup_bar._thread_index, _popup_bar._collector_index, _popup_bar._frame_number); return 0; case 104: diff --git a/pandatool/src/xfileprogs/CMakeLists.txt b/pandatool/src/xfileprogs/CMakeLists.txt index 29562db00d1..9d3acc8959a 100644 --- a/pandatool/src/xfileprogs/CMakeLists.txt +++ b/pandatool/src/xfileprogs/CMakeLists.txt @@ -1,3 +1,7 @@ +if(NOT BUILD_TOOLS) + return() +endif() + add_executable(x-trans xFileTrans.cxx xFileTrans.h) target_link_libraries(x-trans p3progbase p3xfile) install(TARGETS x-trans EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/samples/procedural-cube/main.py b/samples/procedural-cube/main.py index 2f21cd9a0f7..266afc4205f 100755 --- a/samples/procedural-cube/main.py +++ b/samples/procedural-cube/main.py @@ -17,7 +17,6 @@ from panda3d.core import Geom, GeomTriangles, GeomVertexWriter from panda3d.core import Texture, GeomNode from panda3d.core import PerspectiveLens -from panda3d.core import CardMaker from panda3d.core import Light, Spotlight from panda3d.core import TextNode from panda3d.core import LVector3 diff --git a/setup.cfg b/setup.cfg index f67637e357a..c6e478a40e6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -19,6 +19,7 @@ classifiers = Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 + Programming Language :: Python :: 3.13 Programming Language :: Python :: Implementation :: CPython Topic :: Games/Entertainment Topic :: Multimedia diff --git a/tests/collide/test_collision_node.py b/tests/collide/test_collision_node.py new file mode 100644 index 00000000000..20197e956fe --- /dev/null +++ b/tests/collide/test_collision_node.py @@ -0,0 +1,46 @@ +from panda3d.core import * +import sys + + +class CustomObject: + pass + + +def test_collision_node_owner(): + owner = CustomObject() + initial_rc = sys.getrefcount(owner) + + node = CollisionNode("node") + assert node.owner is None + + node.owner = owner + assert sys.getrefcount(owner) == initial_rc + assert node.owner is owner + + node.owner = owner + assert sys.getrefcount(owner) == initial_rc + assert node.owner is owner + + node.owner = None + assert sys.getrefcount(owner) == initial_rc + assert node.owner is None + + del node + assert sys.getrefcount(owner) == initial_rc + + # Assign owner and then delete node + node = CollisionNode("node") + assert sys.getrefcount(owner) == initial_rc + node.owner = owner + assert sys.getrefcount(owner) == initial_rc + del node + assert sys.getrefcount(owner) == initial_rc + + # Delete owner and see what happens to the node + node = CollisionNode("node") + assert sys.getrefcount(owner) == initial_rc + node.owner = owner + assert sys.getrefcount(owner) == initial_rc + del owner + assert node.owner is None + diff --git a/tests/display/test_depth_buffer.py b/tests/display/test_depth_buffer.py index cdbaffd370f..c33ddbb6f13 100644 --- a/tests/display/test_depth_buffer.py +++ b/tests/display/test_depth_buffer.py @@ -198,12 +198,12 @@ def test_depth_bias(depth_region): # With slope-scaled depth bias (our quad has no slope) state = core.RenderState.make(core.DepthBiasAttrib.make(10, 0)) z = render_depth_pixel(depth_region, 5, near=1, far=10, state=state) - assert z == z_ref + assert z == pytest.approx(z_ref) # Same, but negative state = core.RenderState.make(core.DepthBiasAttrib.make(-10, 0)) z = render_depth_pixel(depth_region, 5, near=1, far=10, state=state) - assert z == z_ref + assert z == pytest.approx(z_ref) def test_depth_offset(depth_region): diff --git a/tests/display/test_glsl_shader.py b/tests/display/test_glsl_shader.py index 9e17a7bdc91..a49c9a04686 100644 --- a/tests/display/test_glsl_shader.py +++ b/tests/display/test_glsl_shader.py @@ -42,7 +42,7 @@ """ -def run_glsl_test(gsg, body, preamble="", inputs={}, version=150, exts=set()): +def run_glsl_test(gsg, body, preamble="", inputs={}, version=150, exts=set(), state=None): """ Runs a GLSL test on the given GSG. The given body is executed in the main function and should call assert(). The preamble should contain all of the shader inputs. """ @@ -84,10 +84,15 @@ def run_glsl_test(gsg, body, preamble="", inputs={}, version=150, exts=set()): attrib = attrib.set_shader_input(name, value) attrib = attrib.set_shader_input('_triggered', result) + if not state: + state = core.RenderState.make(attrib) + else: + state = state.set_attrib(attrib) + # Run the compute shader. engine = core.GraphicsEngine.get_global_ptr() try: - engine.dispatch_compute((1, 1, 1), attrib, gsg) + engine.dispatch_compute((1, 1, 1), state, gsg) except AssertionError as exc: assert False, "Error executing compute shader:\n" + code @@ -294,7 +299,7 @@ def test_glsl_uimage(gsg): def test_glsl_ssbo(gsg): - from struct import pack + from struct import pack, unpack num1 = pack(' 0.499); + assert(p3d_LightSource[0].spotCosCutoff < 0.501); + assert(p3d_LightSource[0].spotCutoff == 60); + assert(p3d_LightSource[0].shadowViewMatrix[0][0] > 0.2886); + assert(p3d_LightSource[0].shadowViewMatrix[0][0] < 0.2887); + assert(p3d_LightSource[0].shadowViewMatrix[0][1] == 0); + assert(p3d_LightSource[0].shadowViewMatrix[0][2] == 0); + assert(p3d_LightSource[0].shadowViewMatrix[0][3] == 0); + assert(p3d_LightSource[0].shadowViewMatrix[1][0] == 0); + assert(p3d_LightSource[0].shadowViewMatrix[1][1] > 0.2886); + assert(p3d_LightSource[0].shadowViewMatrix[1][1] < 0.2887); + assert(p3d_LightSource[0].shadowViewMatrix[1][2] == 0); + assert(p3d_LightSource[0].shadowViewMatrix[1][3] == 0); + assert(p3d_LightSource[0].shadowViewMatrix[2][0] == -0.5); + assert(p3d_LightSource[0].shadowViewMatrix[2][1] == -0.5); + assert(p3d_LightSource[0].shadowViewMatrix[2][2] > -1.00002); + assert(p3d_LightSource[0].shadowViewMatrix[2][2] < -1.0); + assert(p3d_LightSource[0].shadowViewMatrix[2][3] == -1); + assert(p3d_LightSource[0].shadowViewMatrix[3][0] > -16.2736); + assert(p3d_LightSource[0].shadowViewMatrix[3][0] < -16.2734); + assert(p3d_LightSource[0].shadowViewMatrix[3][1] > -16.8510); + assert(p3d_LightSource[0].shadowViewMatrix[3][1] < -16.8508); + assert(p3d_LightSource[0].shadowViewMatrix[3][2] > -22.0003); + assert(p3d_LightSource[0].shadowViewMatrix[3][2] < -22.0001); + assert(p3d_LightSource[0].shadowViewMatrix[3][3] > -21.0001); + assert(p3d_LightSource[0].shadowViewMatrix[3][3] < -20.9999); + assert(p3d_LightSource[1].color == vec4(9, 10, 11, 12)); + assert(p3d_LightSource[1].specular == vec4(13, 14, 15, 16)); + assert(p3d_LightSource[1].diffuse == vec4(9, 10, 11, 12)); + assert(p3d_LightSource[1].ambient == vec4(0, 0, 0, 1)); + assert(p3d_LightSource[1].position == vec4(-17, -18, -19, 0)); + assert(p3d_LightSource[1].attenuation == vec3(1, 0, 0)); + assert(p3d_LightSource[1].constantAttenuation == 1); + assert(p3d_LightSource[1].linearAttenuation == 0); + assert(p3d_LightSource[1].quadraticAttenuation == 0); + assert(p3d_LightSource[1].spotExponent == 0); + assert(p3d_LightSource[1].spotCosCutoff == -1); + assert(p3d_LightSource[2].color == vec4(0, 0, 0, 1)); + assert(p3d_LightSource[2].specular == vec4(0, 0, 0, 1)); + assert(p3d_LightSource[2].diffuse == vec4(0, 0, 0, 1)); + assert(p3d_LightSource[2].ambient == vec4(0, 0, 0, 1)); + assert(p3d_LightSource[2].position == vec4(0, 0, 1, 0)); + assert(p3d_LightSource[2].attenuation == vec3(1, 0, 0)); + assert(p3d_LightSource[2].constantAttenuation == 1); + assert(p3d_LightSource[2].linearAttenuation == 0); + assert(p3d_LightSource[2].quadraticAttenuation == 0); + assert(p3d_LightSource[2].spotExponent == 0); + assert(p3d_LightSource[2].spotCosCutoff == -1); + """ + + node = core.NodePath("state") + spot_path = node.attach_new_node(spot) + spot_path.set_pos(20, 21, 22) + node.set_light(spot_path) + + dire_path = node.attach_new_node(dire) + node.set_light(dire_path) + + run_glsl_test(gsg, code, preamble, state=node.get_state()) + + +def test_glsl_state_material(gsg): + mat = core.Material("mat") + mat.ambient = (1, 2, 3, 4) + mat.diffuse = (5, 6, 7, 8) + mat.emission = (9, 10, 11, 12) + mat.specular = (13, 14, 15, 0) + mat.shininess = 16 + mat.metallic = 0.5 + mat.refractive_index = 21 + + preamble = """ + struct p3d_MaterialParameters { + vec4 ambient; + vec4 diffuse; + vec4 emission; + vec3 specular; + float shininess; + float metallic; + float refractiveIndex; + }; + uniform p3d_MaterialParameters p3d_Material; + """ + code = """ + assert(p3d_Material.ambient == vec4(1, 2, 3, 4)); + assert(p3d_Material.diffuse == vec4(5, 6, 7, 8)); + assert(p3d_Material.emission == vec4(9, 10, 11, 12)); + assert(p3d_Material.specular == vec3(13, 14, 15)); + assert(p3d_Material.shininess == 16); + assert(p3d_Material.metallic == 0.5); + assert(p3d_Material.refractiveIndex == 21); + """ + + node = core.NodePath("state") + node.set_material(mat) + + run_glsl_test(gsg, code, preamble, state=node.get_state()) + + +def test_glsl_state_material_pbr(gsg): + mat = core.Material("mat") + mat.base_color = (1, 2, 3, 4) + mat.emission = (9, 10, 11, 12) + mat.roughness = 16 + mat.metallic = 0.5 + mat.refractive_index = 21 + + preamble = """ + struct p3d_MaterialParameters { + vec4 baseColor; + vec4 emission; + float metallic; + float refractiveIndex; + float roughness; + }; + uniform p3d_MaterialParameters p3d_Material; + """ + code = """ + assert(p3d_Material.baseColor == vec4(1, 2, 3, 4)); + assert(p3d_Material.emission == vec4(9, 10, 11, 12)); + assert(p3d_Material.roughness == 16); + assert(p3d_Material.metallic == 0.5); + assert(p3d_Material.refractiveIndex == 21); + """ + + node = core.NodePath("state") + node.set_material(mat) + + run_glsl_test(gsg, code, preamble, state=node.get_state()) + + +def test_glsl_state_fog(gsg): + fog = core.Fog("fog") + fog.color = (1, 2, 3, 4) + fog.exp_density = 0.5 + fog.set_linear_range(6, 10) + + preamble = """ + struct p3d_FogParameters { + vec4 color; + float density; + float start; + float end; + float scale; + }; + uniform p3d_FogParameters p3d_Fog; + """ + code = """ + assert(p3d_Fog.color == vec4(1, 2, 3, 4)); + assert(p3d_Fog.density == 0.5); + assert(p3d_Fog.start == 6); + assert(p3d_Fog.end == 10); + assert(p3d_Fog.scale == 0.25); + """ + + node = core.NodePath("state") + node.set_fog(fog) + + run_glsl_test(gsg, code, preamble, state=node.get_state()) + + +def test_glsl_frame_number(gsg): + clock = core.ClockObject.get_global_clock() + old_frame_count = clock.get_frame_count() + try: + clock.set_frame_count(123) + + preamble = """ + uniform int osg_FrameNumber; + """ + code = """ + assert(osg_FrameNumber == 123); + """ + + run_glsl_test(gsg, code, preamble) + finally: + clock.set_frame_count(old_frame_count) + + def test_glsl_write_extract_image_buffer(gsg): # Tests that we can write to a buffer texture on the GPU, and then extract # the data on the CPU. We test two textures since there was in the past a diff --git a/tests/dist/test_FreezeTool.py b/tests/dist/test_FreezeTool.py index e0eb82b7a56..d7b80b368cd 100644 --- a/tests/dist/test_FreezeTool.py +++ b/tests/dist/test_FreezeTool.py @@ -103,5 +103,13 @@ def test_Freezer_generateRuntimeFromStub(tmp_path, use_console): # Not supported; see #1348 return - output = subprocess.check_output(target) + env = None + if sys.platform == "win32": + env = dict(os.environ) + if not os.environ.get('PATH'): + env['PATH'] = bin_dir + else: + env['PATH'] = bin_dir + os.pathsep + os.environ['PATH'] + + output = subprocess.check_output(target, env=env) assert output.replace(b'\r\n', b'\n') == b'Module imported\nHello world\n' diff --git a/tests/event/test_event.py b/tests/event/test_event.py index 947ed093a30..dbf98ba58c9 100644 --- a/tests/event/test_event.py +++ b/tests/event/test_event.py @@ -31,8 +31,7 @@ class PythonEvent(Event): with gc_disabled(): event = PythonEvent('test_event_subclass_gc1') - assert len(gc.get_objects()) == 1 - assert gc.get_objects()[0] == event + assert event in gc.get_objects() event = None diff --git a/tests/event/test_futures.py b/tests/event/test_futures.py index fb5c1626cf9..c1bf870c1c0 100644 --- a/tests/event/test_futures.py +++ b/tests/event/test_futures.py @@ -1,9 +1,9 @@ from panda3d import core +from asyncio.exceptions import TimeoutError, CancelledError import pytest import time import sys -from asyncio.exceptions import TimeoutError, CancelledError - +import weakref class MockFuture: _asyncio_future_blocking = False @@ -31,7 +31,6 @@ def result(self): return self._result - def test_future_cancelled(): fut = core.AsyncFuture() @@ -681,3 +680,57 @@ def test_event_future_cancel2(): assert not fut2.done() assert not fut2.cancelled() +def test_task_manager_cleanup_non_panda_future(): + future = MockFuture() + # Create a weakref so we can verify the future was cleaned up. + future_ref = weakref.ref(future) + + async def coro_main(): + return await future + + task = core.PythonTask(coro_main(), 'coro_main') + task_mgr = core.AsyncTaskManager.get_global_ptr() + task_mgr.add(task) + # Poll the task_mgr so the PythonTask starts polling on future.done() + task_mgr.poll() + future._result = 'Done123' + future._state = 'DONE' + # Drop our reference to the future, `task` should hold the only reference + del future + # Recognize the future has completed + task_mgr.poll() + + # Verify the task was completed. + assert task.result() == 'Done123' + del coro_main # this should break the last strong reference to the mock future + + assert future_ref() is None, "MockFuture was not cleaned up!" + +def test_await_future_result_cleanup(): + # Create a simple future and an object for it to return + future = core.AsyncFuture() + + class TestObject: + pass + + test_result = TestObject() + future_result_ref = weakref.ref(test_result) + + # Setup an async environment and dispatch it to a task chain to await the future + async def coro_main(): + nonlocal test_result + future.set_result(test_result) + del test_result + await future + + task = core.PythonTask(coro_main(), 'coro_main') + task_mgr = core.AsyncTaskManager.get_global_ptr() + task_mgr.add(task) + # Poll the task_mgr so the PythonTask starts polling on future.done() + task_mgr.poll() + # Break all possible references to the future object + del task + del coro_main + del future # this should break the last strong reference to the future + + assert future_result_ref() is None, "TestObject was not cleaned up!" diff --git a/tests/event/test_pythontask.py b/tests/event/test_pythontask.py index 584788494fd..c793067f8b3 100644 --- a/tests/event/test_pythontask.py +++ b/tests/event/test_pythontask.py @@ -1,4 +1,4 @@ -from panda3d.core import PythonTask +from panda3d.core import AsyncTaskManager, PythonTask from contextlib import contextmanager import pytest import types @@ -115,3 +115,39 @@ def test_pythontask_cycle(): break else: pytest.fail('not found in garbage') + +def test_task_persistent_wrapper(): + task_mgr = AsyncTaskManager.get_global_ptr() + task_chain = task_mgr.make_task_chain("test_task_persistent_wrapper") + + # Create a subclass of PythonTask + class PythonTaskSubclassTest(PythonTask): + pass + + def task_main(task): + # Set our result to be the input task we got into this function + task.set_result(task) + # Verify we got the subclass + assert isinstance(task, PythonTaskSubclassTest) + return task.done + + done_callback_reached = False + + def done_callback(task): + # Verify we got the subclass + assert isinstance(task, PythonTaskSubclassTest) + nonlocal done_callback_reached + done_callback_reached = True + + task = PythonTaskSubclassTest(task_main) + task.set_task_chain(task_chain.name) + task.set_upon_death(done_callback) + task_mgr.add(task) + task_chain.wait_for_tasks() + + assert task.done() + assert not task.cancelled() + # Verify the task passed into the function is the same task we created + assert task.result() is task + # Verify the done callback worked and was tested + assert done_callback_reached diff --git a/tests/gui/test_DirectGui.py b/tests/gui/test_DirectGui.py index f72419a5c3e..50b6122fda8 100644 --- a/tests/gui/test_DirectGui.py +++ b/tests/gui/test_DirectGui.py @@ -8,7 +8,7 @@ def test_DirectGui(base): # EXAMPLE CODE # Load a model - smiley = base.loader.loadModel('models/misc/smiley') + smiley = base.loader.loadModel('models/misc/smiley.egg') # Here we specify the button's command def dummyCmd(index): diff --git a/tests/interrogate/test_property.py b/tests/interrogate/test_property.py index 12da75f4578..7a708b2ab63 100644 --- a/tests/interrogate/test_property.py +++ b/tests/interrogate/test_property.py @@ -609,3 +609,9 @@ def test_map_property_items(): assert isinstance(prop.items(), collections_abc.MappingView) assert frozenset(prop.items()) == frozenset((('key', 'value'), ('key2', 'value2'))) + + +def test_static_property(): + v1 = core.PandaSystem.version_string + v2 = core.PandaSystem.get_version_string() + assert v1 == v2 diff --git a/tests/linmath/test_compose_matrix.py b/tests/linmath/test_compose_matrix.py new file mode 100644 index 00000000000..bd52875a029 --- /dev/null +++ b/tests/linmath/test_compose_matrix.py @@ -0,0 +1,43 @@ +from panda3d import core +import pytest + + +@pytest.mark.parametrize("coordsys", (core.CS_zup_right, core.CS_yup_right, core.CS_zup_left, core.CS_yup_left)) +def test_compose_matrix(coordsys): + scale = core.LVecBase3(1.2, 0.5, 2) + hpr = core.LVecBase3(45, -90, 12.5) + shear = core.LVecBase3(0, 0, 0) + + mat = core.LMatrix3() + core.compose_matrix(mat, scale, shear, hpr, coordsys) + + new_scale = core.LVecBase3() + new_hpr = core.LVecBase3() + new_shear = core.LVecBase3() + core.decompose_matrix(mat, new_scale, new_shear, new_hpr, coordsys) + + assert new_scale.almost_equal(scale) + assert new_shear.almost_equal(shear) + + quat = core.LQuaternion() + quat.set_hpr(hpr, coordsys) + new_quat = core.LQuaternion() + new_quat.set_hpr(new_hpr, coordsys) + assert quat.is_same_direction(new_quat) + + +@pytest.mark.parametrize("coordsys", (core.CS_zup_right, core.CS_yup_right, core.CS_zup_left, core.CS_yup_left)) +def test_compose_matrix2(coordsys): + mat = core.LMatrix3(1, 0, 0, 0, 0, -1, 0, 1, 0) + + new_scale = core.LVecBase3() + new_hpr = core.LVecBase3() + new_shear = core.LVecBase3() + core.decompose_matrix(mat, new_scale, new_shear, new_hpr, coordsys) + + assert new_scale.almost_equal(core.LVecBase3(1, 1, 1)) + if coordsys in (core.CS_zup_left, core.CS_yup_left): + assert new_hpr.almost_equal(core.LVecBase3(0, 90, 0)) + else: + assert new_hpr.almost_equal(core.LVecBase3(0, -90, 0)) + assert new_shear.almost_equal(core.LVecBase3(0, 0, 0)) diff --git a/tests/linmath/test_lvector2.py b/tests/linmath/test_lvector2.py index 84bda154447..542ba2fe83d 100644 --- a/tests/linmath/test_lvector2.py +++ b/tests/linmath/test_lvector2.py @@ -145,6 +145,17 @@ def test_vec2_floordiv(type): assert v.x == i // -j +def test_vec2_repr(): + assert repr(Vec2F(0.1, 0.2)) == "LVector2f(0.1, 0.2)" + assert repr(Vec2F(0.3, 0.4)) == "LVector2f(0.3, 0.4)" + assert repr(Vec2F(-0.9999999403953552, 1.00000001)) == "LVector2f(-0.99999994, 1)" + assert repr(Vec2F(0.00000001, 0.0)) == "LVector2f(1e-8, 0)" + assert repr(Vec2D(0.1, 0.2)) == "LVector2d(0.1, 0.2)" + assert repr(Vec2D(0.3, 0.4)) == "LVector2d(0.3, 0.4)" + assert repr(Vec2D(-0.9999999403953552, 1.00000001)) == "LVector2d(-0.9999999403953552, 1.00000001)" + assert repr(Vec2D(0.00000001, 0.0)) == "LVector2d(1e-8, 0)" + + def test_vec2_buffer(): v = Vec2(1.5, -10.0) m = memoryview(v) diff --git a/tests/linmath/test_lvector3.py b/tests/linmath/test_lvector3.py index e12a1650f0f..ee4828d6872 100644 --- a/tests/linmath/test_lvector3.py +++ b/tests/linmath/test_lvector3.py @@ -130,6 +130,19 @@ def test_vec3_floordiv(type): assert v.x == i // -j +def test_vec3_repr(): + assert repr(Vec3F(0.1, 0.2, 0.3)) == "LVector3f(0.1, 0.2, 0.3)" + assert repr(Vec3F(-0.9999999403953552, 1.00000001, 1)) == "LVector3f(-0.99999994, 1, 1)" + assert repr(Vec3F(-9.451235e29, 9.451234e-19, 1e-11)) == "LVector3f(-9.451235e29, 9.451234e-19, 1e-11)" + assert repr(Vec3F(0.001, 0.0001, 0.00001)) == "LVector3f(0.001, 0.0001, 0.00001)" + assert repr(Vec3F(-0.001, -0.0001, -0.00001)) == "LVector3f(-0.001, -0.0001, -0.00001)" + assert repr(Vec3D(0.1, 0.2, 0.3)) == "LVector3d(0.1, 0.2, 0.3)" + assert repr(Vec3D(-0.9999999403953552, 1.00000001, 1)) == "LVector3d(-0.9999999403953552, 1.00000001, 1)" + assert repr(Vec3D(-9.451235e29, 9.451234e-19, 1e-11)) == "LVector3d(-9.451235e29, 9.451234e-19, 1e-11)" + assert repr(Vec3D(0.001, 0.0001, 0.00001)) == "LVector3d(0.001, 0.0001, 0.00001)" + assert repr(Vec3D(-0.001, -0.0001, -0.00001)) == "LVector3d(-0.001, -0.0001, -0.00001)" + + def test_vec3_buffer(): v = Vec3(0.5, 2.0, -10.0) m = memoryview(v) diff --git a/tests/linmath/test_lvector4.py b/tests/linmath/test_lvector4.py index 060953fbc89..f061191fb57 100644 --- a/tests/linmath/test_lvector4.py +++ b/tests/linmath/test_lvector4.py @@ -146,6 +146,13 @@ def test_vec4_floordiv(type): assert v.x == i // -j +def test_vec4_repr(): + assert repr(Vec4F(0.1, 0.2, 0.3, 0.4)) == "LVector4f(0.1, 0.2, 0.3, 0.4)" + assert repr(Vec4F(-0.9999999403953552, 1.000001, 1e-8, 0.0)) == "LVector4f(-0.99999994, 1.000001, 1e-8, 0)" + assert repr(Vec4D(0.1, 0.2, 0.3, 0.4)) == "LVector4d(0.1, 0.2, 0.3, 0.4)" + assert repr(Vec4D(-0.9999999403953552, 1.00000001, 1e-8, 0.0)) == "LVector4d(-0.9999999403953552, 1.00000001, 1e-8, 0)" + + def test_vec4_buffer(): v = Vec4(0, 0.5, 2.0, -4.0) m = memoryview(v) diff --git a/tests/main.c b/tests/main.c new file mode 100644 index 00000000000..8fce2d6f921 --- /dev/null +++ b/tests/main.c @@ -0,0 +1,122 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file main.c + * @author rdb + * @date 2024-11-03 + */ + +/** + * This script embeds the Python interpreter and runs the unit testing suite. + * It is designed for use with a statically built Panda3D, where the Panda3D + * modules are linked directly into the interpreter. + */ + +#include + +#include "pandabase.h" + +#ifdef LINK_ALL_STATIC +extern PyObject *PyInit_core(); + +#ifdef HAVE_DIRECT +extern PyObject *PyInit_direct(); +#endif + +#ifdef HAVE_PHYSICS +extern PyObject *PyInit_physics(); +#endif + +#ifdef HAVE_EGG +extern PyObject *PyInit_egg(); +extern EXPCL_PANDAEGG void init_libpandaegg(); +#endif + +#ifdef HAVE_BULLET +extern PyObject *PyInit_bullet(); +#endif + +extern EXPCL_PANDA_PNMIMAGETYPES void init_libpnmimagetypes(); +#endif // LINK_ALL_STATIC + + +int main(int argc, char **argv) { + PyStatus status; + PyConfig config; + PyConfig_InitPythonConfig(&config); + + PyConfig_SetBytesString(&config, &config.run_module, "pytest"); + config.parse_argv = 0; + + status = PyConfig_SetBytesArgv(&config, argc, argv); + if (PyStatus_Exception(status)) { + goto exception; + } + + status = Py_InitializeFromConfig(&config); + if (PyStatus_Exception(status)) { + goto exception; + } + PyConfig_Clear(&config); + +#ifdef LINK_ALL_STATIC +#ifdef HAVE_EGG + init_libpandaegg(); +#endif + + init_libpnmimagetypes(); + + { + PyObject *panda3d_module = PyImport_ImportModule("panda3d"); + PyObject *panda3d_dict = PyModule_GetDict(panda3d_module); + PyObject *sys_modules = PySys_GetObject("modules"); + + PyObject *core_module = PyInit_core(); + PyDict_SetItemString(panda3d_dict, "core", core_module); + PyDict_SetItemString(sys_modules, "panda3d.core", core_module); + +#ifdef HAVE_DIRECT + PyObject *direct_module = PyInit_direct(); + PyDict_SetItemString(panda3d_dict, "direct", direct_module); + PyDict_SetItemString(sys_modules, "panda3d.direct", direct_module); +#endif + +#ifdef HAVE_PHYSICS + PyObject *physics_module = PyInit_physics(); + PyDict_SetItemString(panda3d_dict, "physics", physics_module); + PyDict_SetItemString(sys_modules, "panda3d.physics", physics_module); +#endif + +#ifdef HAVE_EGG + PyObject *egg_module = PyInit_egg(); + PyDict_SetItemString(panda3d_dict, "egg", egg_module); + PyDict_SetItemString(sys_modules, "panda3d.egg", egg_module); +#endif + +#ifdef HAVE_BULLET + PyObject *bullet_module = PyInit_bullet(); + PyDict_SetItemString(panda3d_dict, "bullet", bullet_module); + PyDict_SetItemString(sys_modules, "panda3d.bullet", bullet_module); +#endif + } +#endif // LINK_ALL_STATIC + +#ifdef __EMSCRIPTEN__ + // Default fd capturing doesn't work on emscripten + PyRun_SimpleString("import sys; sys.argv.insert(1, '--capture=sys')"); +#endif + + return Py_RunMain(); + +exception: + PyConfig_Clear(&config); + if (PyStatus_IsExit(status)) { + return status.exitcode; + } + Py_ExitStatusException(status); +} diff --git a/tests/pgraph/test_nodepath.py b/tests/pgraph/test_nodepath.py index 9339394724c..f4265304295 100644 --- a/tests/pgraph/test_nodepath.py +++ b/tests/pgraph/test_nodepath.py @@ -106,7 +106,7 @@ def test_nodepath_transform_composition(): leg1 = node2.get_transform().compose(node3.get_transform()) leg2 = node1.get_transform().compose(node3.get_transform()) relative_transform = leg1.get_inverse().compose(leg2) - assert np1.get_transform(np2) == relative_transform + assert np1.get_transform(np2).compare_to(relative_transform, True) == 0 def test_nodepath_comparison(): @@ -312,3 +312,47 @@ def test_nodepath_replace_texture_none(): assert path2.get_texture() == tex1 path1.replace_texture(tex1, None) assert path2.get_texture() is None + + +def test_nodepath_set_collide_owner(): + from panda3d.core import NodePath, CollisionNode + + class CustomOwner: + pass + + owner1 = CustomOwner() + owner2 = CustomOwner() + owner3 = CustomOwner() + + root = NodePath("root") + model1 = root.attach_new_node("model1") + collider1 = model1.attach_new_node(CollisionNode("collider1")) + collider2 = model1.attach_new_node(CollisionNode("collider2")) + model2 = root.attach_new_node("model2") + collider3 = model2.attach_new_node(CollisionNode("collider3")) + + root.set_collide_owner(owner1) + assert collider1.node().owner is owner1 + assert collider2.node().owner is owner1 + assert collider3.node().owner is owner1 + + model1.set_collide_owner(None) + assert collider1.node().owner is None + assert collider2.node().owner is None + assert collider3.node().owner is owner1 + + collider2.set_collide_owner(owner2) + assert collider1.node().owner is None + assert collider2.node().owner is owner2 + assert collider3.node().owner is owner1 + + del owner1 + assert collider1.node().owner is None + assert collider2.node().owner is owner2 + assert collider3.node().owner is None + + root.set_collide_owner(owner3) + model2.set_collide_owner(owner2) + assert collider1.node().owner is owner3 + assert collider2.node().owner is owner3 + assert collider3.node().owner is owner2 diff --git a/tests/pgraph/test_pandanode.py b/tests/pgraph/test_pandanode.py index 9870b4d3c63..2b24168b1e5 100644 --- a/tests/pgraph/test_pandanode.py +++ b/tests/pgraph/test_pandanode.py @@ -144,8 +144,7 @@ class NodeSubclass(PandaNode): with gc_disabled(): node = NodeSubclass('test_node_subclass_gc1') - assert len(gc.get_objects()) == 1 - assert gc.get_objects()[0] == node + assert node in gc.get_objects() node = None diff --git a/tests/physics/test_fall.py b/tests/physics/test_fall.py index 99397072a85..1b261e86286 100644 --- a/tests/physics/test_fall.py +++ b/tests/physics/test_fall.py @@ -23,7 +23,7 @@ def setup(self): #self.setPos(avatarNodePath, Vec3(0)) #self.setHpr(avatarNodePath, Vec3(0)) - avatarNodePath = base.loader.loadModel("models/misc/smiley") + avatarNodePath = base.loader.loadModel("models/misc/smiley.egg") assert not avatarNodePath.isEmpty() # camLL = base.render.find("**/camLL") diff --git a/tests/physics/test_rotation.py b/tests/physics/test_rotation.py index ec24cf433bb..1260651cd22 100644 --- a/tests/physics/test_rotation.py +++ b/tests/physics/test_rotation.py @@ -24,7 +24,7 @@ def setup(self): #self.setPos(avatarNodePath, Vec3(0)) #self.setHpr(avatarNodePath, Vec3(0)) - avatarNodePath = base.loader.loadModel("models/misc/smiley") + avatarNodePath = base.loader.loadModel("models/misc/smiley.egg") assert not avatarNodePath.isEmpty() # camLL = base.render.find("**/camLL") diff --git a/tests/putil/test_sparsearray.py b/tests/putil/test_sparsearray.py index 9721ad495ac..adb7f2265c3 100644 --- a/tests/putil/test_sparsearray.py +++ b/tests/putil/test_sparsearray.py @@ -251,6 +251,35 @@ def test_sparse_array_nonzero(): assert sa +def test_sparse_array_lowest_bit(): + sa = core.SparseArray() + assert sa.get_lowest_off_bit() == 0 + assert sa.get_lowest_on_bit() == -1 + + sa.invert_in_place() + assert sa.get_lowest_off_bit() == -1 + assert sa.get_lowest_on_bit() == 0 + + sa = core.SparseArray() + sa.set_bit(0) + sa.set_bit(1) + assert sa.get_lowest_off_bit() == 2 + assert sa.get_lowest_on_bit() == 0 + + sa.invert_in_place() + assert sa.get_lowest_off_bit() == 0 + assert sa.get_lowest_on_bit() == 2 + + sa = core.SparseArray() + sa.set_bit(2) + assert sa.get_lowest_off_bit() == 0 + assert sa.get_lowest_on_bit() == 2 + + sa.invert_in_place() + assert sa.get_lowest_off_bit() == 2 + assert sa.get_lowest_on_bit() == 0 + + def test_sparse_array_getstate(): sa = core.SparseArray() assert sa.__getstate__() == () diff --git a/tests/showbase/test_Loader.py b/tests/showbase/test_Loader.py index dbbe78e8e88..db8812fd1fd 100644 --- a/tests/showbase/test_Loader.py +++ b/tests/showbase/test_Loader.py @@ -90,7 +90,7 @@ def load_file(path, options, record=None): """) (tmp_path / "fnargle.dist-info").mkdir() (tmp_path / "fnargle.dist-info" / "METADATA").write_text(""" -Metadata-Version: 2.0 +Metadata-Version: 2.1 Name: fnargle Version: 1.0.0 """) @@ -120,9 +120,10 @@ def load_file(path, options, record=None): sys.path = [str(tmp_path), platstdlib, stdlib] Loader._loadedPythonFileTypes = False + loader = Loader() - # base parameter is only used for audio - loader = Loader(None) + if not Loader._loadedPythonFileTypes: + Loader._loadPythonFileTypes() assert Loader._loadedPythonFileTypes # Should be registered, not yet loaded diff --git a/tests/stdpy/test_threading.py b/tests/stdpy/test_threading.py index a105ad20e1a..3a4363e8104 100644 --- a/tests/stdpy/test_threading.py +++ b/tests/stdpy/test_threading.py @@ -9,6 +9,7 @@ def test_threading_error(): threading.stack_size() +@pytest.mark.skipif(sys.platform == "emscripten", reason="No threading") def test_threading(): from collections import deque diff --git a/tests/stdpy/test_threading2.py b/tests/stdpy/test_threading2.py index f2a31dc1723..fd7560def91 100644 --- a/tests/stdpy/test_threading2.py +++ b/tests/stdpy/test_threading2.py @@ -1,8 +1,11 @@ +import sys from collections import deque from panda3d import core from direct.stdpy import threading2 +import pytest +@pytest.mark.skipif(sys.platform == "emscripten", reason="No threading") def test_threading2(): class BoundedQueue(threading2._Verbose): diff --git a/tests/test_imports.py b/tests/test_imports.py index c6295bc7d06..565ecca2b2c 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -18,7 +18,7 @@ def test_imports_panda3d(): if mod.startswith('panda3d.'): importlib.import_module(mod) - if panda3d.__spec__.origin != 'frozen': + if hasattr(panda3d, '__file__') and panda3d.__spec__.origin != 'frozen': dir = os.path.dirname(panda3d.__file__) # Iterate over the things in the panda3d package that look like modules. @@ -32,12 +32,18 @@ def test_imports_panda3d(): module = basename.split('.', 1)[0] ext = basename[len(module):] + if module == 'dtoolconfig' or module == 'interrogatedb': + continue + if ext in extensions: importlib.import_module('panda3d.%s' % (module)) def test_imports_panda3d_net(): from panda3d import core + if not hasattr(core, 'ConnectionWriter'): + pytest.skip("Build without HAVE_NET") + from panda3d import net assert core.ConnectionWriter == net.ConnectionWriter assert core.ConnectionWriter.__module__ == 'panda3d.net' @@ -265,6 +271,7 @@ def test_imports_direct_net(): def test_imports_tk(): + pytest.importorskip('tkinter') Pmw = pytest.importorskip('Pmw') import direct.showbase.TkGlobal diff --git a/tests/test_tools.py b/tests/test_tools.py index b6b187ebc29..c4ac081d6ab 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -5,6 +5,9 @@ import tempfile import panda3d +if sys.platform == "emscripten": + pytest.skip(allow_module_level=True) + try: panda3d_tools = pytest.importorskip("panda3d_tools") except: diff --git a/tests/tkpanels/test_ParticlePanel.py b/tests/tkpanels/test_ParticlePanel.py index e1498a4868d..d80c0eac2f9 100644 --- a/tests/tkpanels/test_ParticlePanel.py +++ b/tests/tkpanels/test_ParticlePanel.py @@ -1,4 +1,5 @@ import pytest +pytest.importorskip('tkinter') Pmw = pytest.importorskip('Pmw') from direct.tkpanels.ParticlePanel import ParticlePanel diff --git a/tests/tkpanels/test_Placer.py b/tests/tkpanels/test_Placer.py index 1cc146efeb9..353afdf5a84 100644 --- a/tests/tkpanels/test_Placer.py +++ b/tests/tkpanels/test_Placer.py @@ -1,4 +1,5 @@ import pytest +pytest.importorskip('tkinter') Pmw = pytest.importorskip('Pmw') from direct.showbase.ShowBase import ShowBase from direct.tkpanels.Placer import Placer diff --git a/tests/tkwidgets/test_AppShell.py b/tests/tkwidgets/test_AppShell.py index e87889d34b0..831407ed046 100644 --- a/tests/tkwidgets/test_AppShell.py +++ b/tests/tkwidgets/test_AppShell.py @@ -1,4 +1,5 @@ import pytest +pytest.importorskip('tkinter') pytest.importorskip('Pmw') from direct.tkwidgets import AppShell diff --git a/tests/tkwidgets/test_Dial.py b/tests/tkwidgets/test_Dial.py index eda8d0591ba..3f74e216d8e 100644 --- a/tests/tkwidgets/test_Dial.py +++ b/tests/tkwidgets/test_Dial.py @@ -1,5 +1,5 @@ -import tkinter as tk import pytest +tk = pytest.importorskip('tkinter') pytest.importorskip('Pmw') from direct.tkwidgets.Dial import Dial diff --git a/tests/tkwidgets/test_EntryScale.py b/tests/tkwidgets/test_EntryScale.py index f06fb036ed4..496376328d0 100644 --- a/tests/tkwidgets/test_EntryScale.py +++ b/tests/tkwidgets/test_EntryScale.py @@ -1,4 +1,5 @@ import pytest +pytest.importorskip('tkinter') pytest.importorskip('Pmw') from direct.tkwidgets.EntryScale import EntryScale, EntryScaleGroup diff --git a/tests/tkwidgets/test_Floater.py b/tests/tkwidgets/test_Floater.py index dfd470763fb..45a3b0ae7d5 100644 --- a/tests/tkwidgets/test_Floater.py +++ b/tests/tkwidgets/test_Floater.py @@ -1,4 +1,5 @@ import pytest +pytest.importorskip('tkinter') pytest.importorskip('Pmw') from direct.tkwidgets.Floater import Floater, FloaterGroup diff --git a/tests/tkwidgets/test_VectorWidgets.py b/tests/tkwidgets/test_VectorWidgets.py index fecad4cfa7d..892701a1492 100644 --- a/tests/tkwidgets/test_VectorWidgets.py +++ b/tests/tkwidgets/test_VectorWidgets.py @@ -1,4 +1,5 @@ import pytest +pytest.importorskip('tkinter') pytest.importorskip('Pmw') from direct.tkwidgets import VectorWidgets