diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 3e3e1df3e2a..7106275d02b 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -5,3 +5,8 @@ updates: directory: / schedule: interval: monthly + + - package-ecosystem: vcpkg + directory: /indra # The location of vcpkg.json + schedule: + interval: weekly diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7279c172979..3d856c67de2 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -2,6 +2,25 @@ name: Build on: workflow_dispatch: + inputs: + channel: + description: "Channel to configure the build" + required: true + type: choice + default: "Auto" + options: + - "Auto" + - "Test" + - "Develop" + - "Project" + - "Beta" + - "Release" + - "Release edu" + project: + description: "Project Name (used for channel name in Project builds)" + required: true + type: string + default: "hippo" pull_request: push: branches: ["main", "release/*", "project/*"] @@ -13,9 +32,13 @@ jobs: setup: runs-on: ubuntu-latest outputs: + viewer_branch: ${{ steps.which-branch.outputs.branch }} + relnotes: ${{ steps.which-branch.outputs.relnotes }} release_run: ${{ steps.setvar.outputs.release_run }} - configurations: ${{ steps.setvar.outputs.configurations }} + build_type: ${{ steps.setvar.outputs.build_type }} bugsplat_db: ${{ steps.setvar.outputs.bugsplat_db }} + viewer_channel: ${{ steps.setvar.outputs.viewer_channel }} + is_private_build: ${{ steps.setvar.outputs.is_private_build }} env: # Build with a tag like "Second_Life#abcdef0" to generate a release page # (used for builds we are planning to deploy). @@ -25,96 +48,171 @@ jobs: RELEASE_RUN: ${{ (github.event.inputs.release_run || github.ref_type == 'tag' && startsWith(github.ref_name, 'Second_Life')) && 'Y' || '' }} FROM_FORK: ${{ github.event.pull_request.head.repo.fork }} steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Setup python + uses: actions/setup-python@v6 + with: + python-version: "3.13" + + - name: Determine source branch + id: which-branch + uses: secondlife/viewer-build-util/which-branch@v2 + with: + token: ${{ github.token }} + - name: Set Variables id: setvar shell: bash + env: + BUILD_VCS_BRANCH: ${{ steps.which-branch.outputs.branch }} + VIEWER_CHANNEL_BASE: "Second Life" run: | echo "release_run=$RELEASE_RUN" >> "$GITHUB_OUTPUT" - if [[ "$FROM_FORK" == "true" ]]; then + if [[ "x$GITHUB_REPOSITORY" == "xsecondlife/viewer-private" ]]; then + echo 'is_private_build=true' >> $GITHUB_OUTPUT + else + echo 'is_private_build=false' >> $GITHUB_OUTPUT + fi + + if [[ "x$GITHUB_REPOSITORY" != "xsecondlife/viewer" && "x$GITHUB_REPOSITORY" != "xsecondlife/viewer-private" ]]; then + # Non-linden viewer repository run OSS build + echo 'build_type=opensource' >> $GITHUB_OUTPUT + echo "bugsplat_db=" >> $GITHUB_OUTPUT + elif [[ "$FROM_FORK" == "true" ]]; then # PR from fork; don't build with Bugsplat, proprietary libs - echo 'configurations=["ReleaseOS"]' >> $GITHUB_OUTPUT + echo 'build_type=opensource' >> $GITHUB_OUTPUT echo "bugsplat_db=" >> $GITHUB_OUTPUT else - echo 'configurations=["Release"]' >> $GITHUB_OUTPUT + echo 'build_type=proprietary' >> $GITHUB_OUTPUT echo "bugsplat_db=SecondLife_Viewer_2018" >> $GITHUB_OUTPUT fi + + # determine the viewer channel from the branch or tag name + # trigger an EDU build by including "edu" in the tag + edu=${{ github.ref_type == 'tag' && contains(github.ref_name, 'edu') }} + echo "ref_type=${{ github.ref_type }}, ref_name=${{ github.ref_name }}, edu='$edu'" + branch=$BUILD_VCS_BRANCH + if [[ "${{inputs.channel}}" != "" && "${{inputs.channel}}" != "Auto" ]]; + then + if [[ "${{inputs.channel}}" == "Project" ]]; + then + export viewer_channel="${{ env.VIEWER_CHANNEL_BASE }} Project ${{inputs.project}}" + else + export viewer_channel="${{ env.VIEWER_CHANNEL_BASE }} ${{inputs.channel}}" + fi + elif [[ "$edu" == "true" ]]; + then + export viewer_channel="${{ env.VIEWER_CHANNEL_BASE }} Release edu" + elif [[ "$branch" == "develop" ]]; + then + export viewer_channel="${{ env.VIEWER_CHANNEL_BASE }} Develop" + else + IFS='/' read -ra ba <<< "$branch" + prefix=${ba[0]} + if [ "$prefix" == "project" ]; then + IFS='_' read -ra prj <<< "${ba[1]}" + prj_str="${prj[*]}" + # uppercase first letter of each word + capitalized=$(echo "$prj_str" | awk '{for (i=1; i<=NF; i++) $i = toupper(substr($i,1,1)) substr($i,2); print}') + export viewer_channel="${{ env.VIEWER_CHANNEL_BASE }} Project $capitalized" + elif [[ "$prefix" == "release" || "$prefix" == "main" ]]; + then + export viewer_channel="${{ env.VIEWER_CHANNEL_BASE }} Release" + else + export viewer_channel="${{ env.VIEWER_CHANNEL_BASE }} Test" + fi + fi + echo "viewer_channel=$viewer_channel" >> "$GITHUB_OUTPUT" + build: needs: setup + permissions: + packages: write strategy: matrix: - runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge","linux-large"]' || '["windows-2022","macos-15-xlarge","ubuntu-22.04"]') }} - configuration: ${{ fromJson(needs.setup.outputs.configurations) }} + runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-26-xlarge","linux-large"]' || '["windows-2025", "macos-26", "ubuntu-22.04"]') }} + configuration: [release, relwithdebinfo, optdebug] + arch: [x64, arm64] build_variant: [Viewer, Tests] + exclude: + - runner: ubuntu-22.04 + arch: arm64 + - runner: windows-2025 + arch: arm64 + - build_variant: Viewer + configuration: relwithdebinfo + - build_variant: Viewer + configuration: optdebug + - runner: macos-26 + configuration: relwithdebinfo + - runner: macos-26 + configuration: optdebug + runs-on: ${{ matrix.runner }} outputs: - viewer_channel: ${{ steps.build.outputs.viewer_channel }} viewer_version: ${{ steps.build.outputs.viewer_version }} - viewer_branch: ${{ steps.which-branch.outputs.branch }} - relnotes: ${{ steps.which-branch.outputs.relnotes }} - imagename: ${{ steps.build.outputs.imagename }} - configuration: ${{ matrix.configuration }} + imagename: ${{ steps.build.outputs.imagename }} env: - AUTOBUILD_ADDRSIZE: 64 - AUTOBUILD_BUILD_ID: ${{ github.run_id }} - AUTOBUILD_CONFIGURATION: ${{ matrix.configuration }} - # authorizes fetching private constituent packages - AUTOBUILD_GITHUB_TOKEN: ${{ secrets.SHARED_AUTOBUILD_GITHUB_TOKEN }} - AUTOBUILD_INSTALLABLE_CACHE: ${{ github.workspace }}/.autobuild-installables - AUTOBUILD_VARIABLES_FILE: ${{ github.workspace }}/.build-variables/variables - # Direct autobuild to store vcs_url, vcs_branch and vcs_revision in - # autobuild-package.xml. - AUTOBUILD_VCS_INFO: "true" - AUTOBUILD_VSVER: "170" - DEVELOPER_DIR: "/Applications/Xcode_16.4.app/Contents/Developer" + # Sets Xcode version used for build + DEVELOPER_DIR: "/Applications/Xcode_26.2.app/Contents/Developer" # Ensure that Linden viewer builds engage Bugsplat. BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }} - build_log_dir: ${{ github.workspace }}/.logs - build_viewer: ${{ matrix.build_variant == 'Viewer' }} - build_tests: ${{ matrix.build_variant == 'Tests' }} - BUILDSCRIPTS_SHARED: ${{ github.workspace }}/.shared - # extracted and committed to viewer repo - BUILDSCRIPTS_SUPPORT_FUNCTIONS: ${{ github.workspace }}/buildscripts_support_functions - GIT_REF: ${{ github.head_ref || github.ref }} - LL_SKIP_REQUIRE_SYSROOT: 1 + # Decide if we're building tests or the viewer + BUILD_VIEWER: ${{ matrix.build_variant == 'Viewer' }} + BUILD_APPEARANCE_UTIL: ${{ startsWith(matrix.runner, 'ubuntu-') && matrix.build_variant == 'Viewer' }} + BUILD_TESTS: ${{ matrix.build_variant == 'Tests' }} + # Build Config + BUILD_ARCH: ${{ matrix.arch }} + BUILD_CONFIG: ${{ matrix.configuration }} + BUILD_TYPE: ${{ needs.setup.outputs.build_type }} + # Crash Reporting - Disabled on linux + RELEASE_CRASH_REPORTING: ${{ !startsWith(matrix.runner, 'ubuntu-') && needs.setup.outputs.build_type == 'proprietary' }} + # Viewer Channel + VIEWER_CHANNEL: ${{ needs.setup.outputs.viewer_channel }} + VIEWER_GRID: "agni" # Setting this variable directs Linden's TUT test driver code to capture # test-program log output at the specified level, but to display it only if # the individual test fails. LOGFAIL: DEBUG master_message_template_checkout: ${{ github.workspace }}/.master-message-template - # Only set variants to the one configuration: don't let build.sh loop - # over variants, let GitHub distribute variants over multiple hosts. - variants: ${{ matrix.configuration }} + # vcpkg Setup + # VCPKG_USERNAME: ${{ github.repository_owner }} + # VCPKG_FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json + # VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json,readwrite" steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + - name: Linux Dependency Install and Disk Cleanup + if: runner.os == 'Linux' + run: | + sudo apt update + sudo apt install -y \ + autoconf autoconf-archive automake bison build-essential cmake curl flex gettext \ + libasound2-dev libaudio-dev libdbus-1-dev libdbus-1-dev libdecor-0-dev libdrm-dev \ + libegl1-mesa-dev libfribidi-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ + libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libibus-1.0-dev libjack-dev \ + libosmesa6-dev libpipewire-0.3-dev libpulse-dev libsndio-dev libtext-unidecode-perl \ + libthai-dev libtool libudev-dev libunwind-dev liburing-dev libvlc-dev libwayland-dev \ + libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxft-dev libxi-dev libxinerama-dev \ + libxkbcommon-dev libxrandr-dev libxss-dev libxtst-dev linux-libc-dev mono-complete \ + ninja-build pkgconf tar tex-common texinfo unzip zip + + sudo locale-gen en_US.UTF-8 + sudo locale-gen en_GB.UTF-8 + sudo locale-gen fr_FR.UTF-8 - - name: Linux Disk Cleanup - if: matrix.build_variant == 'Viewer' && runner.os == 'Linux' + - name: macOS Homebrew Dependency Install + if: runner.os == 'macOS' run: | - # Prune various unused files from linux builder for Viewer build to fix runner disk space exhaustion - df -h - sudo docker container prune -f - sudo docker image prune -a -f - sudo rm -rf /usr/local/share/boost - sudo rm -rf /usr/share/dotnet - sudo rm -rf /usr/local/lib/android - sudo rm -rf /opt/ghc - sudo rm -rf /usr/local/.ghcup - df -h + brew install autoconf autoconf-archive automake libtool mono unzip zip - - name: Setup python - uses: actions/setup-python@v6 - with: - python-version: "3.11" - - name: Checkout build variables + - name: Checkout code uses: actions/checkout@v6 with: - repository: secondlife/build-variables - ref: master - path: .build-variables + ref: ${{ github.event.pull_request.head.sha || github.sha }} - name: Checkout master-message-template uses: actions/checkout@v6 @@ -122,159 +220,131 @@ jobs: repository: secondlife/master-message-template path: .master-message-template - - name: Install autobuild and python dependencies - run: pip3 install autobuild llsd - - - name: Cache autobuild packages - id: cache-installables - uses: actions/cache@v5 + - name: Setup python + uses: actions/setup-python@v6 with: - path: .autobuild-installables - key: ${{ runner.os }}-64-${{ matrix.configuration }}-${{ matrix.build_variant }}-${{ hashFiles('autobuild.xml') }} - restore-keys: | - ${{ runner.os }}-64-${{ matrix.configuration }}-${{ matrix.build_variant }}- - ${{ runner.os }}-64-${{ matrix.configuration }}- - ${{ runner.os }}-64- - - - name: Install Linux dependencies - if: runner.os == 'Linux' + python-version: "3.13" + + - name: Install python dependencies + run: pip3 install llsd cmake ninja + + # - name: Set up vcpkg nuget caching + # shell: bash + # run: | + # if [[ "$RUNNER_OS" == "Windows" ]] + # then + # $(${VCPKG_INSTALLATION_ROOT}/vcpkg fetch nuget | tail -n 1) \ + # sources add \ + # -Source "${{ env.VCPKG_FEED_URL }}" \ + # -StorePasswordInClearText \ + # -Name GitHubPackages \ + # -UserName "${{ env.VCPKG_USERNAME }}" \ + # -Password "${{ secrets.GITHUB_TOKEN }}" + # $(${VCPKG_INSTALLATION_ROOT}/vcpkg fetch nuget | tail -n 1) \ + # setapikey "${{ secrets.GITHUB_TOKEN }}" \ + # -Source "${{ env.VCPKG_FEED_URL }}" + # else + # mono $(${VCPKG_INSTALLATION_ROOT}/vcpkg fetch nuget | tail -n 1) \ + # sources add \ + # -Source "${{ env.VCPKG_FEED_URL }}" \ + # -StorePasswordInClearText \ + # -Name GitHubPackages \ + # -UserName "${{ env.VCPKG_USERNAME }}" \ + # -Password "${{ secrets.GITHUB_TOKEN }}" + # mono $(${VCPKG_INSTALLATION_ROOT}/vcpkg fetch nuget | tail -n 1) \ + # setapikey "${{ secrets.GITHUB_TOKEN }}" \ + # -Source "${{ env.VCPKG_FEED_URL }}" + # fi + + - name: Configure + id: configure + shell: bash + env: + HAVOK: false # ${{ needs.setup.outputs.build_type == 'proprietary' }} run: | - sudo apt update - sudo apt install -y \ - libpulse-dev libunwind-dev \ - libgl1-mesa-dev libglu1-mesa-dev libxinerama-dev \ - libxcursor-dev libxfixes-dev libgstreamer1.0-dev \ - libgstreamer-plugins-base1.0-dev ninja-build libxft-dev \ - libpipewire-0.3-dev libdbus-1-dev libvlc-dev \ - libosmesa6-dev - sudo locale-gen en_US.UTF-8 - sudo locale-gen en_GB.UTF-8 - sudo locale-gen fr_FR.UTF-8 + set -x - - name: Determine source branch - id: which-branch - uses: secondlife/viewer-build-util/which-branch@v2 - with: - token: ${{ github.token }} + # Set VCPKG root + export VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT + + [ -n "$master_message_template_checkout" ] \ + && [ -r "$master_message_template_checkout/message_template.msg" ] \ + && template_verifier_master_url="-DTEMPLATE_VERIFIER_MASTER_URL=file://$master_message_template_checkout/message_template.msg" + + cmake_preset_postfix="" + if [[ "$BUILD_TYPE" != "proprietary" ]] + then + cmake_preset_postfix="-os" + fi + + SIGNING=() + case "$RUNNER_OS" in + Windows) + cmake_preset_name="vs2022$cmake_preset_postfix" + build_directory="build-Windows-$cmake_preset_name" + vcpkg_triplet="x64-windows-secondlife-release" + ;; + macOS) + cmake_preset_name="ninja$cmake_preset_postfix-$BUILD_ARCH" + build_directory="build-Darwin-$cmake_preset_name" + vcpkg_triplet="$BUILD_ARCH-osx-secondlife-release" + ;; + Linux) + cmake_preset_name="ninja$cmake_preset_postfix" + build_directory="build-Linux-$cmake_preset_name" + vcpkg_triplet="x64-linux-secondlife-release" + ;; + esac + + echo "build_directory=$build_directory" >> "$GITHUB_OUTPUT" + echo "cmake_preset=$cmake_preset_name" >> "$GITHUB_OUTPUT" + + cmake -S indra --preset $cmake_preset_name \ + -DVCPKG_TARGET_TRIPLET="$vcpkg_triplet" \ + -DBUILD_VIEWER:BOOL="$BUILD_VIEWER" \ + -DBUILD_APPEARANCE_UTIL:BOOL="$BUILD_APPEARANCE_UTIL" \ + -DBUILD_TESTING:BOOL="$BUILD_TESTS" \ + -DPACKAGE:BOOL=ON \ + -DHAVOK:BOOL="$HAVOK" \ + -DRELEASE_CRASH_REPORTING:BOOL="$RELEASE_CRASH_REPORTING" \ + -DBUGSPLAT_DB:STRING="${BUGSPLAT_DB:-}" \ + -DVIEWER_CHANNEL:STRING="${VIEWER_CHANNEL}" \ + -DGRID:STRING="\"$VIEWER_GRID\"" \ + -DTEMPLATE_VERIFIER_OPTIONS:STRING="$template_verifier_options" $template_verifier_master_url \ + "${SIGNING[@]}" - name: Build id: build shell: bash env: - AUTOBUILD_VCS_BRANCH: ${{ steps.which-branch.outputs.branch }} - RUNNER_OS: ${{ runner.os }} + BUILD_DIRECTORY: ${{ steps.configure.outputs.build_directory }} + CMAKE_PRESET_NAME: ${{ steps.configure.outputs.cmake_preset }} + CTEST_OUTPUT_ON_FAILURE: 1 # Output log on test failure + working-directory: "${{ github.workspace }}/indra" run: | - # set up things the viewer's build.sh script expects set -x - mkdir -p "$build_log_dir" - mkdir -p "$BUILDSCRIPTS_SHARED/packages/lib/python" - source "$BUILDSCRIPTS_SUPPORT_FUNCTIONS" - if [[ "$OSTYPE" =~ cygwin|msys ]] - then - native_path() { cygpath --windows "$1"; } - shell_path() { cygpath --unix "$1"; } - else - native_path() { echo "$1"; } - shell_path() { echo "$1"; } - fi - finalize() - { - case "$1" in - true|0) - record_success "Build Succeeded" - ;; - *) - record_failure "Build Failed with $1" - ;; - esac - } - initialize_build() - { - echo "initialize_build" - } - initialize_version() - { - export revision="$AUTOBUILD_BUILD_ID" - } - python_cmd() - { - if [[ "x${1:0:1}" == "x-" ]] # -m, -c, etc. - then # if $1 is a switch, don't try to twiddle paths - "$(shell_path "$PYTHON_COMMAND")" "$@" - elif [[ "$(basename "$1")" == "codeticket.py" ]] - then # ignore any attempt to contact codeticket - echo "## $@" - else # running a script at an explicit path: fix path for Python - local script="$1" - shift - "$(shell_path "$PYTHON_COMMAND")" "$(native_path "$script")" "$@" - fi - } - repo_branch() - { - echo "$AUTOBUILD_VCS_BRANCH" - } - record_dependencies_graph() - { - echo "TODO: generate and post dependency graph" - } - # Since we're not uploading to codeticket, DO NOT sleep for minutes. - sleep() - { - echo "Not sleeping for $1 seconds" - } - export -f native_path shell_path finalize initialize_build initialize_version - export -f python_cmd repo_branch record_dependencies_graph sleep - ## Useful for diagnosing Windows LLProcess/LLLeap test failures - ##export APR_LOG="${RUNNER_TEMP}/apr.log" - export arch=$(uname | cut -b-6) - # Surprise! GH Windows runner's MINGW6 is a $arch value we've never - # seen before, so numerous tests don't know about it. - [[ "$arch" == "MINGW6" ]] && arch=CYGWIN - export AUTOBUILD="$(which autobuild)" - # determine the viewer channel from the branch or tag name - # trigger an EDU build by including "edu" in the tag - edu=${{ github.ref_type == 'tag' && contains(github.ref_name, 'edu') }} - echo "ref_type=${{ github.ref_type }}, ref_name=${{ github.ref_name }}, edu='$edu'" - branch=$AUTOBUILD_VCS_BRANCH - if [[ "$edu" == "true" ]] + # Set VCPKG root + export VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT + + if $BUILD_TESTS then - export viewer_channel="Second Life Release edu" - elif [[ "$branch" == "develop" ]]; + # Now build the tests. We want to build them in a separate step before running them. + cmake --build --preset $CMAKE_PRESET_NAME-$BUILD_CONFIG + + # Now that we've built the tests, we can run them to validate the build. + # If the tests fail, their output will be visible in the logs due to + # CTEST_OUTPUT_ON_FAILURE above, and the build step will be marked as failed. + cmake --build --preset $CMAKE_PRESET_NAME-$BUILD_CONFIG --target BUILD_AND_RUN_TESTS + elif $BUILD_VIEWER then - export viewer_channel="Second Life Develop" - else - IFS='/' read -ra ba <<< "$branch" - prefix=${ba[0]} - if [ "$prefix" == "project" ]; then - IFS='_' read -ra prj <<< "${ba[1]}" - prj_str="${prj[*]}" - # uppercase first letter of each word - capitalized=$(echo "$prj_str" | awk '{for (i=1; i<=NF; i++) $i = toupper(substr($i,1,1)) substr($i,2); print}') - export viewer_channel="Second Life Project $capitalized" - elif [[ "$prefix" == "release" || "$prefix" == "main" ]]; - then - export viewer_channel="Second Life Release" - else - export viewer_channel="Second Life Test" - fi - fi - echo "viewer_channel=$viewer_channel" - echo "viewer_channel=$viewer_channel" >> "$GITHUB_OUTPUT" - # On windows we need to point the build to the correct python - # as neither CMake's FindPython nor our custom Python.cmake module - # will resolve the correct interpreter location. - if [[ "$RUNNER_OS" == "Windows" ]]; then - export PYTHON="$(native_path "$(which python)")" - echo "Python location: $PYTHON" - export PYTHON_COMMAND="$PYTHON" + cmake --build --preset $CMAKE_PRESET_NAME-$BUILD_CONFIG || fatal "failed building $BUILD_CONFIG viewer" + + # *TODO: Make this a build extension. disabled for now + # package_llphysicsextensions_tpv || fatal "failed building llphysicsextensions packages" else - export PYTHON_COMMAND="python3" + echo "::notice::Skipping build due to both viewer and tests being disabled" fi - export PYTHON_COMMAND_NATIVE="$(native_path "$PYTHON_COMMAND")" - - ./build.sh # Each artifact is downloaded as a distinct .zip file. Multiple jobs # (per the matrix above) writing the same filepath to the same @@ -288,67 +358,123 @@ jobs: # platform, we must disambiguate on more than the platform name. # e.g. if we were still running Windows 32-bit builds, we'd need to # qualify the artifact with bit width. - if [[ "$AUTOBUILD_CONFIGURATION" == "ReleaseOS" ]] - then cfg_suffix='OS' + if [[ "$BUILD_TYPE" != "proprietary" ]] + then cfg_suffix='-OS' else cfg_suffix='' fi - echo "artifact=$RUNNER_OS$cfg_suffix" >> $GITHUB_OUTPUT + echo "artifact=$RUNNER_OS$cfg_suffix-$BUILD_ARCH" >> $GITHUB_OUTPUT + + # Gather version metadata + if [ -r "$BUILD_DIRECTORY/newview/viewer_version.txt" ] + then + viewer_version="$(<"$BUILD_DIRECTORY/newview/viewer_version.txt")" + echo "viewer_version=$viewer_version" >> "$GITHUB_OUTPUT" + fi + + # TODO: Disabled for now since we don't have the necessary Havok dependency available in our open-source vcpkg. + # - name: Build llphysicsextensions TPV package + # id: physics_tpv + # if: needs.setup.outputs.is_private_build == 'true' && needs.setup.outputs.build_type == 'proprietary' && matrix.configuration == 'release' && matrix.build_variant == 'Viewer' + # shell: bash + # env: + # BUILD_DIRECTORY: ${{ steps.configure.outputs.build_directory }} + # run: | + # tpv_status=0 + # # nat 2016-12-21: without HAVOK, can't build PhysicsExtensions_TPV. + # if [[ "$BUILD_TYPE" == "proprietary" && "${HAVOK:-}" != "OFF" ]] + # then + # tpvconfig="$build_dir/packages/llphysicsextensions/autobuild-tpv.xml" + # test -r "$tpvconfig" || fatal "No llphysicsextensions_tpv autobuild configuration found" + # # SL-19942: autobuild ignores -c switch if AUTOBUILD_CONFIGURATION set + # unset AUTOBUILD_CONFIGURATION + # "$autobuild" build --quiet --config-file "$(native_path "$tpvconfig")" -c Tpv \ + # || fatal "failed to build llphysicsextensions_tpv" + + # # capture the package file name for use in upload later... + # PKGTMP=`mktemp -t pgktpv.XXXXXX` + # cleanup="$cleanup ; rm $PKGTMP* 2>/dev/null" + # trap "$cleanup" EXIT + # "$autobuild" package --quiet --config-file "$tpvconfig" --results-file "$(native_path $PKGTMP)" || fatal "failed to package llphysicsextensions_tpv" + # tpv_status=$? + # if [ -r "${PKGTMP}" ] + # then + # . "${PKGTMP}" # sets autobuild_package_{name,filename,md5} + # echo "${autobuild_package_filename}" > $build_dir/llphysicsextensions_package + # fi + # else + # echo "::debug::Do not provide llphysicsextensions_tpv for $BUILD_TYPE" + # llphysicsextensions_package="" + # fi + # return $tpv_status - name: Upload executable uses: actions/upload-artifact@v6 - if: matrix.build_variant == 'Viewer' && steps.build.outputs.viewer_app + if: matrix.configuration == 'release' && matrix.build_variant == 'Viewer' with: name: "${{ steps.build.outputs.artifact }}-app" + if-no-files-found: error + compression-level: 9 path: | ${{ steps.build.outputs.viewer_app }} # The other upload of nontrivial size is the symbol file. Use a distinct # artifact for that too. - - name: Upload symbol file + - name: Upload Windows symbol file uses: actions/upload-artifact@v6 - if: matrix.build_variant == 'Viewer' && steps.build.outputs.symbolfile + if: runner.os == 'Windows' && matrix.configuration == 'release' && matrix.build_variant == 'Viewer' && needs.setup.outputs.build_type == 'proprietary' with: name: "${{ steps.build.outputs.artifact }}-symbols" - path: ${{ steps.build.outputs.symbolfile }} + if-no-files-found: error + path: | + ${{ steps.configure.outputs.build_directory }}/symbols/Release/${{ needs.setup.outputs.viewer_channel }}.sym.tar.xz - - name: Upload metadata + - name: Upload macOS symbol file uses: actions/upload-artifact@v6 - if: matrix.build_variant == 'Viewer' + if: runner.os == 'macOS' && matrix.configuration == 'release' && matrix.build_variant == 'Viewer' && needs.setup.outputs.build_type == 'proprietary' with: - name: "${{ steps.build.outputs.artifact }}-metadata" - # emitted by build.sh, possibly multiple lines + name: "${{ steps.build.outputs.artifact }}-symbols" + if-no-files-found: error path: | - ${{ steps.build.outputs.metadata }} + ${{ steps.configure.outputs.build_directory }}/symbols/Release/${{ needs.setup.outputs.viewer_channel }}.xcarchive.zip - - name: Upload physics package + - name: Upload metadata uses: actions/upload-artifact@v6 - # should only be set for viewer-private - if: matrix.build_variant == 'Viewer' && matrix.configuration == 'Release' && steps.build.outputs.physicstpv + if: matrix.configuration == 'release' && matrix.build_variant == 'Viewer' with: - name: "${{ steps.build.outputs.artifact }}-physics" - # emitted by build.sh, zero or one lines + name: "${{ steps.build.outputs.artifact }}-metadata" + if-no-files-found: error + compression-level: 9 path: | - ${{ steps.build.outputs.physicstpv }} + ${{ steps.configure.outputs.build_directory }}/newview/viewer_version.txt + + # - name: Upload physics package + # uses: actions/upload-artifact@v6 + # # should only be set for viewer-private + # if: needs.setup.outputs.is_private_build == 'true' && needs.setup.outputs.build_type == 'proprietary' && matrix.configuration == 'release' && matrix.build_variant == 'Viewer' + # with: + # name: "${{ steps.build.outputs.artifact }}-physics" + # path: | + # ${{ steps.configure.outputs.build_directory }}/llphysicsextensions_package*.tar.xz - name: Upload appearance utility package uses: actions/upload-artifact@v6 - if: matrix.build_variant == 'Viewer' && steps.build.outputs.appearanceutility + if: runner.os == 'Linux' && matrix.configuration == 'release' && matrix.build_variant == 'Viewer' with: name: "${{ steps.build.outputs.artifact }}-appearanceutility" - # emitted by build.sh, zero or one lines path: | - ${{ steps.build.outputs.appearanceutility }} - + ${{ steps.configure.outputs.build_directory }}/llappearanceutility/Release/appearance-utility-bin + ${{ steps.configure.outputs.build_directory }}/llappearanceutility/Release/appearance-utility-headless-bin sign-and-package-windows: env: AZURE_KEY_VAULT_URI: ${{ secrets.AZURE_KEY_VAULT_URI }} - AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - needs: build + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + needs: [setup, build] runs-on: windows-2022 + if: needs.setup.outputs.build_type == 'proprietary' steps: - name: Sign and package Windows viewer if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID @@ -362,12 +488,13 @@ jobs: sign-and-package-mac: env: - NOTARIZE_CREDS_MACOS: ${{ secrets.NOTARIZE_CREDS_MACOS }} - SIGNING_CERT_MACOS: ${{ secrets.SIGNING_CERT_MACOS }} + NOTARIZE_CREDS_MACOS: ${{ secrets.NOTARIZE_CREDS_MACOS }} + SIGNING_CERT_MACOS: ${{ secrets.SIGNING_CERT_MACOS }} SIGNING_CERT_MACOS_IDENTITY: ${{ secrets.SIGNING_CERT_MACOS_IDENTITY }} SIGNING_CERT_MACOS_PASSWORD: ${{ secrets.SIGNING_CERT_MACOS_PASSWORD }} - needs: build + needs: [setup, build] runs-on: macos-latest + if: needs.setup.outputs.build_type == 'proprietary' steps: - name: Unpack Mac notarization credentials if: env.NOTARIZE_CREDS_MACOS @@ -393,7 +520,7 @@ jobs: if: env.SIGNING_CERT_MACOS && env.SIGNING_CERT_MACOS_IDENTITY && env.SIGNING_CERT_MACOS_PASSWORD && steps.note-creds.outputs.note_user && steps.note-creds.outputs.note_pass && steps.note-creds.outputs.note_team uses: secondlife/viewer-build-util/sign-pkg-mac@v2 with: - channel: ${{ needs.build.outputs.viewer_channel }} + channel: ${{ needs.setup.outputs.viewer_channel }} imagename: ${{ needs.build.outputs.imagename }} cert_base64: ${{ env.SIGNING_CERT_MACOS }} cert_name: ${{ env.SIGNING_CERT_MACOS_IDENTITY }} @@ -407,25 +534,25 @@ jobs: BUGSPLAT_DATABASE: "${{ secrets.BUGSPLAT_DATABASE }}" SYMBOL_UPLOAD_CLIENT_ID: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_ID }}" SYMBOL_UPLOAD_CLIENT_SECRET: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_SECRET }}" - needs: build - if: needs.build.outputs.configuration == 'Release' + needs: [setup, build] + if: needs.setup.outputs.build_type == 'proprietary' runs-on: ubuntu-latest steps: - name: Download viewer exe uses: actions/download-artifact@v7 with: - name: Windows-app + name: Windows-x64-app path: _artifacts - name: Download Windows Symbols if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID uses: actions/download-artifact@v7 with: - name: Windows-symbols + name: Windows-x64-symbols - name: Extract viewer pdb if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID shell: bash run: | - tar -xJf "${{ needs.build.outputs.viewer_channel }}.sym.tar.xz" -C _artifacts + tar -xJf "${{ needs.setup.outputs.viewer_channel }}.sym.tar.xz" -C _artifacts - name: Post Windows symbols if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID uses: BugSplat-Git/symbol-upload@095d163ae9ceb006d286a731dcd35cf6a1b458c8 @@ -433,7 +560,7 @@ jobs: clientId: "${{ env.SYMBOL_UPLOAD_CLIENT_ID }}" clientSecret: "${{ env.SYMBOL_UPLOAD_CLIENT_SECRET }}" database: "${{ env.BUGSPLAT_DATABASE }}" - application: ${{ needs.build.outputs.viewer_channel }} + application: ${{ needs.setup.outputs.viewer_channel }} version: ${{ needs.build.outputs.viewer_version }} directory: _artifacts files: "**/{SecondLifeViewer.exe,llwebrtc.dll,*.pdb}" @@ -445,15 +572,15 @@ jobs: BUGSPLAT_DATABASE: "${{ secrets.BUGSPLAT_DATABASE }}" SYMBOL_UPLOAD_CLIENT_ID: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_ID }}" SYMBOL_UPLOAD_CLIENT_SECRET: "${{ secrets.BUGSPLAT_SYMBOL_UPLOAD_CLIENT_SECRET }}" - needs: build - if: needs.build.outputs.configuration == 'Release' + needs: [setup, build] + if: needs.setup.outputs.build_type == 'proprietary' runs-on: ubuntu-latest steps: - name: Download Mac Symbols if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID uses: actions/download-artifact@v7 with: - name: macOS-symbols + name: macOS-x64-symbols - name: Post Mac symbols if: env.BUGSPLAT_DATABASE && env.SYMBOL_UPLOAD_CLIENT_ID uses: BugSplat-Git/symbol-upload@095d163ae9ceb006d286a731dcd35cf6a1b458c8 @@ -461,7 +588,7 @@ jobs: clientId: "${{ env.SYMBOL_UPLOAD_CLIENT_ID }}" clientSecret: "${{ env.SYMBOL_UPLOAD_CLIENT_SECRET }}" database: "${{ env.BUGSPLAT_DATABASE }}" - application: ${{ needs.build.outputs.viewer_channel }} + application: ${{ needs.setup.outputs.viewer_channel }} version: ${{ needs.build.outputs.viewer_version }} (${{ needs.build.outputs.viewer_version }}) directory: . files: "**/*.xcarchive.zip" @@ -487,11 +614,8 @@ jobs: - name: Rename metadata run: | - cp Windows-metadata/autobuild-package.xml Windows-autobuild-package.xml cp Windows-metadata/newview/viewer_version.txt Windows-viewer_version.txt - cp macOS-metadata/autobuild-package.xml macOS-autobuild-package.xml cp macOS-metadata/newview/viewer_version.txt macOS-viewer_version.txt - cp Linux-metadata/autobuild-package.xml Linux-autobuild-package.xml cp Linux-metadata/newview/viewer_version.txt Linux-viewer_version.txt # forked from softprops/action-gh-release @@ -500,14 +624,14 @@ jobs: uses: secondlife-3p/action-gh-release@v1 with: # name the release page for the branch - name: "${{ needs.build.outputs.viewer_branch }}" + name: "${{ needs.setup.outputs.viewer_branch }}" # SL-20546: want the channel and version to be visible on the # release page body: | Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - ${{ needs.build.outputs.viewer_channel }} + ${{ needs.setup.outputs.viewer_channel }} ${{ needs.build.outputs.viewer_version }} - ${{ needs.build.outputs.relnotes }} + ${{ needs.setup.outputs.relnotes }} prerelease: true generate_release_notes: true target_commitish: ${{ github.sha }} @@ -517,7 +641,6 @@ jobs: macOS-installer/*.dmg Windows-installer/*.exe *.tar.xz - *-autobuild-package.xml *-viewer_version.txt - name: post release URL diff --git a/.gitignore b/.gitignore index a784d6e7d4c..43cf7581bb5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,7 @@ # By extension *.DS_Store *.bak -*.diff *.orig -*.patch *.pyc *.rej *.swp @@ -17,11 +15,14 @@ *~ # Specific paths and/or names +.vs .venv +.cache +.zed CMakeCache.txt cmake_install.cmake LICENSES -build-* +build* debian/files debian/secondlife-appearance-utility* debian/secondlife-viewer* @@ -29,11 +30,7 @@ indra/.distcc indra/out/* indra/packages/* -build-vc80/ -build-vc100/ -build-vc120/ -build-vc*-32/ -build-vc*-64/ +build-*/ indra/CMakeFiles indra/build-vc[0-9]* indra/lib/mono/1.0/*.dll @@ -91,3 +88,5 @@ web/secondlife.com.* .env .vscode +.vs +.zed diff --git a/README.md b/README.md index 1e40c7f9f58..d984ed9e46e 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,33 @@ Third party maintained forks, which include Linux compatible builds, are indexed ## Build Instructions -[Windows](https://wiki.secondlife.com/wiki/Build_the_Viewer_on_Windows) +The Second Life viewer uses CMake for build system generation and vcpkg for dependency management. -[Mac](https://wiki.secondlife.com/wiki/Build_the_Viewer_on_macOS) +### Platform-specific setup guides -[Linux](https://wiki.secondlife.com/wiki/Build_the_Viewer_on_Linux) +[Windows](doc/BUILD.WINDOWS.md) + +[Mac](doc/BUILD.MAC.md) + +[Linux](doc/BUILD.LINUX.md) + +### Configuration Types +| CMake | Description | +|:---------------------------|:------------------------------------------------------------------------------------| +| Debug | A debug build linked against debug libraries | +| OptDebug | A debug build linked with release libraries | +| RelWithDebInfo | A release optimized build with asserts linked with release libraries | +| Release | A release optimized build linked with release libraries | + +### Build Options + +| CMake | Description | Default | +|:---------------------------|:------------------------------------------------------------------------------------|---------| +| BUILD_VIEWER | Build viewer binaries | ON | +| BUILD_APPEARANCE_UTIL | Build appearance utility | OFF | +| BUILD_TESTING | Build test binries. | OFF | +| PACKAGE | Build installer packages when viewer build enabled | ON | +| USE_OPENAL | Build with support for the OpenAL audio engine | ON | ## Contribute diff --git a/autobuild.xml b/autobuild.xml deleted file mode 100644 index bc6b073a99f..00000000000 --- a/autobuild.xml +++ /dev/null @@ -1,3241 +0,0 @@ - - - - version - 1.3 - type - autobuild - installables - - SDL3 - - platforms - - windows64 - - archive - - hash - 121b209bbf8ffb2f7f668a74de0e654f4be7339f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-sdl3/releases/download/v3.2.24-r1/SDL3-3.2.24-r1-windows64-18539840462.tar.zst - - name - windows64 - - linux64 - - archive - - hash - 06226c54c57afd601707c0f5f7a2e0736ab1f326 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-sdl3/releases/download/v3.2.24-r1/SDL3-3.2.24-r1-linux64-18539840462.tar.zst - - name - linux64 - - darwin64 - - archive - - hash - aff68fb5655629c698e198af1581835267588f77 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-sdl3/releases/download/v3.2.24-r1/SDL3-3.2.24-r1-darwin64-18539840462.tar.zst - - name - darwin64 - - - license - lgpl - license_file - LICENSES/SDL3.txt - copyright - Copyright (C) 1997-2022 Sam Lantinga (slouken@libsdl.org) - version - 3.2.24-r1 - use_scm_version - true - name - SDL3 - description - Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. - - apr_suite - - platforms - - darwin64 - - archive - - hash - 3f8e58fe74e144b771858e89a5514bf354964c76 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.5-r2/apr_suite-1.7.5-18696779749-darwin64-18696779749.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - df36114eb8fb66fdcbb190011222a7d336791d98 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.5-r2/apr_suite-1.7.5-18696779749-linux64-18696779749.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 164705831819d247753c9fd608c2c1ac8dca1883 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-apr_suite/releases/download/v1.7.5-r2/apr_suite-1.7.5-18696779749-windows64-18696779749.tar.zst - - name - windows64 - - - license - apache - license_file - LICENSES/apr_suite.txt - copyright - Copyright © 2012 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. - version - 1.7.5-18696779749 - name - apr_suite - description - Apache portable runtime project - - boost - - platforms - - darwin64 - - archive - - hash - 61cc299413a32350175cf7139f64388d3d096ec7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-darwin64-20977261894.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 6b93e323284bfab8ec20a7f3bc740c6915980bf8 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-linux64-20977261894.tar.zst - - name - linux64 - - windows64 - - archive - - hash - c543437ca30a63dcd2538fffa89a43ef43f625fb - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-boost/releases/download/v1.90.0-c7a9feb/boost-1.90-windows64-20977261894.tar.zst - - name - windows64 - - - license - boost 1.0 - license_file - LICENSES/boost.txt - copyright - (see individual source files) - version - 1.90.0-c7a9feb - name - boost - description - Boost C++ Libraries - - bugsplat - - platforms - - darwin64 - - archive - - hash - 9bcafdd7e1df6b92096fa850627d4f3437630d4a - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-bugsplat/releases/download/v1.2.6-a475cbb/bugsplat-1.2.6-19430122611-darwin64-19430122611.tar.zst - - name - darwin64 - - windows64 - - archive - - hash - 4e9f0c1cdbc1cebf6185ecc45228ced7f9af1532 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-bugsplat/releases/download/v1.2.6-a475cbb/bugsplat-6.1.1.0-19430122611-windows64-19430122611.tar.zst - - name - windows64 - - - license - Proprietary - license_file - LICENSES/BUGSPLAT_LICENSE.txt - copyright - Copyright 2003-2017, BugSplat - version - 5.0.1.0-71fc41e - name - bugsplat - description - Bugsplat crash reporting package - - colladadom - - platforms - - darwin64 - - archive - - hash - 9710f82a237b95aaafbbcf708b89f6015b80d85f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-darwin64-20980076767.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 6a1725b1bc13634eb4dd872a4f83c3f16497475f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-linux64-20980076767.tar.zst - - name - linux64 - - windows64 - - archive - - hash - ba9eeb62ae3046d91f9e061db823c1863623b017 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-colladadom/releases/download/v2.3-r11/colladadom-2.3.0-r11-windows64-20980076767.tar.zst - - name - windows64 - - - license - SCEA - license_file - LICENSES/collada.txt - copyright - Copyright 2006 Sony Computer Entertainment Inc. - version - 2.3.0-r11 - name - colladadom - - cubemaptoequirectangular - - platforms - - darwin64 - - archive - - hash - e21e7755fe740d5ed30bd29441170449a57caa8b - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-darwin64-cb8785a.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - aea0bed0f953a9371b9091f09230b41597f891f7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-linux64-cb8785a.tar.zst - - name - linux64 - - windows64 - - archive - - hash - eabc3b0c9d9084f49b8a4dc5d3834d77f668c27a - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-cubemap_to_eqr_js/releases/download/v1.1.0-cb8785a/cubemaptoequirectangular-1.1.0-windows64-cb8785a.tar.zst - - name - windows64 - - - license - MIT - license_file - LICENSES/CUBEMAPTOEQUIRECTANGULAR_LICENSE.txt - copyright - Copyright (c) 2017 Jaume Sanchez Elias, http://www.clicktorelease.com - version - 1.1.0 - name - cubemaptoequirectangular - - curl - - platforms - - darwin64 - - archive - - hash - 5eab8167cec442e8c156bb653012d7544cca6037 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-darwin64-20982000504.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 3465bbe70cfba2814b1fd52094c62804f4067490 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-linux64-20982000504.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 0e64e20945eeb19259abf8e78400eb492e31eda7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-curl/releases/download/v7.54.1-r4/curl-7.54.1-20982000504-windows64-20982000504.tar.zst - - name - windows64 - - - license - curl - license_file - LICENSES/curl.txt - copyright - Copyright (c) 1996 - 2014, Daniel Stenberg, (daniel@haxx.se). - version - 7.54.1-20982000504 - name - curl - description - Library for transferring data specified with URL syntax - - dictionaries - - platforms - - common - - archive - - hash - e03eb77224290c875ff84f75b7fe3d0e7c162c94 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-dictionaries/releases/download/v1-a01bb6c/dictionaries-1.a01bb6c-common-a01bb6c.tar.zst - - name - common - - - license - various open source - license_file - LICENSES/dictionaries.txt - copyright - Copyright 2014 Apache OpenOffice software - version - 1.a01bb6c - name - dictionaries - description - Spell checking dictionaries to bundled into the viewer - - dullahan - - platforms - - darwin64 - - archive - - hash - 2c81fa7aa03b427088ab54ce3b71088a0003126b - hash_algorithm - sha1 - url - https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139-darwin64-18568015445.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 8e06d060729250c5bfcb993c8f818f36ea17de16 - hash_algorithm - sha1 - url - https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139-linux64-18568015445.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 7ca6db37f019b47e230c0861607c546d45535367 - hash_algorithm - sha1 - url - https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161628_139.0.40_g465474a_chromium-139.0.7258.139-windows64-18568015445.tar.zst - - name - windows64 - - - license - MPL - license_file - LICENSES/LICENSE.txt - copyright - Copyright (c) 2017, Linden Research, Inc. - version - 1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139 - name - dullahan - description - A headless browser SDK that uses the Chromium Embedded Framework (CEF). It is designed to make it easier to write applications that render modern web content directly to a memory buffer, inject synthesized mouse and keyboard events as well as interact with web based features like JavaScript or cookies. - - emoji_shortcodes - - platforms - - common - - archive - - hash - 9c58108270fbad15a321f75501cdfb9c6b78a6f2 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-emoji-shortcodes/releases/download/v15.3.2-r1/emoji_shortcodes-15.3.2.10207138275-common-10207138275.tar.zst - - name - common - - - license - MIT - license_file - LICENSES/emojibase-license.txt - copyright - Copyright 2017-2019 Miles Johnson. - version - 15.3.2.10207138275 - name - emoji_shortcodes - canonical_repo - https://github.com/secondlife/3p-emoji-shortcodes - description - Emoji shortcodes - - expat - - platforms - - darwin64 - - archive - - hash - e0ba69946f2203c03faf89c1f6d5bbc48d88d2a9 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-expat/releases/download/v2.6.4-r1/expat-2.6.4-r1-darwin64-11943227858.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 13483477c1f8b4bad9055fba561c64137453c3da - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-expat/releases/download/v2.6.4-r1/expat-2.6.4-r1-linux64-11943227858.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 542af7d8bb8de3297c80c23a771bbcb513a630b7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-expat/releases/download/v2.6.4-r1/expat-2.6.4-r1-windows64-11943227858.tar.zst - - name - windows64 - - - license - expat - license_file - LICENSES/expat.txt - copyright - Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper - Copyright (c) 2001-2022 Expat maintainers. - version - 2.6.4-r1 - name - expat - description - Expat is an XML parser library written in C - - freetype - - platforms - - darwin64 - - archive - - hash - 550a90bca35bdbbd615afb1a1c02383cb3b6edbe - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-darwin64-20935810762.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - f52b05392962cb6a8e5f534d8687faa525d4960a - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-linux64-20935810762.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 3c30052adcbfec572562bb1e7927d7a8f4d93f3d - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-freetype/releases/download/v2.13.3-r4/freetype-2.13.3-r4-windows64-20935810762.tar.zst - - name - windows64 - - - license - FreeType - license_file - LICENSES/freetype.txt - copyright - Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg. - version - 2.13.3-r4 - name - freetype - description - Font rendering library - - glext - - platforms - - common - - archive - - hash - 90eade4785ee8acf18837125208b717f7e857d06 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-glext/releases/download/v2025.10.27-r1/glext-2025.10.27-common-18888617188.tar.zst - - name - common - - - license - Copyright (c) 2007-2010 The Khronos Group Inc. - license_file - LICENSES/glext.txt - copyright - Copyright (c) 2007-2010 The Khronos Group Inc. - version - 2025.10.27 - name - glext - description - glext headers define function prototypes and constants for OpenGL extensions - - glm - - platforms - - common - - archive - - hash - 353ae3a560143732503a8e14499ae12db1e66056 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-glm/releases/download/v1.0.1-r1/glm-v1.0.1-common-9066386153.tar.zst - - name - common - - - license - MIT - license_file - LICENSES/glm_license.txt - copyright - Copyright (c) 2005 - G-Truc Creation - version - v1.0.1 - name - glm - vcs_branch - refs/tags/v1.0.1-r1 - vcs_revision - 399cd5ba57a9267a560ce07e50a0f8c5fe3dc66f - vcs_url - git://github.com/secondlife/3p-glm.git - canonical_repo - https://github.com/secondlife/3p-glm - description - OpenGL Mathematics - source_type - git - - havok-source - - platforms - - darwin64 - - archive - - creds - github - hash - 1648aeb68395cba38f9326c671609d6730cbcc28 - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/196725921 - - name - darwin64 - - linux64 - - archive - - creds - github - hash - 702ad28b6dbace2a68260d69f6d1768d163b5a6f - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/196725902 - - name - linux64 - - windows64 - - archive - - creds - github - hash - ea980f372981fe7685f91a111da2785825d473ed - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-havok-source/releases/assets/196725911 - - name - windows64 - - - license - havok - license_file - LICENSES/havok.txt - copyright - Uses Havok (TM) Physics. (c)Copyright 1999-2010 Havok.com Inc. (and its Licensors). All Rights Reserved. See www.havok.com for details. - version - 2012.1-2 - name - havok-source - description - Havok source code for libs and demos - - jpegencoderbasic - - platforms - - darwin64 - - archive - - hash - b05374300cdd40c381614f2ee4497de340eda991 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-darwin64-790015a.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 23daab838f4b8f92e5dc1a2f6c568cb7b0cb43b7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-linux64-790015a.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 23e8ba22aadf88d249a21844bfcdd01138c05937 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-jpeg_encoder_js/releases/download/v1.0-790015a/jpegencoderbasic-1.0-windows64-790015a.tar.zst - - name - windows64 - - - license - NONE - license_file - LICENSES/JPEG_ENCODER_BASIC_LICENSE.txt - copyright - Andreas Ritter, www.bytestrom.eu, 11/2009 - version - 1.0 - name - jpegencoderbasic - - libjpeg-turbo - - platforms - - windows64 - - archive - - hash - 10f14875ce5c7f5028217c8b7468733190fd333d - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.4-r1/libjpeg_turbo-3.0.4-r1-windows64-11968659895.tar.zst - - name - windows64 - - linux64 - - archive - - hash - d3b1b0fde28c8cf0c33fed167dba87bba5c6cc64 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.4-r1/libjpeg_turbo-3.0.4-r1-linux64-11968659895.tar.zst - - name - linux64 - - darwin64 - - archive - - hash - 79e78cbaaec9a99c0ae4a5cdd4a98535c8fa3c6d - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libjpeg-turbo/releases/download/v3.0.4-r1/libjpeg_turbo-3.0.4-r1-darwin64-11968659895.tar.zst - - name - darwin64 - - - license - libjpeg-turbo - license_file - LICENSES/libjpeg-turbo.txt - copyright - Copyright (C)2009-2024 D. R. Commander. All Rights Reserved. Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. - version - 3.0.4-r1 - name - libjpeg-turbo - canonical_repo - https://github.com/secondlife/3p-libjpeg-turbo - description - JPEG encoding, decoding library - - kdu - - platforms - - darwin64 - - archive - - creds - github - hash - da318f0813e4126d90e35b22a8dce235e908707a - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381808 - - name - darwin64 - - linux64 - - archive - - creds - github - hash - 1ba58cf884726dfdf02a7662d52f1befe3f16d44 - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381812 - - name - linux64 - - windows64 - - archive - - creds - github - hash - e8d693089b9ecd15b6644f13ada7ae7c317944df - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-kdu/releases/assets/208381814 - - name - windows64 - - - license - Kakadu - license_file - LICENSES/kdu.txt - copyright - Kakadu software - version - 8.4.1.11976899217 - name - kdu - description - JPEG2000 library by Kakadu - - libhunspell - - platforms - - darwin64 - - archive - - hash - 91acd05f450162b07ca2f68094778c483d28128d - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r2/libhunspell-1.7.2.11968900321-darwin64-11968900321.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 10e5b5d793c3c5cb5335dea89734302bda5a9f59 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r2/libhunspell-1.7.2.11968900321-linux64-11968900321.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 0f7b9c46dc4e81a6296e4836467f5fe52aa5761d - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libhunspell/releases/download/v1.7.2-r2/libhunspell-1.7.2.11968900321-windows64-11968900321.tar.zst - - name - windows64 - - - license - LGPL - license_file - LICENSES/hunspell.txt - copyright - LGPL 2.1 - version - 1.7.2.11968900321 - name - libhunspell - description - Spell checking library - - libndofdev - - platforms - - darwin64 - - archive - - hash - d1638886671b31935ea7e3c824e015ea1a45b12e - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.a0b7d99/libndofdev-0.1.11968678219-darwin64-11968678219.tar.zst - - name - darwin64 - - windows64 - - archive - - hash - 7b3e504885c4c0cc75db298e682f408c4f2e95f7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libndofdev/releases/download/v0.1.a0b7d99/libndofdev-0.1.11968678219-windows64-11968678219.tar.zst - - name - windows64 - - - license - BSD - license_file - LICENSES/libndofdev.txt - copyright - Copyright (c) 2007, 3Dconnexion, Inc. - All rights reserved. - version - 0.1.11968678219 - name - libndofdev - description - 3DConnexion SDK - - libpng - - platforms - - darwin64 - - archive - - hash - 6fa10d5f44601dda6efc3eda1a9dab22525e7a9a - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-darwin64-20934739343.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 112b7f46f5923e6418dfa4bc13ebe2db6911c9b9 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-linux64-20934739343.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 2731c45f1e62e33b8612b3ee2b9c4cb39dafbfe2 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libpng/releases/download/v1.6.53-eea12b7/libpng-1.6.44-dev1.geea12b7-windows64-20934739343.tar.zst - - name - windows64 - - - license - libpng - license_file - LICENSES/libpng.txt - copyright - Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson - version - 1.6.53-eea12b7 - name - libpng - description - PNG Reference library - - libxml2 - - platforms - - darwin64 - - archive - - hash - c1ad7ff9ec91049c93d2dcd832f81a00f8f4b4b9 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-darwin64-20936141417.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 7fc2df91648661468a82754b26fd7dedfbef1d39 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-linux64-20936141417.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 84828c26b67c33f0d3e565718943aa339582b34f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-libxml2/releases/download/v2.13.9-d53cd6f/libxml2-2.13.9-d53cd6f-windows64-20936141417.tar.zst - - name - windows64 - - - license - mit - license_file - LICENSES/libxml2.txt - copyright - Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. - version - 2.13.9-d53cd6f - name - libxml2 - description - Libxml2 is the XML C parser and toolkit developed for the Gnome project. - - llca - - platforms - - common - - archive - - hash - 6d6771706a5b70caa24893ff62afc925f8d035f6 - hash_algorithm - sha1 - url - https://github.com/secondlife/llca/releases/download/v202407221723.0-a0fd5b9/llca-202407221423.0-common-10042698865.tar.zst - - name - common - - - license - mit - license_file - LICENSES/ca-license.txt - copyright - Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project. - - version - 202407221423.0 - name - llca - - llphysicsextensions_source - - platforms - - common - - archive - - creds - github - hash - fff82c79edb900c547c40dca9a0e3ebac5a8c7da - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/llphysicsextensions_source/releases/assets/299858950 - - name - common - - - license - internal - license_file - LICENSES/llphysicsextensions.txt - copyright - Copyright (c) 2010, Linden Research, Inc. - version - 1.0.11137145495 - name - llphysicsextensions_source - - llphysicsextensions_tpv - - platforms - - darwin64 - - archive - - hash - f09066891d5a52add50bdb14efdc86f6 - url - https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/84729/788142/llphysicsextensions_tpv-1.0.561752-darwin64-561752.tar.bz2 - - name - darwin64 - - linux64 - - archive - - hash - 711f4ec769e4b5f59ba25ee43c11bcbc - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/4724/14846/llphysicsextensions_stub-1.0.504712-linux64-504712.tar.bz2 - - name - linux64 - - windows64 - - archive - - hash - a43e360236e7c17b5823f91e4c349e60 - url - https://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/84731/788139/llphysicsextensions_tpv-1.0.561752-windows64-561752.tar.bz2 - - name - windows - - - license - internal - license_file - LICENSES/HavokSublicense.pdf - copyright - Copyright (c) 2010, Linden Research, Inc. - version - 1.0.561752 - name - llphysicsextensions_tpv - - meshoptimizer - - platforms - - darwin64 - - archive - - hash - 3692af717636da9c2b1e0f13eb084ce022b67f6c - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-darwin64-20867041007.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 22ad1be39a1196a1ca3902ba936460cb69252b9c - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-linux64-20867041007.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 2c9769f31da5de3920d7ee400d280398c911a30f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-meshoptimizer/releases/download/v1.0.1-9d6a006/meshoptimizer-1.0.1-9d6a006-windows64-20867041007.tar.zst - - name - windows64 - - - license - meshoptimizer - license_file - LICENSES/meshoptimizer.txt - copyright - Copyright (c) 2016-2021 Arseny Kapoulkine - version - 220.0.0-r1 - name - meshoptimizer - canonical_repo - https://bitbucket.org/lindenlab/3p-meshoptimizer - description - Meshoptimizer. Mesh optimization library. - - mikktspace - - platforms - - darwin64 - - archive - - hash - 65edf85c36a10001e32bdee582bec4732137208b - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-darwin64-8756084692.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - fa9dcee4584df7e7271fdf69c08e6fd3122a47fc - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-linux64-8756084692.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 130b33a70bdb3a8a188376c6a91840bdb61380a8 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-mikktspace/releases/download/v2-e967e1b/mikktspace-1-windows64-8756084692.tar.zst - - name - windows64 - - - license - Apache 2.0 - license_file - mikktspace.txt - copyright - Copyright (C) 2011 by Morten S. Mikkelsen, Copyright (C) 2022 Blender Authors - version - 1 - name - mikktspace - canonical_repo - https://bitbucket.org/lindenlab/3p-mikktspace - description - Mikktspace Tangent Generator - - minizip-ng - - platforms - - darwin64 - - archive - - hash - 85179317015c5c91986000d69c9f61a01af7617f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-darwin64-20933148061.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - ef1524f507f44fed6f1c1f00ae274ddb8a1ac359 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-linux64-20933148061.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 90be39cf789b596377458f1ea78f415a9c281a8c - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-minizip-ng/releases/download/v4.0.7-r4/minizip_ng-4.0.7-r4-windows64-20933148061.tar.zst - - name - windows64 - - - license - minizip-ng - license_file - LICENSES/minizip-ng.txt - copyright - This project uses the zlib license. Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler - version - 4.0.7-r4 - name - minizip-ng - canonical_repo - https://bitbucket.org/lindenlab/3p-minizip-ng - description - minizip-ng is a zip manipulation library. Based on work of Gilles Vollant. - - nanosvg - - platforms - - darwin64 - - archive - - hash - 32ead724319c2ea6f65fc5be0e3157cc - url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/115452/994130/nanosvg-2022.09.27-darwin64-580364.tar.bz2 - - name - darwin64 - - linux - - archive - - hash - 84698f044598ff79e255965f3d1c3e80 - url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/115397/993664/nanosvg-2022.09.27-linux-580337.tar.bz2 - - name - linux - - windows64 - - archive - - hash - ee61ff8b866be04c325f1fe2db516d71 - url - https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/115454/994144/nanosvg-2022.09.27-windows64-580364.tar.bz2 - - name - windows64 - - - license - Zlib - license_file - LICENSES/nanosvg.txt - copyright - Copyright (c) 2013-14 Mikko Mononen - version - 2022.09.27 - name - nanosvg - canonical_repo - https://bitbucket.org/lindenlab/3p-nanosvg - description - NanoSVG is a simple single-header-file SVG parser and rasterizer - - nghttp2 - - platforms - - darwin64 - - archive - - hash - f45ea5a42d6a419f9b605dd3f976fbcb3850d736 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-nghttp2/releases/download/v1.64.0-r2/nghttp2-1.64.0-r1-darwin64-13184359419.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - c6e450fa41f24f1b4103d2006d706595f2a36c59 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-nghttp2/releases/download/v1.64.0-r2/nghttp2-1.64.0-r1-linux64-13184359419.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 3bd92f892e155104740570fe244ea4dbb0b57d4b - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-nghttp2/releases/download/v1.64.0-r2/nghttp2-1.64.0-r1-windows64-13184359419.tar.zst - - name - windows64 - - - license - MIT - license_file - LICENSES/nghttp2.txt - copyright - Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa -Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors - version - 1.64.0-r1 - name - nghttp2 - description - Library providing HTTP 2 support for libcurl - source_type - hg - - nvapi - - platforms - - windows64 - - archive - - hash - bc574ea89164387a6c12bb49e1bac091c1d4da27 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-nvapi/releases/download/v560-r1/nvapi-560.0.0-r1-windows64-10390321492.tar.zst - - name - windows64 - - - license - MIT - license_file - LICENSES/nvapi.txt - copyright - Copyright (c) 2024 NVIDIA CORPORATION and AFFILIATES. All rights reserved. - version - 560.0.0-r1 - name - nvapi - description - NVAPI provides an interface to NVIDIA devices. - - ogg_vorbis - - platforms - - darwin64 - - archive - - hash - 68657c5c161c3fe8ff64eac3787172fcb06da972 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r2/ogg_vorbis-1.3.5-1.3.7.11968798109-darwin64-11968798109.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 9a6ffad7b4186a158c019c5a5a5d7b8badb441da - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r2/ogg_vorbis-1.3.5-1.3.7.11968798109-linux64-11968798109.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 5f4cbb928ebfe774a9c07d3f2c255fd38bd6b4d6 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-ogg_vorbis/releases/download/v1.3.5-1.3.7-r2/ogg_vorbis-1.3.5-1.3.7.11968798109-windows64-11968798109.tar.zst - - name - windows64 - - - license - ogg-vorbis - license_file - LICENSES/ogg-vorbis.txt - copyright - Copyright (c) 2002, Xiph.org Foundation - version - 1.3.5-1.3.7.11968798109 - name - ogg_vorbis - description - Audio encoding library - - open-libndofdev - - platforms - - linux64 - - archive - - hash - 612bfcb7cf0e6afaf7ce7f1db6feccd81137eb99 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-open-libndofdev/releases/download/v1.14-r7/open_libndofdev-0.14.19022717849-linux64-19022717849.tar.zst - - name - linux64 - - - license - BSD - license_file - LICENSES/libndofdev.txt - copyright - Copyright (c) 2008, Jan Ciger (jan.ciger (at) gmail.com) - version - 0.14.19022717849 - name - open-libndofdev - description - Open Source replacement for 3DConnection SDK - - openal - - platforms - - darwin64 - - archive - - hash - a3cc405d48a48a474d05b3de3d28da2005d80037 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-darwin64-13245988487.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - a2b63f0f85ca156c59ee1d34ef96c8e50b89153c - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-linux64-13245988487.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 8ad24fba1191c9cb0d2ab36e64b04b4648a99f43 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-windows64-13245988487.tar.zst - - name - windows64 - - - license - LGPL2 - license_file - LICENSES/openal-soft.txt - copyright - Copyright (C) 1999-2007 by authors. - version - 1.24.2-r1 - name - openal - description - OpenAL Soft is a software implementation of the OpenAL 3D audio API. - - openjpeg - - platforms - - darwin64 - - archive - - hash - 8dc190451c5b7af0d72e7ab54f8fbde6dccf79c6 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.4-r1/openjpeg-2.5.4.18754730947-darwin64-18754730947.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 9c89879f81ee0434e1f59c47d74a25958ae08e9e - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.4-r1/openjpeg-2.5.4.18754730947-linux64-18754730947.tar.zst - - name - linux64 - - windows64 - - archive - - hash - b78887212f18ae59dc7961e0e1af781e568bd92c - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openjpeg/releases/download/v2.5.4-r1/openjpeg-2.5.4.18754730947-windows64-18754730947.tar.zst - - name - windows64 - - - license - BSD - license_file - LICENSES/openjpeg.txt - copyright - Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium; Copyright (c) 2002-2007, Professor Benoit Macq; Copyright (c) 2001-2003, David Janssens; Copyright (c) 2002-2003, Yannick Verschueren; Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe; Copyright (c) 2005, Herve Drolon, FreeImage Team; Copyright (c) 2006-2007, Parvatha Elangovan; Copyright (c) 2008, Jerome Fimes, Communications & Systemes <jerome.fimes@c-s.fr>; Copyright (c) 2010-2011, Kaori Hagihara; Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France; Copyright (c) 2012, CS Systemes d'Information, France; - version - 2.5.4.18754730947 - name - openjpeg - description - The OpenJPEG library is an open-source JPEG 2000 codec written in C language. - - openssl - - platforms - - darwin64 - - archive - - hash - e08f640fb423f878c288426c836189b30b0c8ad0 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-darwin64-20981673556.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - d83a1e910762b792c90550ce2b8f51f9aaec7570 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-linux64-20981673556.tar.zst - - name - linux64 - - windows64 - - archive - - hash - eec78c22e2d1eecf375aa0c6eff08fe67d2316f4 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openssl/releases/download/v1.1.1w-r4/openssl-1.1.1w-r4-windows64-20981673556.tar.zst - - name - windows64 - - - license - openssl - license_file - LICENSES/openssl.txt - copyright - Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved; Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - version - 1.1.1w-r4 - name - openssl - description - Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) Library - - openxr - - platforms - - windows64 - - archive - - hash - 3cccc3e3f3137066c286270b35abc00ee0c0bb0c - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-windows64-10710818432.tar.zst - - name - windows64 - - linux64 - - archive - - hash - f0ad0418a98fb8cb6e158fca3902c15ac1de9d2a - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-linux64-10710818432.tar.zst - - name - linux64 - - darwin64 - - archive - - hash - a9bfabec63a987bd34bcfdc295b928bd0696e1d7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-openxr/releases/download/v1.1.40-r1/openxr-1.1.40-r1-darwin64-10710818432.tar.zst - - name - darwin64 - - - license - Apache 2.0 - license_file - LICENSES/openxr.txt - copyright - Copyright 2017-2024, The Khronos Group Inc. - version - 1.1.40-r1 - name - openxr - canonical_repo - https://github.com/secondlife/3p-openxr - description - Generated headers and sources for OpenXR loader. - - slvoice - - platforms - - darwin64 - - archive - - hash - 1e70b06fe6eb9796097010871b32d8e95167e373 - hash_algorithm - sha1 - url - https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-darwin64-5942f08.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 92b0ae08832bd0e99c34ef8f3e6346ad - url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/613/1289/slvoice-3.2.0002.10426.500605-linux64-500605.tar.bz2 - - name - linux64 - - windows64 - - archive - - hash - ddfb7c30d9756915e8b26f44e2ee3a69ee87fb9a - hash_algorithm - sha1 - url - https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-windows64-5942f08.tar.zst - - name - windows64 - - - license - Mixed - license_file - LICENSES/vivox_licenses.txt - copyright - 2010 Vivox, including audio coding using Polycom¨ Siren14TM (ITU-T Rec. G.722.1 Annex C) - version - 4.10.0000.32327.5fc3fe7c.5942f08 - name - slvoice - description - Vivox SDK components - - sse2neon - - platforms - - common - - archive - - hash - e51fb1d24836d897ce90b8a72010635915b959d6 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-sse2neon/releases/download/v1.8.0/sse2neon-1.8.0-common-17657389472.tar.zst - - name - common - - - license - MIT - license_file - LICENSES/sse2neon.txt - copyright - Copyright (c) 2015-2024 SSE2NEON Contributors. - version - 1.8.0 - name - sse2neon - canonical_repo - https://github.com/secondlife/3p-sse2neon - description - A translator from Intel SSE intrinsics to Arm/Aarch64 NEON implementation - - threejs - - platforms - - common - - archive - - hash - 982c0fa427458082ea9e3cb9603904210732b64e - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-three_js/releases/download/v0.132.2-5da28d9/threejs-0.132.2-common-8454371083.tar.zst - - name - common - - - license - MIT - license_file - LICENSES/THREEJS_LICENSE.txt - copyright - Copyright © 2010-2021 three.js authors - version - 0.132.2 - name - threejs - - tinygltf - - platforms - - common - - archive - - hash - 005d23bb2606ae2cc9e844adc1a0edf112c69812 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-tinygltf/releases/download/v2.9.3-r1/tinygltf-2.9.3-r1-common-10341018043.tar.zst - - name - common - - - license - MIT - license_file - LICENSES/tinygltf_license.txt - copyright - // Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many contributors. - version - 2.9.3-r1 - name - tinygltf - canonical_repo - https://bitbucket.org/lindenlab/3p-tinygltf - description - tinygltf import library - source - https://bitbucket.org/lindenlab/3p-tinygltf - source_type - git - - tracy - - platforms - - darwin64 - - archive - - hash - 0c3d01b7e9e39c23f0f40c56a1a04d1fba08ead0 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-tracy/releases/download/v0.11.1-r1/tracy-v0.11.1.11706699176-darwin64-11706699176.tar.zst - - name - darwin64 - - windows64 - - archive - - hash - b46cef5646a8d0471ab6256fe5119220fa238772 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-tracy/releases/download/v0.11.1-r1/tracy-v0.11.1.11706699176-windows64-11706699176.tar.zst - - name - windows64 - - linux64 - - archive - - hash - beab04c9ea6036b1851a485b65c66cf6a38f0be4 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-tracy/releases/download/v0.11.1-r1/tracy-v0.11.1.11706699176-linux64-11706699176.tar.zst - - name - linux64 - - - license - bsd - license_file - LICENSES/tracy_license.txt - copyright - Copyright (c) 2017-2024, Bartosz Taudul (wolf@nereid.pl) - version - v0.11.1.11706699176 - name - tracy - canonical_repo - https://bitbucket.org/lindenlab/3p-tracy - description - Tracy Profiler Library - source - https://bitbucket.org/lindenlab/3p-tracy - source_type - git - - tut - - platforms - - common - - archive - - hash - 9f0bf4545f08df5381e0f39ccce3a57c6ec4b0f4 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-tut/releases/download/v2008.11.30-409bce5/tut-2008.11.30-common-409bce5.tar.zst - - name - common - - - license - bsd - license_file - LICENSES/tut.txt - copyright - Copyright 2002-2006 Vladimir Dyuzhev, Copyright 2007 Denis Kononenko, Copyright 2008-2009 Michał Rzechonek - version - 2008.11.30 - name - tut - description - TUT is a small and portable unit test framework for C++. - - viewer-fonts - - platforms - - common - - archive - - hash - e88a7c97a6843d43e0093388f211299ec2892790 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-viewer-fonts/releases/download/v1.1.0-r1/viewer_fonts-1.0.0.10204976553-common-10204976553.tar.zst - - name - common - - - license - Various open source - license_file - LICENSES/fonts.txt - copyright - Copyright 2016-2022 Brad Erickson CC-BY-4.0/MIT, Copyright 2016-2022 Twitter, Inc. CC-BY-4.0, Copyright 2013 Joe Loughry and Terence Eden MIT - version - 1.0.0.10204976553 - name - viewer-fonts - description - Viewer fonts - - viewer-manager - - platforms - - darwin64 - - archive - - hash - 8a04e6b3c6ff7f645219955a1389035565eb10d8 - hash_algorithm - sha1 - url - https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-darwin64-f14b5ec.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - a1e467c08ecbe6ab24fc8756a815a431a9b00f62 - hash_algorithm - sha1 - url - https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-linux64-f14b5ec.tar.zst - - name - linux64 - - windows64 - - archive - - hash - 56b613decdd36b2a17646bf3e2cfc2fed8456b8c - hash_algorithm - sha1 - url - https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-windows64-f14b5ec.tar.zst - - name - windows64 - - - license - viewerlgpl - license_file - LICENSE - copyright - Copyright (c) 2000-2012, Linden Research, Inc. - version - 3.0-f14b5ec - name - viewer-manager - description - Linden Lab Viewer Management Process suite. - source - https://github.com/secondlife/viewer-manager - source_type - hg - - vlc-bin - - platforms - - darwin64 - - archive - - hash - 6d72afd5cc21446c65899615909b1f09f155585d - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.296d9f4/vlc_bin-3.0.21.11968962952-darwin64-11968962952.tar.zst - - name - darwin64 - - windows64 - - archive - - hash - f986e6e93acf8a32a8be5b638f0bd0e2e07d7507 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.296d9f4/vlc_bin-3.0.21.11968962952-windows64-11968962952.tar.zst - - name - windows64 - - - license - GPL2 - license_file - LICENSES/vlc.txt - copyright - Copyright (C) 1998-2016 VLC authors and VideoLAN - version - 3.0.21.11968962952 - name - vlc-bin - - vulkan_gltf - - platforms - - common - - archive - - hash - 8e365eff8dcace48d91e2530f8b13e420849aefc - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-vulkan-gltf-pbr/releases/download/v1.0.0-d7c372f/vulkan_gltf-1.0.0-common-d7c372f.tar.zst - - name - common - - - license - Copyright (c) 2018 Sascha Willems - license_file - vulkan_gltf.txt - copyright - Copyright (c) 2018 Sascha Willems - version - 1.0.0 - name - vulkan_gltf - canonical_repo - https://bitbucket.org/lindenlab/3p-vulkan-gltf-pbr - description - Vulkan GLTF Sample Implementation - - webrtc - - platforms - - darwin64 - - archive - - hash - a5e72a9d13b6c4646d1e02b5820f16560d204de7 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-darwin64-18609120431.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 1030e5086f401d738463223da3ed99c225340f39 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-linux64-18609120431.tar.zst - - name - linux64 - - windows64 - - archive - - hash - d1cae9bc8866ca01aa9f5e72b36d12ef608b1998 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-windows64-18609120431.tar.zst - - name - windows64 - - - license - MIT - license_file - LICENSES/webrtc-license.txt - copyright - Copyright (c) 2011, The WebRTC project authors. All rights reserved. - version - m137.7151.04.21.18609120431 - name - webrtc - vcs_branch - secondlife - vcs_revision - d3f62d32bac8694d3c7423c731ae30c113bf6a11 - vcs_url - https://github.com/secondlife/3p-webrtc-build - canonical_repo - https://github.com/secondlife/3p-webrtc-build - - xxhash - - platforms - - common - - archive - - hash - fc9362865e33391d55c64d6101726da0a25d924e - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-xxhash/releases/download/v0.8.2-r1/xxhash-0.8.2-10285735820-common-10285735820.tar.zst - - name - common - - - license - xxhash - license_file - LICENSES/xxhash.txt - copyright - Copyright (c) 2012-2021 Yann Collet - version - 0.8.2-10285735820 - name - xxhash - description - xxHash Library - - zlib-ng - - platforms - - darwin64 - - archive - - hash - 4906257288c61b14d2e16116fc3139af35d3374f - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-darwin64-20930307098.tar.zst - - name - darwin64 - - linux64 - - archive - - hash - 2b81a6a4ebd9ae5555d48b52eea7c2d875d68f60 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-linux64-20930307098.tar.zst - - name - linux64 - - windows64 - - archive - - hash - e2e0f964ba44fe2e6428e1e7ca262a3f80d92e65 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.5-0d88d03/zlib_ng-2.2.5-dev0.g0d88d03.d20260112-windows64-20930307098.tar.zst - - name - windows64 - - - license - zlib-ng - license_file - LICENSES/zlib-ng.txt - copyright - Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler - version - 2.2.5-0d88d03 - name - zlib-ng - canonical_repo - https://bitbucket.org/lindenlab/3p-zlib-ng - description - zlib data compression library for the next generation systems - - tinyexr - - platforms - - common - - archive - - hash - a9649f85e20c0b83acfd7b02ca19c1dcdd15f01e - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-tinyexr/releases/download/v1.0.9-5e8947c/tinyexr-1.0.9-5e8947c-common-10475846787.tar.zst - - name - common - - - license - 3-clause BSD - license_file - LICENSES/tinyexr_license.txt - copyright - Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors. - version - 1.0.9-5e8947c - name - tinyexr - vcs_branch - dependabot/github_actions/secondlife/action-autobuild-4 - vcs_revision - 4dc4d1d90d82a22843e2adf5130f9ecb5ee5769e - vcs_url - https://github.com/secondlife/3p-tinyexr - description - tinyexr import library - source_type - git - - discord_sdk - - platforms - - windows64 - - archive - - creds - github - hash - e11571bf76b27d15c244069988ae372eaa5afae9 - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-discord-sdk/releases/assets/279333720 - - name - windows64 - - darwin64 - - archive - - creds - github - hash - dc21df8b051c425163acf3eff8f06e32f407c9e0 - hash_algorithm - sha1 - url - https://api.github.com/repos/secondlife/3p-discord-sdk/releases/assets/279333706 - - name - darwin64 - - - license - discord_sdk - license_file - LICENSES/discord_sdk.txt - copyright - Discord Inc. - version - 1.4.9649.16733550144 - name - discord_sdk - vcs_branch - main - vcs_revision - ef5c7c4a490ceac2df2b2f046788b1daf1bbb392 - vcs_url - https://github.com/secondlife/3p-discord-sdk - canonical_repo - https://github.com/secondlife/3p-discord-sdk - description - Discord Social SDK - - vhacd - - platforms - - common - - archive - - hash - 49046b0b41310d2fb0d72853730b2faad35d3e36 - hash_algorithm - sha1 - url - https://github.com/secondlife/3p-vhacd/releases/download/v4.1.0-r1/vhacd-4.1.0-r1-common-18475951995.tar.zst - - name - common - - - license - BSD - license_file - LICENSES/vhacd.txt - copyright - Copyright (c) 2011, Khaled Mamou - version - 4.1.0-r1 - name - vhacd - description - Voxelized Hierarchical Approximate Convex Decomposition - - - package_description - - platforms - - common - - configurations - - RelWithDebInfo - - configure - - command - cmake - options - - -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE - -DROOT_PROJECT_NAME:STRING=SecondLife - -DINSTALL_PROPRIETARY=TRUE - -DUSE_OPENAL:BOOL=ON - - - build - - - name - RelWithDebInfo - - RelWithDebInfoOS - - configure - - command - cmake - options - - -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo - -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE - -DROOT_PROJECT_NAME:STRING=SecondLife - -DINSTALL_PROPRIETARY=FALSE - - arguments - - ../indra - - - name - RelWithDebInfoOS - - Release - - configure - - command - cmake - options - - -DCMAKE_BUILD_TYPE:STRING=Release - -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE - -DROOT_PROJECT_NAME:STRING=SecondLife - -DINSTALL_PROPRIETARY=TRUE - -DUSE_OPENAL:BOOL=ON - - - build - - - name - Release - - ReleaseOS - - configure - - command - cmake - options - - -DCMAKE_BUILD_TYPE:STRING=Release - -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE - -DROOT_PROJECT_NAME:STRING=SecondLife - -DINSTALL_PROPRIETARY=FALSE - - arguments - - ../indra - - - name - ReleaseOS - - - name - common - - darwin64 - - configurations - - RelWithDebInfo - - configure - - options - - -G - Xcode - - arguments - - ../indra - - - build - - command - cmake - options - - --build - . - --config - RelWithDebInfo - --parallel - $AUTOBUILD_CPU_COUNT - - - default - True - name - RelWithDebInfo - - RelWithDebInfoOS - - configure - - options - - -G - Xcode - - - build - - command - cmake - options - - --build - . - --config - RelWithDebInfo - --parallel - $AUTOBUILD_CPU_COUNT - - - name - RelWithDebInfoOS - - Release - - configure - - options - - -G - Xcode - - arguments - - ../indra - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - name - Release - - ReleaseOS - - configure - - options - - -G - Xcode - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - name - ReleaseOS - - - build_directory - build-darwin-universal - name - darwin64 - - linux64 - - configurations - - RelWithDebInfo - - configure - - options - - -G - Unix Makefiles - - arguments - - ../indra - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - default - True - name - RelWithDebInfo - - RelWithDebInfoOS - - configure - - options - - -G - Ninja - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - name - RelWithDebInfoOS - - Release - - configure - - options - - -G - Unix Makefiles - - arguments - - ../indra - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - name - Release - - ReleaseOS - - configure - - options - - -G - Ninja - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - name - ReleaseOS - - - build_directory - build-linux-x86_64 - name - linux64 - - windows - - configurations - - RelWithDebInfo - - configure - - options - - -G - ${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN} - -A - ${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} - - arguments - - ..\indra - - - build - - command - cmake - options - - --build - . - --config - RelWithDebInfo - --parallel - $AUTOBUILD_CPU_COUNT - - - default - True - name - RelWithDebInfo - - RelWithDebInfoOS - - configure - - options - - -G - ${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN} - -A - ${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} - -DINSTALL_PROPRIETARY=FALSE - -DUSE_KDU=FALSE - -DUSE_OPENAL:BOOL=ON - - arguments - - ..\indra - - - build - - command - cmake - options - - --build - . - --config - RelWithDebInfo - --parallel - $AUTOBUILD_CPU_COUNT - - - name - RelWithDebInfoOS - - Release - - configure - - options - - -G - ${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN} - -A - ${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} - - arguments - - ..\indra - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - name - Release - - ReleaseOS - - configure - - options - - -G - ${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN} - -A - ${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} - -DUNATTENDED:BOOL=ON - -DINSTALL_PROPRIETARY=FALSE - -DUSE_KDU=FALSE - -DUSE_OPENAL:BOOL=ON - - arguments - - ..\indra - - - build - - command - cmake - options - - --build - . - --config - Release - --parallel - $AUTOBUILD_CPU_COUNT - - - name - ReleaseOS - - - build_directory - build-vc${AUTOBUILD_VSVER|170}-$AUTOBUILD_ADDRSIZE - name - windows - - - license - LGPL - license_file - docs/LICENSE-source.txt - copyright - Copyright (c) 2020, Linden Research, Inc. - version_file - newview/viewer_version.txt - name - Second Life Viewer - canonical_repo - https://github.com/secondlife/viewer - description - Second Life Viewer - - - diff --git a/build.sh b/build.sh deleted file mode 100755 index 72dc2b96e8b..00000000000 --- a/build.sh +++ /dev/null @@ -1,587 +0,0 @@ -#!/usr/bin/env bash - -# This is the custom build script for the viewer -# -# It must be run by the Linden Lab build farm shared buildscript because -# it relies on the environment that sets up, functions it provides, and -# the build result post-processing it does. -# -# PLEASE NOTE: -# -# * This script is interpreted on three platforms, including windows and cygwin -# Cygwin can be tricky.... -# * The special style in which python is invoked is intentional to permit -# use of a native python install on windows - which requires paths in DOS form - -cleanup="true" - -retry_cmd() -{ - max_attempts="$1"; shift - initial_wait="$1"; shift - attempt_num=1 - echo "trying" "$@" - until "$@" - do - if ((attempt_num==max_attempts)) - then - echo "Last attempt $attempt_num failed" - return 1 - else - wait_time=$(($attempt_num*$initial_wait)) - echo "Attempt $attempt_num failed. Trying again in $wait_time seconds..." - sleep $wait_time - attempt_num=$(($attempt_num+1)) - fi - done - echo "succeeded" - return 0 -} - -build_dir_Darwin() -{ - echo build-darwin-universal -} - -build_dir_Linux() -{ - echo build-linux-x86_64 -} - -build_dir_CYGWIN() -{ - echo build-vc${AUTOBUILD_VSVER:-120}-${AUTOBUILD_ADDRSIZE} -} - -viewer_channel_suffix() -{ - local package_name="$1" - local suffix_var="${package_name}_viewer_channel_suffix" - local suffix=$(eval "echo \$${suffix_var}") - if [ "$suffix"x = ""x ] - then - echo "" - else - echo "_$suffix" - fi -} - -installer_Darwin() -{ - local package_name="$1" - local package_dir="$(build_dir_Darwin)/newview/" - local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_universal\\.dmg\$" - # since the additional packages are built after the base package, - # sorting oldest first ensures that the unqualified package is returned - # even if someone makes a qualified name that duplicates the last word of the base name - local package=$(ls -1tr "$package_dir" 2>/dev/null | grep -E "$pattern" | head -n 1) - test "$package"x != ""x && echo "$package_dir/$package" -} - -installer_Linux() -{ - local package_name="$1" - local package_dir="$(build_dir_Linux)/newview/" - local pattern=".*$(viewer_channel_suffix ${package_name})_[0-9]+_[0-9]+_[0-9]+_[0-9]+_i686\\.tar\\.xz\$" - # since the additional packages are built after the base package, - # sorting oldest first ensures that the unqualified package is returned - # even if someone makes a qualified name that duplicates the last word of the base name - package=$(ls -1tr "$package_dir" 2>/dev/null | grep -E "$pattern" | head -n 1) - test "$package"x != ""x && echo "$package_dir/$package" -} - -installer_CYGWIN() -{ - local package_name="$1" - local variant=${last_built_variant:-Release} - local build_dir=$(build_dir_CYGWIN ${variant}) - local package_dir - if [ "$package_name"x = ""x ] - then - package_dir="${build_dir}/newview/${variant}" - else - package_dir="${build_dir}/newview/${package_name}/${variant}" - fi - if [ -r "${package_dir}/touched.bat" ] - then - local package_file=$(sed 's:.*=::' "${package_dir}/touched.bat") - echo "${package_dir}/${package_file}" - fi -} - -# if someone wants to run build.sh outside the GitHub environment -[[ -n "$GITHUB_OUTPUT" ]] || export GITHUB_OUTPUT='/dev/null' -# The following is based on the Warning for GitHub multiline output strings: -# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings -EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) - -# Build up these arrays as we go -metadata=() -symbolfile=() -physicstpv=() -appearanceutility=() -# and dump them to GITHUB_OUTPUT when done -cleanup="$cleanup ; \ -arrayoutput metadata ; \ -arrayoutput symbolfile ; \ -arrayoutput physicstpv ; \ -arrayoutput appearanceutility" -trap "$cleanup" EXIT - -arrayoutput() -{ - local outputname="$1" - # append "[*]" to the array name so array indirection works - local array="$1[*]" - local IFS=' -' - echo "$outputname<<$EOF -${!array} -$EOF" >> "$GITHUB_OUTPUT" -} - -pre_build() -{ - local variant="$1" - begin_section "Configure $variant" - [ -n "$master_message_template_checkout" ] \ - && [ -r "$master_message_template_checkout/message_template.msg" ] \ - && template_verifier_master_url="-DTEMPLATE_VERIFIER_MASTER_URL=file://$master_message_template_checkout/message_template.msg" - - RELEASE_CRASH_REPORTING=OFF - HAVOK=OFF - TESTING=OFF - SIGNING=() - if [[ "$variant" != *OS ]] - then - # Proprietary builds - - RELEASE_CRASH_REPORTING=ON - HAVOK=ON - - if [[ "$arch" == "Darwin" ]] - then - SIGNING=("-DENABLE_SIGNING:BOOL=YES" \ - "-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.") - fi - fi - - if [[ "$arch" == "Linux" ]] - then - # RELEASE_CRASH_REPORTING is tuned on unconditionaly, this is fine but not for Linux as of now (due to missing breakpad/crashpad support) - RELEASE_CRASH_REPORTING=OFF - fi - - if $build_tests - then - TESTING=ON - fi - - if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] - then - case "$arch" in - CYGWIN) - symplat="windows" - ;; - Darwin) - symplat="darwin" - ;; - Linux) - symplat="linux" - ;; - esac - # This name is consumed by indra/newview/CMakeLists.txt. Make it - # absolute because we've had troubles with relative pathnames. - abs_build_dir="$(cd "$build_dir"; pwd)" - VIEWER_SYMBOL_FILE="$(native_path "$abs_build_dir/symbols/$variant/${viewer_channel}.sym.tar.xz")" - fi - - # honor autobuild_configure_parameters same as sling-buildscripts - eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters)) - - "$autobuild" configure --quiet -c $variant \ - ${eval_autobuild_configure_parameters:---} \ - -DLL_TESTS:BOOL="$TESTING" \ - -DPACKAGE:BOOL=ON \ - -DHAVOK:BOOL="$HAVOK" \ - -DRELEASE_CRASH_REPORTING:BOOL="$RELEASE_CRASH_REPORTING" \ - -DVIEWER_SYMBOL_FILE:STRING="${VIEWER_SYMBOL_FILE:-}" \ - -DBUGSPLAT_DB:STRING="${BUGSPLAT_DB:-}" \ - -DVIEWER_CHANNEL:STRING="${viewer_channel}" \ - -DGRID:STRING="\"$viewer_grid\"" \ - -DTEMPLATE_VERIFIER_OPTIONS:STRING="$template_verifier_options" $template_verifier_master_url \ - "${SIGNING[@]}" \ - || fatal "$variant configuration failed" - - end_section "Configure $variant" -} - -package_llphysicsextensions_tpv() -{ - begin_section "PhysicsExtensions_TPV" - tpv_status=0 - # nat 2016-12-21: without HAVOK, can't build PhysicsExtensions_TPV. - if [ "$variant" = "Release" -a "${HAVOK:-}" != "OFF" ] - then - tpvconfig="$build_dir/packages/llphysicsextensions/autobuild-tpv.xml" - test -r "$tpvconfig" || fatal "No llphysicsextensions_tpv autobuild configuration found" - # SL-19942: autobuild ignores -c switch if AUTOBUILD_CONFIGURATION set - unset AUTOBUILD_CONFIGURATION - "$autobuild" build --quiet --config-file "$(native_path "$tpvconfig")" -c Tpv \ - || fatal "failed to build llphysicsextensions_tpv" - - # capture the package file name for use in upload later... - PKGTMP=`mktemp -t pgktpv.XXXXXX` - cleanup="$cleanup ; rm $PKGTMP* 2>/dev/null" - trap "$cleanup" EXIT - "$autobuild" package --quiet --config-file "$tpvconfig" --results-file "$(native_path $PKGTMP)" || fatal "failed to package llphysicsextensions_tpv" - tpv_status=$? - if [ -r "${PKGTMP}" ] - then - . "${PKGTMP}" # sets autobuild_package_{name,filename,md5} - echo "${autobuild_package_filename}" > $build_dir/llphysicsextensions_package - fi - else - record_event "Do not provide llphysicsextensions_tpv for $variant" - llphysicsextensions_package="" - fi - end_section "PhysicsExtensions_TPV" - return $tpv_status -} - -build() -{ - local variant="$1" - if $build_tests - then - begin_section "autobuild $variant tests" - # honor autobuild_build_parameters same as sling-buildscripts - export CTEST_OUTPUT_ON_FAILURE=1 # Output log on test failure - eval_autobuild_build_parameters=$(eval $(echo echo $autobuild_build_parameters)) - "$autobuild" build --no-configure -c $variant \ - $eval_autobuild_build_parameters -- --target BUILD_AND_RUN_TESTS \ - || fatal "failed building $variant tests" - echo true >"$build_dir"/build_ok - end_section "autobuild $variant tests" - elif $build_viewer - then - begin_section "autobuild $variant" - # honor autobuild_build_parameters same as sling-buildscripts - eval_autobuild_build_parameters=$(eval $(echo echo $autobuild_build_parameters)) - "$autobuild" build --no-configure -c $variant \ - $eval_autobuild_build_parameters \ - || fatal "failed building $variant" - echo true >"$build_dir"/build_ok - end_section "autobuild $variant" - - begin_section "extensions $variant" - # Run build extensions - if [ -d ${build_dir}/packages/build-extensions ] - then - for extension in ${build_dir}/packages/build-extensions/*.sh - do - begin_section "Extension $extension" - . $extension - end_section "Extension $extension" - done - fi - - # *TODO: Make this a build extension. disabled for now - # package_llphysicsextensions_tpv || fatal "failed building llphysicsextensions packages" - end_section "extensions $variant" - - else - record_event "Skipping build due to configuration build_viewer=${build_viewer}" - echo true >"$build_dir"/build_ok - fi -} - -################################################################ -# Start of the actual script -################################################################ - -# Check to see if we were invoked from the master buildscripts wrapper, if not, fail -if [ "x${BUILDSCRIPTS_SUPPORT_FUNCTIONS}" = x ] -then - echo "This script relies on being run by the master Linden Lab buildscripts" 1>&2 - exit 1 -fi - -shopt -s nullglob # if nothing matches a glob, expand to nothing - -initialize_build # provided by master buildscripts build.sh - -begin_section "autobuild initialize" -# ensure AUTOBUILD is in native path form for child processes -AUTOBUILD="$(native_path "$AUTOBUILD")" -# set "$autobuild" to cygwin path form for use locally in this script -autobuild="$(shell_path "$AUTOBUILD")" -if [ ! -x "$autobuild" ] -then - record_failure "AUTOBUILD not executable: '$autobuild'" - exit 1 -fi - -# load autobuild provided shell functions and variables -"$autobuild" --quiet source_environment > "$build_log_dir/source_environment" -PYTHONPATH="$BUILDSCRIPTS_SHARED/packages/lib/python:$PYTHONPATH" -begin_section "dump source environment commands" -cat "$build_log_dir/source_environment" -end_section "dump source environment commands" - -begin_section "execute source environment commands" -. "$build_log_dir/source_environment" -end_section "execute source environment commands" - -end_section "autobuild initialize" - -# something about the additional_packages mechanism messes up buildscripts results.py on Linux -# since we don't care about those packages on Linux, just zero it out, yes - a HACK -if [ "$arch" = "Linux" ] -then - export additional_packages= -fi - -begin_section "select viewer channel" -# Look for a branch-specific viewer_channel setting -# changeset_branch is set in the sling-buildscripts -viewer_build_branch=$(echo -n "${changeset_branch:-$(repo_branch ${BUILDSCRIPTS_SRC:-$(pwd)})}" | tr -Cs 'A-Za-z0-9_' '_' | sed -E 's/^_+//; s/_+$//') -if [ -n "$viewer_build_branch" ] -then - branch_viewer_channel_var="${viewer_build_branch}_viewer_channel" - if [ -n "${!branch_viewer_channel_var}" ] - then - viewer_channel="${!branch_viewer_channel_var}" - record_event "Overriding viewer_channel for branch '$changeset_branch' to '$viewer_channel'" - else - record_event "No branch-specific viewer_channel for branch '$viewer_build_branch'; to set a branch build channel set '$branch_viewer_channel_var'" - fi -fi -end_section "select viewer channel" - -python_cmd "$helpers/codeticket.py" addinput "Viewer Channel" "${viewer_channel}" - -initialize_version # provided by buildscripts build.sh; sets version id - -begin_section "coding policy check" -# On our TC Windows build hosts, the GitPython library underlying our -# coding_policy_git.py script fails to run git for reasons we have not tried -# to diagnose. Clearly git works fine on those hosts, or we would never get -# this far. Running coding policy checks on one platform *should* suffice... -if [[ "$arch" == "Darwin" ]] -then - git_hooks_reqs="$git_hooks_checkout/requirements.txt" - if [[ -r "$(shell_path "$git_hooks_reqs")" ]] - then - # install the git-hooks dependencies - pip install -r "$(native_path "$git_hooks_reqs")" || \ - fatal "pip install git-hooks failed" - fi - git_hooks_script="$git_hooks_checkout/coding_policy_git.py" - if [[ -r "$(shell_path "$git_hooks_script")" ]] - then - # validate the branch we're about to build - python_cmd "$(native_path "$git_hooks_script")" --all_files || \ - fatal "coding policy check failed" - fi -fi -end_section "coding policy check" - -# Now run the build -succeeded=true -last_built_variant= -for variant in $variants -do - # Only the last built arch is available for upload - last_built_variant="$variant" - - build_dir=`build_dir_$arch $variant` - - begin_section "Initialize $variant Build Directory" - rm -rf "$build_dir" - mkdir -p "$build_dir/tmp" - end_section "Initialize $variant Build Directory" - - if pre_build "$variant" "$build_dir" - then - begin_section "Build $variant" - build "$variant" "$build_dir" - end_section "Build $variant" - - begin_section "post-build $variant" - if `cat "$build_dir/build_ok"` - then - case "$variant" in - Release*) - if [ -r "$build_dir/autobuild-package.xml" ] - then - begin_section "Autobuild metadata" - python_cmd "$helpers/codeticket.py" addoutput "Autobuild Metadata" "$build_dir/autobuild-package.xml" --mimetype text/xml \ - || fatal "Upload of autobuild metadata failed" - metadata+=("$build_dir/autobuild-package.xml") - record_dependencies_graph "$build_dir/autobuild-package.xml" # defined in buildscripts/hg/bin/build.sh - end_section "Autobuild metadata" - else - record_event "no autobuild metadata at '$build_dir/autobuild-package.xml'" - fi - if [ -r "$build_dir/newview/viewer_version.txt" ] - then - begin_section "Viewer Version" - viewer_version="$(<"$build_dir/newview/viewer_version.txt")" - python_cmd "$helpers/codeticket.py" addoutput "Viewer Version" "$viewer_version" --mimetype inline-text \ - || fatal "Upload of viewer version failed" - metadata+=("$build_dir/newview/viewer_version.txt") - echo "viewer_version=$viewer_version" >> "$GITHUB_OUTPUT" - end_section "Viewer Version" - fi - ;; - Doxygen) - if [ -r "$build_dir/doxygen_warnings.log" ] - then - record_event "Doxygen warnings generated; see doxygen_warnings.log" - python_cmd "$helpers/codeticket.py" addoutput "Doxygen Log" "$build_dir/doxygen_warnings.log" --mimetype text/plain ## TBD - metadata+=("$build_dir/doxygen_warnings.log") - fi - if [ -d "$build_dir/doxygen/html" ] - then - tar -cJf "$build_dir/viewer-doxygen.tar.xz" --strip-components 3 "$build_dir/doxygen/html" - python_cmd "$helpers/codeticket.py" addoutput "Doxygen Tarball" "$build_dir/viewer-doxygen.tar.xz" \ - || fatal "Upload of doxygen tarball failed" - metadata+=("$build_dir/viewer-doxygen.tar.xz") - fi - ;; - *) - ;; - esac - - else - record_failure "Build of \"$variant\" failed." - fi - end_section "post-build $variant" - - else - record_event "configure for $variant failed: build skipped" - fi - - if ! $succeeded - then - record_event "remaining variants skipped due to $variant failure" - break - fi -done - -# build debian package -if [ "$arch" == "Linux" ] -then - if $succeeded - then - if $build_viewer_deb && [ "$last_built_variant" == "Release" ] - then - begin_section "Build Viewer Debian Package" - - # mangle the changelog - dch --force-bad-version \ - --distribution unstable \ - --newversion "${VIEWER_VERSION}" \ - "Automated build #$build_id, repository $branch revision $revision." - - # build the debian package - $pkg_default_debuild_command || record_failure "\"$pkg_default_debuild_command\" failed." - - # Unmangle the changelog file - hg revert debian/changelog - - end_section "Build Viewer Debian Package" - - # Run debian extensions - if [ -d ${build_dir}/packages/debian-extensions ]; then - for extension in ${build_dir}/packages/debian-extensions/*.sh; do - . $extension - done - fi - # Move any .deb results. - mkdir -p ../packages_public - mkdir -p ../packages_private - mv ${build_dir}/packages/*.deb ../packages_public 2>/dev/null || true - mv ${build_dir}/packages/packages_private/*.deb ../packages_private 2>/dev/null || true - - # upload debian package and create repository - begin_section "Upload Debian Repository" - for deb_file in `/bin/ls ../packages_public/*.deb ../*.deb 2>/dev/null`; do - deb_pkg=$(basename "$deb_file" | sed 's,_.*,,') - python_cmd "$helpers/codeticket.py" addoutput "Debian $deb_pkg" $deb_file \ - || fatal "Upload of debian $deb_pkg failed" - done - for deb_file in `/bin/ls ../packages_private/*.deb 2>/dev/null`; do - deb_pkg=$(basename "$deb_file" | sed 's,_.*,,') - python_cmd "$helpers/codeticket.py" addoutput "Debian $deb_pkg" "$deb_file" --private \ - || fatal "Upload of debian $deb_pkg failed" - done - - create_deb_repo - - # Rename the local debian_repo* directories so that the master buildscript - # doesn't make a remote repo again. - for debian_repo_type in debian_repo debian_repo_private; do - if [ -d "$build_log_dir/$debian_repo_type" ]; then - mv $build_log_dir/$debian_repo_type $build_log_dir/${debian_repo_type}_pushed - fi - done - end_section "Upload Debian Repository" - - else - record_event "debian build not enabled" - fi - else - record_event "skipping debian build due to failed build" - fi -fi - -# check status and upload results to S3 -if $succeeded -then - if $build_viewer - then - begin_section "Uploads" - # nat 2016-12-22: without RELEASE_CRASH_REPORTING, we have no symbol file. - if [ "${RELEASE_CRASH_REPORTING:-}" != "OFF" ] - then - # e.g. build-darwin-x86_64/symbols/Release/Second Life Test.xarchive.zip - symbol_file="${build_dir}/symbols/${variant}/${viewer_channel}.xcarchive.zip" - if [[ ! -f "$symbol_file" ]] - then - # symbol tarball we prep for (e.g.) Breakpad - symbol_file="$VIEWER_SYMBOL_FILE" - fi - # Upload crash reporter file - symbolfile+=("$symbol_file") - fi - - # Upload our apperance utility packages for linux - if [ "$arch" == "Linux" ] - then - appearance_utility_dir="${build_dir}/llappearanceutility" - appearanceutility+=("${appearance_utility_dir}/appearance-utility-bin") - appearanceutility+=("${appearance_utility_dir}/appearance-utility-headless-bin") - fi - - # Upload the llphysicsextensions_tpv package, if one was produced - # Only upload this package when building the private repo so the - # artifact is private. - if [[ "x$GITHUB_REPOSITORY" == "xsecondlife/viewer-private" && \ - -r "$build_dir/llphysicsextensions_package" ]] - then - llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) - physicstpv+=("$llphysicsextensions_package") - fi - end_section "Uploads" - else - record_event "skipping upload of installer" - fi - -else - record_event "skipping upload of installer due to failed build" -fi - -# The branch independent build.sh script invoking this script will finish processing -$succeeded || exit 1 diff --git a/buildscripts_support_functions b/buildscripts_support_functions deleted file mode 100644 index 557d2f80fbe..00000000000 --- a/buildscripts_support_functions +++ /dev/null @@ -1,60 +0,0 @@ -# standalone functions from sling-buildscripts - -set_build_number_to_revision() -{ - record_event "buildNumber $revision" -} - -record_event() -{ - echo "=== $@" -} - -begin_section() -{ - record_event "START $*" - sections+=("$*") -} - -end_section() -{ - # accommodate dumb Mac bash 3, which doesn't understand array[-1] - local last=$(( ${#sections[@]} - 1 )) - record_event "END ${*:-${sections[$last]}}" - unset "sections[$last]" -} - -record_success() -{ - record_event "SUCCESS $*" -} - -record_failure() -{ - record_event "FAILURE $*" >&2 -} - -fatal() -{ - record_failure "$@" - finalize false - exit 1 -} - -# redefined fail for backward compatibility -alias fail=fatal - -pass() -{ - exit 0 -} - -export -f set_build_number_to_revision -export -f record_event -export -f begin_section -export -f end_section -export -f record_success -export -f record_failure -export -f fatal -export -f pass -export sections diff --git a/doc/BUILD.LINUX.md b/doc/BUILD.LINUX.md index 09acfafaec4..fb0cdf0674d 100644 --- a/doc/BUILD.LINUX.md +++ b/doc/BUILD.LINUX.md @@ -2,25 +2,66 @@ ## Install Dependencies -### AlmaLinux 10 +
+Arch + ``` -sudo dnf group install "Development Tools" -sudo dnf install cmake fontconfig-devel git glib2-devel gstreamer1-devel gstreamer1-plugins-base-devel libX11-devel mesa-libOSMesa-devel libglvnd-devel ninja-build python3 vlc-devel wayland-devel +sudo pacman -Syu automake autoconf base-devel cmake fontconfig git glib2-devel gstreamer gst-plugins-base-libs ninja libglvnd libvlc libx11 pkgconf python wayland +``` + +
+ +
+Debian + +#### Debian 12+ + +``` +sudo apt install \ +autoconf autoconf-archive automake bison build-essential cmake curl flex gettext \ +libasound2-dev libaudio-dev libdbus-1-dev libdbus-1-dev libdecor-0-dev libdrm-dev \ +libegl1-mesa-dev libfribidi-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ +libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libibus-1.0-dev libjack-dev \ +libosmesa6-dev libpipewire-0.3-dev libpulse-dev libsndio-dev libtext-unidecode-perl \ +libthai-dev libtool libudev-dev libunwind-dev liburing-dev libvlc-dev libwayland-dev \ +libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxft-dev libxi-dev libxinerama-dev \ +libxkbcommon-dev libxrandr-dev libxss-dev libxtst-dev linux-libc-dev ninja-build \ +pkgconf tar tex-common texinfo unzip zip ``` -> [!NOTE] -> You may need to enable the EPEL repository for some packages `sudo dnf install epel-release` -### Arch +
+ +
+Ubuntu + +#### Ubuntu 22.04+ ``` -sudo pacman -Syu base-devel cmake fontconfig git glib2-devel gstreamer gst-plugins-base-libs ninja libglvnd libvlc libx11 python wayland +sudo apt install \ +autoconf autoconf-archive automake bison build-essential cmake curl flex gettext \ +libasound2-dev libaudio-dev libdbus-1-dev libdbus-1-dev libdecor-0-dev libdrm-dev \ +libegl1-mesa-dev libfribidi-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \ +libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libibus-1.0-dev libjack-dev \ +libosmesa6-dev libpipewire-0.3-dev libpulse-dev libsndio-dev libtext-unidecode-perl \ +libthai-dev libtool libudev-dev libunwind-dev liburing-dev libvlc-dev libwayland-dev \ +libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxft-dev libxi-dev libxinerama-dev \ +libxkbcommon-dev libxrandr-dev libxss-dev libxtst-dev linux-libc-dev ninja-build \ +pkgconf tar tex-common texinfo unzip zip ``` -### Debian - Ubuntu 22.04 - Ubuntu 24.04 +
+ +
+Fedora/RHEL + +#### AlmaLinux 10 ``` -sudo apt install build-essential cmake git libfontconfig-dev libglib2.0-dev libglvnd-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libosmesa6-dev libvlc-dev libwayland-dev libx11-dev ninja-build python3 python3-venv +sudo dnf group install "Development Tools" +sudo dnf install cmake fontconfig-devel git glib2-devel gstreamer1-devel gstreamer1-plugins-base-devel libX11-devel mesa-libOSMesa-devel libglvnd-devel ninja-build python3 vlc-devel wayland-devel ``` +> [!NOTE] +> You may need to enable the EPEL repository for some packages `sudo dnf install epel-release` -### Fedora +#### Fedora 44+ ``` sudo dnf install @development-tools @c-development cmake fontconfig-devel git glib-devel gstreamer1-devel gstreamer1-plugins-base-devel libX11-devel mesa-compat-libOSMesa-devel libglvnd-devel ninja-build python3 vlc-devel wayland-devel ``` @@ -30,58 +71,83 @@ To build with clang instead of gcc, also install: sudo dnf install clang lld ``` -### OpenSUSE Tumbleweed +
+ +
+OpenSUSE + +#### Tumbleweed ``` sudo zypper in -t pattern devel_basis devel_C_C++ sudo zypper install cmake fontconfig-devel git glib2-devel gstreamer-devel gstreamer-plugins-base-devel libglvnd-devel libX11-devel ninja Mesa-libGL-devel python3 vlc-devel wayland-devel ``` +
+ ## Create development folders ``` mkdir -p ~/code/secondlife cd ~/code/secondlife ``` -## Setup Virtual Environment and install Autobuild +## Checkout viewer code ``` -python3 -m venv .venv -source .venv/bin/activate -pip install autobuild llsd +git clone https://github.com/secondlife/viewer.git +cd ~/code/secondlife/viewer ``` -> [!NOTE] -> If the above was successful you should receive output similar to `autobuild 3.10.2` when running `autobuild --version` -## Setup Build Variables +## Setup Virtual Environment and Python dependencies ``` -git clone https://github.com/secondlife/build-variables.git -export AUTOBUILD_VARIABLES_FILE=~/code/secondlife/build-variables/variables +python3 -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt ``` -## Clone Viewer -``` -git clone https://github.com/secondlife/viewer.git -cd ~/code/secondlife/viewer -``` +## Configure and install vcpkg dependencies +Switch to the viewer repository you just checked out and run cmake to configure: -## Configure Viewer ### GCC ``` -autobuild configure -c ReleaseOS -A64 +cmake -S indra --preset ninja-os ``` ### Clang (faster build; less stable) ``` -autobuild configure -c ReleaseOS -- -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=LLD +cmake -S indra --preset ninja-os -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_LINKER_TYPE=LLD ``` +> [!TIP] +> If you encounter errors due to cmake being out of date you can fetch it from pip! +> +> `pip install --upgrade cmake ninja` + +The --preset argument determines which build configuration to create, generally either an individual build configuration or a multi-config generator such as Ninja. + +To list availiable presets: + +```cmake -S indra --list-presets``` + + +For the Linden viewer build, this usage: + +```cmake -S indra --preset ninja-os [other options]...``` + +passes [other options] to CMake. This can be used to override different CMake variables, e.g.: + +```cmake -S indra --preset ninja-os -DSOME_VARIABLE:BOOL=TRUE``` + +The set of applicable CMake variables is still evolving. Please consult the CMake source files in indra/cmake, as well as the individual CMakeLists.txt files in the indra directory tree, to learn their effects. + ## Build Viewer +Now switch to the `indra` directory and run the following command: + ``` -autobuild build -c ReleaseOS --no-configure +cmake --build --preset ninja-os-release ``` > [!NOTE] -> If the above was successful you should find the viewer package in `viewer/build-linux-x86_64/newview` +> If the above was successful you should find the viewer package in `viewer/build-Linux-ninja-os/newview/Release` -### Troubleshooting -- If you encounter warnings, try adding `-- -DGCC_DISABLE_FATAL_WARNINGS=TRUE` or `-DCLANG_DISABLE_FATAL_WARNINGS=TRUE` to the configure command +## Troubleshooting +- If you encounter warnings, try adding `-DGCC_DISABLE_FATAL_WARNINGS=TRUE` or `-DCLANG_DISABLE_FATAL_WARNINGS=TRUE` to the configure command diff --git a/doc/BUILD.MAC.md b/doc/BUILD.MAC.md new file mode 100644 index 00000000000..69b6f21d5a7 --- /dev/null +++ b/doc/BUILD.MAC.md @@ -0,0 +1,78 @@ +# Building on macOS + +## Step 1: Install Dependencies and Tools + +### Install Xcode and Homebrew + +* [Xcode](https://developer.apple.com/xcode/) +* [Homebrew](https://brew.sh/) + +### Install Homebrew dependencies + +Now we're going to install required build tools from Homebrew. + +``` +brew install git cmake zip unzip curl pkgconf automake autoconf autoconf-archive gettext libtool +``` + +## Step 2: Checkout Viewer Code +Open a Terminal and checkout the viewer source code: + +```git clone https://github.com/secondlife/viewer.git``` + +## Step 3: Setup Virtual Environment and Python dependencies +``` +cd viewer +python3 -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +## Step 4: Configure and install vcpkg dependencies +Switch to the viewer repository you just checked out and run cmake to configure: + +``` +cmake -S indra --preset xcode-os +``` + +The --preset argument determines which build configuration to create, generally either an individual build configuration or a multi-config IDE such as Visual Studio or Xcode. + +To list availiable presets: + +```cmake -S indra --list-presets``` + + +For the Linden viewer build, this usage: + +```cmake -S indra --preset xcode-os [other options]...``` + +passes [other options] to CMake. This can be used to override different CMake variables, e.g.: + +```cmake -S indra --preset xcode-os -DSOME_VARIABLE:BOOL=TRUE``` + +The set of applicable CMake variables is still evolving. Please consult the CMake source files in indra/cmake, as well as the individual CMakeLists.txt files in the indra directory tree, to learn their effects. + +## Step 5: Build +When that completes, you can either build within Xcode or from the Terminal: + +### Xcode: +The command below will open the generated xcodeproj in Xcode + +``` +open ./build-Darwin-xcode-os/SecondLife.xcodeproj +``` + +### Terminal: +Build by running the following command: + +``` +cmake --build build-Darwin-xcode-os --config Release +``` + +the resulting viewer executable will be at: + +``` +build-Darwin-xcode-os/newview//SecondLife.app +``` + + diff --git a/doc/BUILD.WINDOWS.md b/doc/BUILD.WINDOWS.md new file mode 100644 index 00000000000..186df1affb1 --- /dev/null +++ b/doc/BUILD.WINDOWS.md @@ -0,0 +1,82 @@ +# Building on Windows + +## Step 1: Install Build Tools + +* [CMake](https://cmake.org/download/) +* [Git for Windows](https://git-scm.com/install/windows) +* [Visual Studio 2022 or 2026](https://visualstudio.microsoft.com/vs/community/) - Select "Desktop development with C++" workload +* [Python 3.10+](https://www.python.org/downloads/) - Be sure to "Add Python to PATH" + +### Intermediate Check + +Confirm things are installed properly so far by typing the following in a Terminal: + +``` +cmake --version +python --version +git --version +``` + +If everything reported sensible values and not "Command not found" errors, then you are in good shape! + +## Step 2: Checkout Viewer Code +Open a `Powershell` from the `Start Menu` and checkout the viewer source code: + +```git clone https://github.com/secondlife/viewer.git``` + +## Step 3: Setup Virtual Environment and Python dependencies +``` +cd viewer +python3 -m venv .venv +.\.venv\Scripts\Activate.ps1 +pip install -r requirements.txt +``` + +## Step 4: Configure and install vcpkg dependencies +Switch to the viewer repository you just checked out and run cmake to configure and install dependencies: + +``` +cmake -S indra --preset vs2022-os +``` + +The --preset argument determines which build configuration to create, generally either an individual build configuration or a multi-config IDE such as Visual Studio. + +To list availiable presets: + +```cmake -S indra --list-presets``` + + +For the Linden viewer build, this usage: + +```cmake -S indra --preset vs2022-os [other options]...``` + +passes [other options] to CMake. This can be used to override different CMake variables, e.g.: + +```cmake -S indra --preset vs2022-os -DSOME_VARIABLE:BOOL=TRUE``` + +The set of applicable CMake variables is still evolving. Please consult the CMake source files in indra/cmake, as well as the individual CMakeLists.txt files in the indra directory tree, to learn their effects. + +## Step 5: Build +When that completes, you can either build within Visual Studio or from the command line: + +### Visual Studio: +The command below will open the generated solution in Visual Studio + +``` +explorer.exe .\build-Windows-vs2022-os\SecondLife.sln +``` + +### Command Line: +Build by running: + +``` +cmake --build build-Windows-vs2022-os --config Release +``` + +the resulting viewer executable will be at: + +``` +build-Windows-vs2022-os/newview//SecondLifeViewer.exe +``` + + diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 61a2916bdb5..e65e89b6c1e 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -3,60 +3,181 @@ # cmake_minimum_required should appear before any # other commands to guarantee full compatibility # with the version specified -## 3.8 added VS_DEBUGGER_WORKING_DIRECTORY support -## 3.13/12 is needed for add_link_options/add_compile_definitions -## 3.14 added FILE CREATE_LINK -## 3.16 is needed for target_precompile_headers -## Nicky: Ideally we want at least 3.21 for good preset support -## We're not there yet, but once done, there is a kludge in Linking.cmake -# "if(${CMAKE_VERSION} VERSION_LESS "3.20.0")" that can also be removed -cmake_minimum_required(VERSION 3.16.0...4.0 FATAL_ERROR) -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.29.0") - cmake_policy(SET CMP0156 NEW) -endif() -if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.31.0") - cmake_policy(SET CMP0179 NEW) -endif() +# 3.27 is our minimum required cmake version while 4.2 is our cmake policy max version(meaning any policies of version 4.2 or below are set to NEW) +cmake_minimum_required(VERSION 3.27...4.2 FATAL_ERROR) + +include(CMakeDependentOption) set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING "The root project/makefile/solution name. Defaults to SecondLife.") -project(${ROOT_PROJECT_NAME}) -set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_CURRENT_BINARY_DIR}") - -include(conanbuildinfo OPTIONAL RESULT_VARIABLE USE_CONAN ) -if( USE_CONAN ) - set( USE_CONAN ON ) - set( USE_AUTOBUILD_3P OFF ) - conan_basic_setup(TARGETS NO_OUTPUT_DIRS) - add_compile_definitions(LL_USESYSTEMLIBS USE_CONAN NO_AUTOBUILD_3P) -else() - set( USE_CONAN OFF ) - set( USE_AUTOBUILD_3P ON ) -endif() +# Set our base channel +set(VIEWER_CHANNEL "Second Life Test" CACHE STRING "Viewer Channel Name") -if (NOT DEFINED CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 20) -endif() -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # This slows down build massively +# Default deploy grid +set(GRID agni CACHE STRING "Target Grid") -set(CMAKE_OPTIMIZE_DEPENDENCIES ON) +# Build executable options +option(BUILD_VIEWER "Build the viewer project" ON) +option(BUILD_APPEARANCE_UTIL "Build the appearance utility project" OFF) +option(BUILD_TESTING "Build and run unit and integration tests: disable for build timing runs to reduce variation" OFF) -set(CMAKE_COLOR_DIAGNOSTICS ON) +# Plugin Build Options +option(BUILD_EXAMPLE_PLUGIN "Build support for SLPlugin example plugin" ON) +option(BUILD_CEF_PLUGIN "Build support for SLPlugin CEF web plugin." ON) +option(BUILD_VLC_PLUGIN "Build support for SLPlugin VLC media plugin." ON) +cmake_dependent_option(BUILD_GSTREAMER_PLUGIN "Build support for SLPlugin Gstreamer media plugin." ON "UNIX;NOT APPLE" OFF) -# Speeds up cmake generation significantly in some cases -set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON) +# Build feature and optimization options +option(OS_DRAG_DROP "Build the viewer with OS level drag and drop support" ON) +option(USE_NDOF "Use NDOF space navigator joystick library." ON) +option(USE_LTO "Enable Link Time Optimization" OFF) +option(USE_NVAPI "Use NVidia NVAPI library for gpu profile support (Windows Only)" ON) +option(USE_OPENAL "Enable support for the OpenAL audio engine" ON) +option(USE_OPENXR "Enable building with OpenXR support (Experimental)" OFF) +option(USE_PRECOMPILED_HEADERS "Enable use of precompiled header directives where supported." ON) -include(Variables) -include(BuildVersion) +# SIMD Options (x86_64 only) +option(USE_SSE4_2 "Use SSE4.2/x86-64-v2 instruction sets (x86_64 only)" OFF) +option(USE_AVX "Use AVX/x86-64-v2+avx instruction sets (x86_64 only)" OFF) +option(USE_AVX2 "Use AVX2/x86_64-v3 instruction sets (x86_64 only)" OFF) + +# Sanitizers (Mac and Linux Only) +option(ENABLE_ASAN "Enable Address Sanitizer" OFF) +option(ENABLE_UBSAN "Enable Undefined Behavior Sanitizer" OFF) +option(ENABLE_THREADSAN "Enable Thread Sanitizer" OFF) + +# Proprietary Libraries +option(INSTALL_PROPRIETARY "Build with support for non-free libraries" OFF) +cmake_dependent_option(USE_KDU "Enable support for the Kakadu JPEG2000 decoding library" ON "INSTALL_PROPRIETARY" OFF) + +# TODO: Replace with commented option below once Havok support is added to vcpkg +option(HAVOK "Use Havok physics library" OFF) +#cmake_dependent_option(HAVOK "Use Havok physics library" ON "INSTALL_PROPRIETARY" OFF) + +# Uncomment when support for Discord is finalized +#cmake_dependent_option(USE_DISCORD "Enable Discord SDK and Rich Prescence support" ON "INSTALL_PROPRIETARY" OFF) + +# SDL Options +cmake_dependent_option(USE_SDL_WINDOW "Build with SDL based window management and input" ON "UNIX;NOT APPLE" OFF) + +# Configure crash reporting +option(RELEASE_CRASH_REPORTING "Enable use of crash reporting in release builds" OFF) +option(NON_RELEASE_CRASH_REPORTING "Enable use of crash reporting in developer builds" OFF) + +# Bugsplat setup +if (INSTALL_PROPRIETARY AND (WIN32 OR APPLE)) + # Note that viewer_manifest.py makes decision based on BUGSPLAT_DB and not USE_BUGSPLAT + if (BUGSPLAT_DB) + set(USE_BUGSPLAT ON CACHE BOOL "Use the BugSplat crash reporting system") + else (BUGSPLAT_DB) + set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") + endif (BUGSPLAT_DB) +else () + set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") + set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name") +endif () + +# Tracy Profiler +# Default Tracy profiling on for test builds, but off for all others +set(BUILDING_TEST_CHANNEL OFF) +string(TOLOWER "${VIEWER_CHANNEL}" channel_lower) +if(channel_lower MATCHES "^second life test") + set(BUILDING_TEST_CHANNEL ON) +endif() +cmake_dependent_option(USE_TRACY "Enable support for Tracy profiler" ON "BUILDING_TEST_CHANNEL" OFF) +option(USE_TRACY_ON_DEMAND "Use on-demand Tracy profiling." ON) +option(USE_TRACY_LOCAL_ONLY "Disallow remote Tracy profiling." ON) +option(USE_TRACY_GPU "Use Tracy GPU profiling" OFF) +option(USE_TRACY_GUI "Enable building Tracy profiler GUI" OFF) + +# Signing +option(ENABLE_SIGNING "Enable signing the viewer" OFF) +set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if necessary.") + +# macOS deploy target(must be set BEFORE first project call) +set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum macOS version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value.") + +# Set our supported configuration types +set(CMAKE_CONFIGURATION_TYPES "Debug;OptDebug;RelWithDebInfo;Release" CACHE STRING "Supported build types.") if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING - "Build type. One of: Debug Release RelWithDebInfo" FORCE) + "Build type. One of: Debug OptDebug Release RelWithDebInfo") endif (NOT CMAKE_BUILD_TYPE) -if (LL_TESTS) +########################################################################## +# vcpkg feature flags MUST be set before the first project() call below # +########################################################################## + +if (USE_KDU) + list(APPEND VCPKG_MANIFEST_FEATURES "kdu") +endif() + +# Setup SDL feature flag +if (USE_SDL_WINDOW) + list(APPEND VCPKG_MANIFEST_FEATURES "sdl3") +endif() + +# Setup Tracy feature flags +if (USE_TRACY) + list(APPEND VCPKG_MANIFEST_FEATURES "tracy") +endif() + +if (USE_TRACY_LOCAL_ONLY) + list(APPEND VCPKG_MANIFEST_FEATURES "tracy-local") +endif() + +if(USE_TRACY_ON_DEMAND) + list(APPEND VCPKG_MANIFEST_FEATURES "tracy-on-demand") +endif() + +if(USE_TRACY_GUI) + list(APPEND VCPKG_MANIFEST_FEATURES "tracy-gui") +endif() + +if(USE_OPENXR) + list(APPEND VCPKG_MANIFEST_FEATURES "openxr") +endif() + +if(USE_BUGSPLAT) + list(APPEND VCPKG_MANIFEST_FEATURES "bugsplat") +endif() + +# Export compile_commands.json for ninja and makefile generators +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +if(NOT USE_PRECOMPILED_HEADERS) + set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) +endif() + +# Include our cmake module directory +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" "${CMAKE_CURRENT_BINARY_DIR}") + +# Setup VCPKG toolchains and targets +include(BootstrapVcpkg) + +# Generate base project after setting pre-generation variables +project(${ROOT_PROJECT_NAME}) + +# Location of indra directory +set(INDRA_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +set(INDRA_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}") + +# Set up common variables +include(Variables) + +# Set up Python +include(Python) + +# Set up our base build system variable and compiler flags +include(00-Common) +include(Linking) + +# Set up version number generation +include(BuildVersion) + +if (BUILD_TESTING) set(CMAKE_SKIP_TEST_ALL_DEPENDENCY FALSE) include(ProcessorCount) ProcessorCount(NUM_CORES) @@ -74,94 +195,113 @@ if (LL_TESTS) ) add_custom_target(BUILD_TESTS) - add_dependencies(BUILD_AND_RUN_TESTS BUILD_TESTS) - set_target_properties(BUILD_TESTS PROPERTIES FOLDER "CMakePredefinedTargets" ) endif () -add_subdirectory(cmake) +# Declare All Dependency Includes +include(APR) +include(Boost) +include(bugsplat) +include(Collada-Dom) +include(CURL) +include(Discord) +include(EXPAT) +include(FontConfig) +include(FreeType) +include(GLEXT) +include(GLIB) +include(GLM) +include(Havok) +include(Hunspell) +include(JPEG) +include(LLKDU) +include(LLPhysicsExtensions) +include(Meshoptimizer) +include(Mikktspace) +include(NDOF) +include(NanoSVG) +include(NVAPI) +include(OpenAL) +include(OpenGL) +include(OpenJPEG) +include(OpenSSL) +include(OpenXR) +include(PNG) +include(SDL3) +include(SSE2NEON) +include(TinyEXR) +include(TinyGLTF) +include(Tracy) +include(Tut) +include(VHACD) +include(Vorbis) +include(WebRTC) +include(xxHash) +include(ZLIBNG) -if (USE_PRECOMPILED_HEADERS) - add_subdirectory(${LIBS_OPEN_PREFIX}llprecompiled) +# Add our test macros +if (BUILD_TESTING) + include(LLAddBuildTest) endif () -add_subdirectory(${LIBS_OPEN_PREFIX}llaudio) -add_subdirectory(${LIBS_OPEN_PREFIX}llappearance) -add_subdirectory(${LIBS_OPEN_PREFIX}llcharacter) -add_subdirectory(${LIBS_OPEN_PREFIX}llcommon) -add_subdirectory(${LIBS_OPEN_PREFIX}llcorehttp) -add_subdirectory(${LIBS_OPEN_PREFIX}llimage) -add_subdirectory(${LIBS_OPEN_PREFIX}llkdu) -add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj) -add_subdirectory(${LIBS_OPEN_PREFIX}llinventory) -add_subdirectory(${LIBS_OPEN_PREFIX}llmath) -add_subdirectory(${LIBS_OPEN_PREFIX}llmeshoptimizer) -add_subdirectory(${LIBS_OPEN_PREFIX}llmessage) -add_subdirectory(${LIBS_OPEN_PREFIX}llphysicsextensionsos) -add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive) -add_subdirectory(${LIBS_OPEN_PREFIX}llrender) -add_subdirectory(${LIBS_OPEN_PREFIX}llfilesystem) -add_subdirectory(${LIBS_OPEN_PREFIX}llwebrtc) -add_subdirectory(${LIBS_OPEN_PREFIX}llwindow) -add_subdirectory(${LIBS_OPEN_PREFIX}llxml) - -if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) - add_subdirectory(${LIBS_CLOSED_PREFIX}copy_win_scripts) -endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) - -add_custom_target(viewer) - -add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) -add_subdirectory(${LIBS_OPEN_PREFIX}llui) -add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components) - -if( LL_TESTS ) -# Legacy C++ tests. Build always, run if LL_TESTS is true. -add_subdirectory(${VIEWER_PREFIX}test) + +# Third party system library copy step +include(Copy3rdPartyLibs) + +# Add our cmake modules to cmake +add_subdirectory(cmake) + +add_subdirectory(llprecompiled) +add_subdirectory(llaudio) +add_subdirectory(llappearance) +add_subdirectory(llcharacter) +add_subdirectory(llcommon) +add_subdirectory(llcorehttp) +add_subdirectory(llimage) +add_subdirectory(llkdu) +add_subdirectory(llimagej2coj) +add_subdirectory(llinventory) +add_subdirectory(llmath) +add_subdirectory(llmessage) +add_subdirectory(llphysicsextensionsos) +add_subdirectory(llprimitive) +add_subdirectory(llrender) +add_subdirectory(llfilesystem) +add_subdirectory(llwebrtc) +add_subdirectory(llwindow) +add_subdirectory(llxml) +add_subdirectory(llplugin) +add_subdirectory(llui) +add_subdirectory(viewer_components) + +if(BUILD_TESTING) + # Legacy C++ tests. + add_subdirectory(test) endif() -if (ENABLE_MEDIA_PLUGINS) # viewer media plugins -add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) -endif (ENABLE_MEDIA_PLUGINS) +add_subdirectory(media_plugins) -if (LINUX) +if (BUILD_APPEARANCE_UTIL) + # Avatar Appearance Utility add_subdirectory(llappearanceutility) endif() -if (WINDOWS) - # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake - if (EXISTS ${VIEWER_DIR}win_setup) - add_subdirectory(${VIEWER_DIR}win_setup) - endif (EXISTS ${VIEWER_DIR}win_setup) -endif (WINDOWS) - -if (USE_BUGSPLAT) - if (BUGSPLAT_DB) - message(STATUS "Building with BugSplat; database '${BUGSPLAT_DB}'") - else (BUGSPLAT_DB) - message(WARNING "Building with BugSplat, but no database name set (BUGSPLAT_DB)") - endif (BUGSPLAT_DB) -else (USE_BUGSPLAT) - message(STATUS "Not building with BugSplat") -endif (USE_BUGSPLAT) - -add_subdirectory(${VIEWER_PREFIX}newview) -add_dependencies(viewer secondlife-bin) +# Viewer +add_subdirectory(newview) -add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL) +add_subdirectory(doxygen EXCLUDE_FROM_ALL) # sets the 'startup project' for debugging from visual studio. set_property( - DIRECTORY ${VIEWER_PREFIX} + DIRECTORY PROPERTY VS_STARTUP_PROJECT ${VIEWER_BINARY_NAME} ) -if (LL_TESTS) +if (BUILD_TESTING) # Define after the custom targets are created so # individual apps can add themselves as dependencies - add_subdirectory(${INTEGRATION_TESTS_PREFIX}integration_tests) -endif (LL_TESTS) - + add_subdirectory(integration_tests) +endif () diff --git a/indra/CMakePresets.json b/indra/CMakePresets.json new file mode 100644 index 00000000000..4d228110f37 --- /dev/null +++ b/indra/CMakePresets.json @@ -0,0 +1,529 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "common", + "hidden": true, + "binaryDir": "${sourceParentDir}/build-${hostSystemName}-${presetName}" + }, + { + "name": "linux", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + }, + { + "name": "macos", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, + { + "name": "macos-arm64", + "hidden": true, + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "arm64" + } + }, + { + "name": "macos-x64", + "hidden": true, + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "x86_64" + } + }, + { + "name": "windows", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "nonfree", + "hidden": true, + "cacheVariables": { + "INSTALL_PROPRIETARY": true + } + }, + { + "name": "ninja-os", + "displayName": "Ninja Multi-Config", + "generator": "Ninja Multi-Config", + "inherits": "common", + "cacheVariables": { + "CMAKE_DEFAULT_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "ninja", + "displayName": "Ninja Multi-Config Proprietary", + "inherits": [ + "ninja-os", + "nonfree" + ] + }, + { + "name": "vs2022-os", + "displayName": "Visual Studio 2022", + "inherits": [ + "common", + "windows" + ], + "generator": "Visual Studio 17 2022" + }, + { + "name": "vs2022", + "displayName": "Visual Studio 2022 Proprietary", + "inherits": [ + "vs2022-os", + "nonfree" + ] + }, + { + "name": "vs2026-os", + "displayName": "Visual Studio 2026", + "inherits": [ + "common", + "windows" + ], + "generator": "Visual Studio 18 2026" + }, + { + "name": "vs2026", + "displayName": "Visual Studio 2026 Proprietary", + "inherits": [ + "vs2026-os", + "nonfree" + ] + }, + { + "name": "ninja-os-arm64", + "displayName": "Ninja Multi-Config(arm64)", + "inherits": [ + "ninja-os", + "macos", + "macos-arm64" + ] + }, + { + "name": "ninja-os-x64", + "displayName": "Ninja Multi-Config(x86_64)", + "inherits": [ + "ninja-os", + "macos", + "macos-x64" + ] + }, + { + "name": "ninja-arm64", + "displayName": "Ninja Multi-Config(arm64)", + "inherits": [ + "ninja", + "macos", + "macos-arm64" + ] + }, + { + "name": "ninja-x64", + "displayName": "Ninja Multi-Config(x86_64)", + "inherits": [ + "ninja", + "macos", + "macos-x64" + ] + }, + { + "name": "xcode-os", + "displayName": "Xcode OS", + "inherits": [ + "common", + "macos" + ], + "generator": "Xcode" + }, + { + "name": "xcode-os-arm64", + "displayName": "Xcode OS(arm64)", + "inherits": [ + "xcode-os", + "macos-arm64" + ] + }, + { + "name": "xcode-os-x64", + "displayName": "Xcode OS(x86_64)", + "inherits": [ + "xcode-os", + "macos-x64" + ] + }, + { + "name": "xcode", + "displayName": "Xcode Proprietary", + "inherits": [ + "xcode-os", + "nonfree" + ] + }, + { + "name": "xcode-arm64", + "displayName": "Xcode Proprietary(arm64)", + "inherits": [ + "xcode-os-arm64", + "nonfree" + ] + }, + { + "name": "xcode-x64", + "displayName": "Xcode Proprietary(x86_64)", + "inherits": [ + "xcode-os-x64", + "nonfree" + ] + } + ], + "buildPresets": [ + { + "name": "linux", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + }, + { + "name": "macos", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, + { + "name": "windows", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "ninja-debug", + "configurePreset": "ninja", + "configuration": "Debug" + }, + { + "name": "ninja-optdebug", + "configurePreset": "ninja", + "configuration": "OptDebug" + }, + { + "name": "ninja-relwithdebinfo", + "configurePreset": "ninja", + "configuration": "RelWithDebInfo" + }, + { + "name": "ninja-release", + "configurePreset": "ninja", + "configuration": "Release" + }, + { + "name": "ninja-os-debug", + "configurePreset": "ninja-os", + "configuration": "Debug" + }, + { + "name": "ninja-os-optdebug", + "configurePreset": "ninja-os", + "configuration": "OptDebug" + }, + { + "name": "ninja-os-relwithdebinfo", + "configurePreset": "ninja-os", + "configuration": "RelWithDebInfo" + }, + { + "name": "ninja-os-release", + "configurePreset": "ninja-os", + "configuration": "Release" + }, + { + "name": "vs2022-debug", + "configurePreset": "vs2022", + "configuration": "Debug", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2022-optdebug", + "configurePreset": "vs2022", + "configuration": "OptDebug", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2022-relwithdebinfo", + "configurePreset": "vs2022", + "configuration": "RelWithDebInfo", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2022-release", + "configurePreset": "vs2022", + "configuration": "Release", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2022-os-debug", + "configurePreset": "vs2022-os", + "configuration": "Debug", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2022-os-optdebug", + "configurePreset": "vs2022-os", + "configuration": "OptDebug", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2022-os-relwithdebinfo", + "configurePreset": "vs2022-os", + "configuration": "RelWithDebInfo", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2022-os-release", + "configurePreset": "vs2022-os", + "configuration": "Release", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2026-release", + "configurePreset": "vs2026", + "configuration": "Release", + "inherits": [ + "windows" + ] + }, + { + "name": "vs2026-os-release", + "configurePreset": "vs2026-os", + "configuration": "Release", + "inherits": [ + "windows" + ] + }, + { + "name": "ninja-arm64-release", + "configurePreset": "ninja-arm64", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "ninja-x64-release", + "configurePreset": "ninja-x64", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "ninja-os-arm64-release", + "configurePreset": "ninja-os-arm64", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "ninja-os-x64-release", + "configurePreset": "ninja-os-x64", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "xcode-release", + "configurePreset": "xcode", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "xcode-arm64-release", + "configurePreset": "xcode-arm64", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "xcode-x64-release", + "configurePreset": "xcode-x64", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "xcode-os-release", + "configurePreset": "xcode-os", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "xcode-os-arm64-release", + "configurePreset": "xcode-os-arm64", + "configuration": "Release", + "inherits": [ + "macos" + ] + }, + { + "name": "xcode-os-x64-release", + "configurePreset": "xcode-os-x64", + "configuration": "Release", + "inherits": [ + "macos" + ] + } + ], + "workflowPresets": [ + { + "name": "ninja-release", + "steps": [ + { + "type": "configure", + "name": "ninja" + }, + { + "type": "build", + "name": "ninja-release" + } + ] + }, + { + "name": "ninja-os-release", + "steps": [ + { + "type": "configure", + "name": "ninja-os" + }, + { + "type": "build", + "name": "ninja-os-release" + } + ] + }, + { + "name": "vs2022-release", + "steps": [ + { + "type": "configure", + "name": "vs2022" + }, + { + "type": "build", + "name": "vs2022-release" + } + ] + }, + { + "name": "vs2022-os", + "steps": [ + { + "type": "configure", + "name": "vs2022-os" + }, + { + "type": "build", + "name": "vs2022-os-release" + } + ] + }, + { + "name": "vs2026-release", + "steps": [ + { + "type": "configure", + "name": "vs2026" + }, + { + "type": "build", + "name": "vs2026-release" + } + ] + }, + { + "name": "vs2026-os-release", + "steps": [ + { + "type": "configure", + "name": "vs2026-os" + }, + { + "type": "build", + "name": "vs2026-os-release" + } + ] + }, + { + "name": "xcode-release", + "steps": [ + { + "type": "configure", + "name": "xcode" + }, + { + "type": "build", + "name": "xcode-release" + } + ] + }, + { + "name": "xcode-os-release", + "steps": [ + { + "type": "configure", + "name": "xcode-os" + }, + { + "type": "build", + "name": "xcode-os-release" + } + ] + } + ] +} \ No newline at end of file diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 1ab94e13df5..6efc5a46f22 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -3,36 +3,94 @@ # Compilation options shared by all Second Life components. #***************************************************************************** -# It's important to realize that CMake implicitly concatenates -# CMAKE_CXX_FLAGS with (e.g.) CMAKE_CXX_FLAGS_RELEASE for Release builds. So -# set switches in CMAKE_CXX_FLAGS that should affect all builds, but in -# CMAKE_CXX_FLAGS_RELEASE or CMAKE_CXX_FLAGS_RELWITHDEBINFO for switches -# that should affect only that build variant. -# -# Also realize that CMAKE_CXX_FLAGS may already be partially populated on -# entry to this file. -# -# Additionally CMAKE_C_FLAGS is prepended to CMAKE_CXX_FLAGS_RELEASE and -# CMAKE_CXX_FLAGS_RELWITHDEBINFO which risks having flags overriden by cmake -# inserting additional options that are part of the build config type. +# We setup four configurations: +# Debug - Full Debug build against Debug libraries +# OptDebug - Debug build against Release libraries +# RelWithDebInfo - Release build with Asserts +# Release - Release build #***************************************************************************** include_guard() include(Variables) include(Linking) -# We go to some trouble to set LL_BUILD to the set of relevant compiler flags. -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} $ENV{LL_BUILD_RELEASE}") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} $ENV{LL_BUILD_RELWITHDEBINFO}") +if(NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 20) +endif() +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_SCAN_FOR_MODULES OFF) # This slows down build massively + +# Optimize static library build dependency targets +set(CMAKE_OPTIMIZE_DEPENDENCIES ON) + +# Enable colored compiler diagnostic output +set(CMAKE_COLOR_DIAGNOSTICS ON) + +# Position Independent Code/ASLR +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# Hidden symbols to reduce binary size +set(CMAKE_C_VISIBILITY_PRESET "hidden") +set(CMAKE_CXX_VISIBILITY_PRESET "hidden") +set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) -# Given that, all the flags you see added below are flags NOT present in -# https://bitbucket.org/lindenlab/viewer-build-variables/src/tip/variables. -# Before adding new ones here, it's important to ask: can this flag really be -# applied to the viewer only, or should/must it be applied to all 3p libraries -# as well? +# Link Time Optimization +if(USE_LTO) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) +endif() + +# We want warnings as errors by default +if(NOT VS__DISABLE_FATAL_WARNINGS AND NOT GCC_DISABLE_FATAL_WARNINGS AND NOT CLANG_DISABLE_FATAL_WARNINGS) + set(CMAKE_COMPILE_WARNING_AS_ERROR ON) +endif() + +# Set up our OptDebug target +if (LL_GENERATOR_IS_MULTI_CONFIG OR CMAKE_BUILD_TYPE STREQUAL "OptDebug") + set(CMAKE_C_FLAGS_OPTDEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + set(CMAKE_CXX_FLAGS_OPTDEBUG ${CMAKE_CXX_FLAGS_DEBUG}) + set(CMAKE_EXE_LINKER_FLAGS_OPTDEBUG ${CMAKE_EXE_LINKER_FLAGS_DEBUG}) + set(CMAKE_MODULE_LINKER_FLAGS_OPTDEBUG ${CMAKE_MODULE_LINKER_FLAGS_DEBUG}) + set(CMAKE_SHARED_LINKER_FLAGS_OPTDEBUG ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}) + set(CMAKE_STATIC_LINKER_FLAGS_OPTDEBUG ${CMAKE_STATIC_LINKER_FLAGS_DEBUG}) + + # Need to map libraries to release variants on windows and macos + if(WINDOWS) + set(CMAKE_MAP_IMPORTED_CONFIG_OPTDEBUG Release) + endif() +endif() + +# Debug Global Defines +add_compile_definitions( + $<$:LL_DEBUG=1> + $<$:_DEBUG> +) + +# OptDebug Global Defines +add_compile_definitions( + $<$:LL_DEBUG=1> + $<$:LL_OPTDEBUG=1> + $<$:NDEBUG> +) + +# RelWithDebInfo Global Defines +add_compile_definitions( + $<$:LL_RELEASE=1> + $<$:LL_RELEASE_WITH_DEBUG_INFO=1> + $<$:NDEBUG=1> +) + +# Release Global Defines +add_compile_definitions( + $<$:LL_RELEASE=1> + $<$:LL_RELEASE_FOR_DOWNLOAD=1> + $<$:NDEBUG=1> +) # Portable compilation flags. add_compile_definitions(ADDRESS_SIZE=${ADDRESS_SIZE}) + # Because older versions of Boost.Bind dumped placeholders _1, _2 et al. into # the global namespace, Boost now requires either BOOST_BIND_NO_PLACEHOLDERS # to avoid that or BOOST_BIND_GLOBAL_PLACEHOLDERS to state that we require it @@ -46,106 +104,134 @@ add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_ENABLE_EXPERIME # SSE2NEON throws a pointless warning when compiler optimizations are enabled add_compile_definitions(SSE2NEON_SUPPRESS_WARNINGS=1) -# Configure crash reporting -set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds") -set(NON_RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in developer builds") - if(RELEASE_CRASH_REPORTING) - add_compile_definitions( LL_SEND_CRASH_REPORTS=1) + add_compile_definitions(LL_SEND_CRASH_REPORTS=1) endif() if(NON_RELEASE_CRASH_REPORTING) - add_compile_definitions( LL_SEND_CRASH_REPORTS=1) + add_compile_definitions(LL_SEND_CRASH_REPORTS=1) endif() -set(USE_LTO OFF CACHE BOOL "Enable Link Time Optimization") -if(USE_LTO) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) -endif() - -# Don't bother with a MinSizeRel or Debug builds. -set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release" CACHE STRING "Supported build types." FORCE) - # Platform-specific compilation flags. +if(WINDOWS) + set(CMAKE_MSVC_RUNTIME_CHECKS "$<$:StackFrameErrorCheck;UninitializedVariable>") + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT $,EditAndContinue,ProgramDatabase>) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") -if (WINDOWS) # Don't build DLLs. set(BUILD_SHARED_LIBS OFF) - # for "backwards compatibility", cmake sneaks in the Zm1000 option which royally - # screws incredibuild. this hack disables it. - # for details see: http://connect.microsoft.com/VisualStudio/feedback/details/368107/clxx-fatal-error-c1027-inconsistent-values-for-ym-between-creation-and-use-of-precompiled-headers - # http://www.ogre3d.org/forums/viewtopic.php?f=2&t=60015 - # http://www.cmake.org/pipermail/cmake/2009-September/032143.html - string(REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) + add_link_options( + $<$:/OPT:REF> + $<$:/OPT:ICF> + /DEBUG:FULL + /LARGEADDRESSAWARE + /NODEFAULTLIB:LIBCMT + /NODEFAULTLIB:LIBCMTD + $<$:/NODEFAULTLIB:MSVCRTD> + $<$:/NODEFAULTLIB:MSVCRT> + ) + + add_compile_definitions( + LL_WINDOWS=1 + UNICODE + _UNICODE + WINVER=0x0A00 + _WIN32_WINNT=0x0A00 + ) - add_link_options(/LARGEADDRESSAWARE - /NODEFAULTLIB:LIBCMT - /IGNORE:4099) + # Set windows specific warning supressions + add_compile_definitions( + WIN32_LEAN_AND_MEAN + NOMINMAX + _CRT_SECURE_NO_WARNINGS # Allow use of sprintf etc + _CRT_NONSTDC_NO_DEPRECATE # Allow use of sprintf etc + _CRT_OBSOLETE_NO_WARNINGS + _WINSOCK_DEPRECATED_NO_WARNINGS # Disable deprecated WinSock API warnings + ) + # Webrtc libraries incompatible with win32 debug builds add_compile_definitions( - WIN32_LEAN_AND_MEAN - NOMINMAX -# DOM_DYNAMIC # For shared library colladadom - _CRT_SECURE_NO_WARNINGS # Allow use of sprintf etc - _CRT_NONSTDC_NO_DEPRECATE # Allow use of sprintf etc - _CRT_OBSOLETE_NO_WARNINGS - _WINSOCK_DEPRECATED_NO_WARNINGS # Disable deprecated WinSock API warnings - ) + $<$:DISABLE_WEBRTC=1> + ) + + # Options shared between all configurations add_compile_options( - /Zo - /GS - /TP - /W3 - /c - /Zc:forScope - /nologo - /Oy- - /fp:fast - /MP - /permissive- - ) - - # Nicky: x64 implies SSE2 - if( ADDRESS_SIZE EQUAL 32 ) - add_compile_options( /arch:SSE2 ) - endif() + /EHsc + /Gy + /GS + /GR + /W3 + /nologo + $<$:/fp:fast> + /MP + /permissive- + /Zc:preprocessor + /Zc:__cplusplus + /Zc:inline + /Zc:wchar_t + ) + + # Debug MSVC Options + add_compile_options( + $<$:/Od> + $<$:/Ob0> + ) + + # OptDebug MSVC Options + add_compile_options( + $<$:/Od> + $<$:/Ob0> + ) + + # RelWithDebInfo MSVC Options + add_compile_options( + $<$:/O2> + ) - # Are we using the crummy Visual Studio KDU build workaround? - if (NOT VS_DISABLE_FATAL_WARNINGS) - add_compile_options(/WX) - endif (NOT VS_DISABLE_FATAL_WARNINGS) - - #ND: When using something like buildcache (https://github.com/mbitsnbites/buildcache) - # to make those wrappers work /Zi must be changed to /Z7, as /Zi due to it's nature is not compatible with caching - if (${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES ".*cache.*") - add_compile_options( /Z7 ) - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") - string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") - string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + # Release MSVC Options + add_compile_options( + $<$:/O2> + ) + + # Flags to support building with newer instruction sets. + # https://learn.microsoft.com/en-us/cpp/build/reference/arch-x64?view=msvc-170 + if(USE_AVX2) + add_compile_options( + /arch:AVX2 + ) + elseif(USE_AVX) + add_compile_options( + /arch:AVX + ) + elseif(USE_SSE4_2) + add_compile_options( + /arch:SSE4.2 + ) endif() -endif (WINDOWS) + # We want aggressive inlining on MSVC Release to better match clang/gcc at O3 + string(REPLACE "/Ob1" "/Ob3" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + string(REPLACE "/Ob1" "/Ob3" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + string(REPLACE "/Ob2" "/Ob3" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "/Ob2" "/Ob3" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") +endif(WINDOWS) -if (LINUX) +if(LINUX) set(CMAKE_SKIP_RPATH TRUE) - # LL_IGNORE_SIGCHLD - # don't catch SIGCHLD in our base application class for the viewer - some of - # our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The - # viewer doesn't need to catch SIGCHLD anyway. + # LL_IGNORE_SIGCHLD + # don't catch SIGCHLD in our base application class for the viewer - some of + # our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! The + # viewer doesn't need to catch SIGCHLD anyway. add_compile_definitions( - _REENTRANT - APPID=secondlife - LL_IGNORE_SIGCHLD + LL_LINUX=1 + _REENTRANT + APPID=secondlife + LL_IGNORE_SIGCHLD ) - option(ENABLE_ASAN "Enable Address Sanitizer" OFF) - option(ENABLE_UBSAN "Enable Undefined Behavior Sanitizer" OFF) - option(ENABLE_THREADSAN "Enable Thread Sanitizer" OFF) if(ENABLE_ASAN OR ENABLE_UBSAN OR ENABLE_THREADSAN) set(GCC_DISABLE_FATAL_WARNINGS ON) # Disable warnings as errors during sanitizer builds due to false positives @@ -178,60 +264,182 @@ if (LINUX) add_compile_definitions($<$:_FORTIFY_SOURCE=2>) endif() + # Options shared between all configs + add_compile_options( + $<$:-fstack-protector> + -fexceptions + -fno-math-errno + -fno-strict-aliasing + -fsigned-char + -g + ) + + # Debug Options add_compile_options( - $<$,$>:-fstack-protector> - -fexceptions - -fno-math-errno - -fno-strict-aliasing - -fsigned-char - -g - -msse2 - -pthread - -fvisibility=hidden + $<$:-O0> ) + # OptDebug Options + add_compile_options( + $<$:-Og> + ) + + # RelWithDebInfo Options + add_compile_options( + $<$:-O3> + ) + + # Release Options + add_compile_options( + $<$:-O3> + ) + + # Flags to support building with newer instruction sets. + # Set up using x86_64 microarchitecture levels + # https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels + if(USE_AVX2) + add_compile_options( + -march=x86-64-v3 + ) + elseif(USE_AVX) + # x86_64-v2 includes sse4.2 and we additionally add AVX support + add_compile_options( + -march=x86-64-v2 + -mavx + ) + elseif(USE_SSE4_2) + # x86_64-v2 includes sse4.2 + add_compile_options( + -march=x86-64-v2 + ) + else() + # Baseline x86-64 support includes sse2 + add_compile_options( + -march=x86-64 + ) + endif() + add_link_options( - "LINKER:-z,relro" - "LINKER:-z,now" - "LINKER:--build-id" - "LINKER:--as-needed" - "LINKER:--no-undefined" + "LINKER:-z,relro" + "LINKER:-z,now" + "LINKER:--build-id" + "LINKER:--as-needed" + "LINKER:--no-undefined" ) -endif (LINUX) -if (DARWIN) + # Only turn on headless if we can find osmesa libraries. + find_package(PkgConfig) + pkg_check_modules(OSMESA IMPORTED_TARGET GLOBAL osmesa) + if(OSMESA_FOUND) + set(BUILD_HEADLESS ON CACHE BOOL "Build headless libraries.") + endif(OSMESA_FOUND) +endif(LINUX) + +if(DARWIN) # Use rpath loading on macos set(CMAKE_MACOSX_RPATH TRUE) - set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}") + # Only generate top-level xcodeproj + set(CMAKE_XCODE_GENERATE_TOP_LEVEL_PROJECT_ONLY ON) + + # Set up xcode scheme + set(CMAKE_XCODE_GENERATE_SCHEME ON) + set(CMAKE_XCODE_SCHEME_LAUNCH_CONFIGURATION "RelWithDebInfo") + if(ENABLE_ASAN OR ENABLE_UBSAN OR ENABLE_THREADSAN) + if(ENABLE_ASAN) + set(CMAKE_XCODE_SCHEME_ADDRESS_SANITIZER ON) + endif() + + if(ENABLE_UBSAN) + set(CMAKE_XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER ON) + endif() + + if(ENABLE_THREADSAN) + set(CMAKE_XCODE_SCHEME_THREAD_SANITIZER ON) + endif() + endif() + + # Use dwarf symbols for most libraries and executables for compilation speed + # per-target overrides applied where needed + set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS YES) + set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf") + + set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) + set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS sse4.2) + # we must hard code this to off for now. xcode's built in signing does not + # handle embedded app bundles such as CEF and others. Any signing for local + # development must be done after the build as we do in viewer_manifest.py for + # released builds + # https://stackoverflow.com/a/54296008 + # With Xcode 14.1, apparently you must take drastic steps to prevent + # implicit signing. + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED NO) + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO) + # "-" represents "Sign to Run Locally" and empty string represents "Do Not Sign" + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") + set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "") + set(CMAKE_XCODE_ATTRIBUTE_DISABLE_MANUAL_TARGET_ORDER_BUILD_WARNING YES) + set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION NO) + + # Platform define + add_compile_definitions(LL_DARWIN=1) # Ensure debug symbols are always generated - add_compile_options(-g --debug) # --debug is a clang synonym for -g that bypasses cmake behaviors + add_compile_options(-g2 -gdwarf -fno-fast-math -fno-strict-aliasing) + + if(BUILD_TARGET_IS_X86_64) + add_compile_options(-msse4.2) + endif() # Silence GL deprecation warnings add_compile_definitions(GL_SILENCE_DEPRECATION=1) + + # Debug Options + add_compile_options( + $<$:-O0> + ) + + # OptDebug Options + add_compile_options( + $<$:-Og> + ) + + # RelWithDebInfo Options + add_compile_options( + $<$:-O3> + ) + + # Release Options + add_compile_options( + $<$:-O3> + ) + + add_link_options($<$:LINKER:-dead_strip> LINKER:-dead_strip_dylibs) + + add_link_options("LINKER:-headerpad_max_install_names" "LINKER:-search_paths_first") endif(DARWIN) -if (LINUX OR DARWIN) +if(LINUX OR DARWIN) add_compile_options(-Wall -Wno-sign-compare -Wno-trigraphs -Wno-reorder -Wno-unused-but-set-variable -Wno-unused-variable) - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - add_compile_options(-Wno-unused-private-field) - endif() - - if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - add_compile_options(-Wno-unused-local-typedef) + if(COMPILER_IS_CLANG) + add_compile_options(-Wno-unused-private-field -Wno-unused-local-typedef -Wno-reorder-ctor) endif() - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(COMPILER_IS_GCC) add_compile_options(-Wno-stringop-truncation -Wno-stringop-overflow -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-local-typedefs) - endif () - if (NOT GCC_DISABLE_FATAL_WARNINGS AND NOT CLANG_DISABLE_FATAL_WARNINGS) - add_compile_options(-Werror) - endif () + # This warning is extremely false positive sensitive, including on libstdc++'s own headers. + add_compile_options(-Wno-array-bounds) + endif() - add_compile_options(-m${ADDRESS_SIZE}) -endif (LINUX OR DARWIN) + if (BUILD_TARGET_IS_X86_64) + add_compile_options(-m${ADDRESS_SIZE}) + endif() +endif() +# Enable support for Drag and Drop +if(OS_DRAG_DROP) + add_compile_definitions(LL_OS_DRAGDROP_ENABLED=1) +endif(OS_DRAG_DROP) diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake index e0807a7d19d..4b49514a1ac 100644 --- a/indra/cmake/APR.cmake +++ b/indra/cmake/APR.cmake @@ -1,33 +1,36 @@ -include(Linking) -include(Prebuilt) - include_guard() - -add_library( ll::apr INTERFACE IMPORTED ) - -use_system_binary( apr apr-util ) -use_prebuilt_binary(apr_suite) +add_library(ll::apr INTERFACE IMPORTED) if (WINDOWS) - target_compile_definitions(ll::apr INTERFACE APR_DECLARE_STATIC=1 APU_DECLARE_STATIC=1 API_DECLARE_STATIC=1) -endif () - -find_library(APR_LIBRARY - NAMES - apr-1.lib - libapr-1.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(APRUTIL_LIBRARY - NAMES - aprutil-1.lib - libaprutil-1.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::apr INTERFACE ${APR_LIBRARY} ${APRUTIL_LIBRARY}) - -if(DARWIN) - target_link_libraries(ll::apr INTERFACE iconv) + find_package(apr CONFIG REQUIRED) + target_link_libraries(ll::apr INTERFACE + $<$:apr::apr-1> + $<$:apr::aprapp-1> + $<$:apr::libapr-1> + $<$:apr::libaprapp-1> + ) + + find_library(APU_LIBRARY_RELEASE + NAMES aprutil-1 libaprutil-1 + PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" + REQUIRED + NO_DEFAULT_PATH + ) + + target_link_libraries(ll::apr INTERFACE optimized ${APU_LIBRARY_RELEASE}) + + find_library(APU_LIBRARY_DEBUG + NAMES aprutil-1 libaprutil-1 + PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" + NO_DEFAULT_PATH + ) + + if (NOT APU_LIBRARY_DEBUG STREQUAL "APU_LIBRARY_DEBUG-NOTFOUND") + target_link_libraries(ll::apr INTERFACE debug ${APU_LIBRARY_DEBUG}) + endif() +else() + find_package(PkgConfig) + pkg_check_modules(APR REQUIRED IMPORTED_TARGET GLOBAL apr-1) + pkg_check_modules(APR_UTIL REQUIRED IMPORTED_TARGET GLOBAL apr-util-1) + target_link_libraries(ll::apr INTERFACE PkgConfig::APR_UTIL PkgConfig::APR) endif() - -target_include_directories(ll::apr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/apr-1) diff --git a/indra/cmake/Audio.cmake b/indra/cmake/Audio.cmake deleted file mode 100644 index 5a7a7ab0b52..00000000000 --- a/indra/cmake/Audio.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# -*- cmake -*- -include(Linking) -include(Prebuilt) - -include_guard() -add_library( ll::vorbis INTERFACE IMPORTED ) - -use_system_binary(vorbis) -use_prebuilt_binary(ogg_vorbis) -target_include_directories( ll::vorbis SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include ) - -find_library(OGG_LIBRARY - NAMES - libogg.lib - libogg.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(VORBIS_LIBRARY - NAMES - libvorbis.lib - libvorbis.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(VORBISENC_LIBRARY - NAMES - libvorbisenc.lib - libvorbisenc.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(VORBISFILE_LIBRARY - NAMES - libvorbisfile.lib - libvorbisfile.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::vorbis INTERFACE ${VORBISENC_LIBRARY} ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY} ) - diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index fd3e0eccdef..0e5a4d831bd 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -1,80 +1,13 @@ -# -*- cmake -*- -include(Prebuilt) -include(Linking) - include_guard() +add_library(ll::boost INTERFACE IMPORTED) -add_library( ll::boost INTERFACE IMPORTED ) -if( USE_CONAN ) - target_link_libraries( ll::boost INTERFACE CONAN_PKG::boost ) - target_compile_definitions( ll::boost INTERFACE BOOST_ALLOW_DEPRECATED_HEADERS BOOST_BIND_GLOBAL_PLACEHOLDERS ) - return() -endif() - -use_prebuilt_binary(boost) - -# As of sometime between Boost 1.67 and 1.72, Boost libraries are suffixed -# with the address size. -set(addrsfx "-x${ADDRESS_SIZE}") - -find_library(BOOST_CONTEXT_LIBRARY - NAMES - libboost_context - libboost_context-mt - libboost_context-mt${addrsfx} - boost_context - boost_context-mt - boost_context-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_FIBER_LIBRARY - NAMES - libboost_fiber - libboost_fiber-mt - libboost_fiber-mt${addrsfx} - boost_fiber - boost_fiber-mt - boost_fiber-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_FILESYSTEM_LIBRARY - NAMES - libboost_filesystem - libboost_filesystem-mt - libboost_filesystem-mt${addrsfx} - boost_filesystem - boost_filesystem-mt - boost_filesystem-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_PROGRAMOPTIONS_LIBRARY - NAMES - libboost_program_options - libboost_program_options-mt - libboost_program_options-mt${addrsfx} - boost_program_options - boost_program_options-mt - boost_program_options-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(BOOST_URL_LIBRARY - NAMES - libboost_url - libboost_url-mt - libboost_url-mt${addrsfx} - boost_url - boost_url-mt - boost_url-mt${addrsfx} - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::boost INTERFACE - ${BOOST_FIBER_LIBRARY} - ${BOOST_CONTEXT_LIBRARY} - ${BOOST_FILESYSTEM_LIBRARY} - ${BOOST_PROGRAMOPTIONS_LIBRARY} - ${BOOST_URL_LIBRARY}) - -if (LINUX) - target_link_libraries(ll::boost INTERFACE rt) -endif (LINUX) +find_package(Boost CONFIG REQUIRED COMPONENTS context fiber filesystem json program_options url) +target_link_libraries(ll::boost INTERFACE Boost::disable_autolinking Boost::headers Boost::fiber Boost::context Boost::filesystem Boost::program_options Boost::url Boost::json) +if(WINDOWS) + find_package(Boost CONFIG REQUIRED COMPONENTS stacktrace_windbg) + target_link_libraries(ll::boost INTERFACE Boost::stacktrace_windbg) +else() + find_package(Boost CONFIG REQUIRED COMPONENTS stacktrace_basic) + target_link_libraries(ll::boost INTERFACE Boost::stacktrace_basic) +endif() diff --git a/indra/cmake/BootstrapVcpkg.cmake b/indra/cmake/BootstrapVcpkg.cmake new file mode 100644 index 00000000000..74f3620df2e --- /dev/null +++ b/indra/cmake/BootstrapVcpkg.cmake @@ -0,0 +1,105 @@ +# -*- cmake -*- +# +# Automatic clone and bootstrap of a vcpkg_root environment when VCPKG_ROOT is not found +# Automatic vcpkg target triplet selection based on generator and platform + +include_guard(GLOBAL) + +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) + include(FetchContent) + + if(DEFINED ENV{VCPKG_ROOT}) + set(VCPKG_ROOT $ENV{VCPKG_ROOT}) + + if(WIN32) + set(VCPKG_EXECUTABLE ${VCPKG_ROOT}/vcpkg.exe) + else() + set(VCPKG_EXECUTABLE ${VCPKG_ROOT}/vcpkg) + endif() + + if(NOT EXISTS "${VCPKG_EXECUTABLE}") + message(FATAL_ERROR "VCPKG_ROOT found in environment but vcpkg executable could not be found.") + endif() + else() + set(VCPKG_ROOT ${CMAKE_BINARY_DIR}/vcpkg_root) + set(ENV{VCPKG_ROOT} ${VCPKG_ROOT}) + + FetchContent_Populate( + vcpkg + GIT_REPOSITORY https://github.com/microsoft/vcpkg.git + SOURCE_DIR ${VCPKG_ROOT} + ) + + if(WIN32) + set(VCPKG_EXECUTABLE ${VCPKG_ROOT}/vcpkg.exe) + set(VCPKG_BOOTSTRAP ${VCPKG_ROOT}/bootstrap-vcpkg.bat) + else() + set(VCPKG_EXECUTABLE ${VCPKG_ROOT}/vcpkg) + set(VCPKG_BOOTSTRAP ${VCPKG_ROOT}/bootstrap-vcpkg.sh) + endif() + + if(NOT EXISTS "${VCPKG_EXECUTABLE}") + message("Bootstrapping vcpkg in ${VCPKG_ROOT}") + execute_process(COMMAND "${VCPKG_BOOTSTRAP}" WORKING_DIRECTORY "${VCPKG_ROOT}") + if(NOT EXISTS "${VCPKG_EXECUTABLE}") + message(FATAL_ERROR "Could not bootstrap vcpkg") + endif() + endif() + endif() + + set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake CACHE STRING "") +endif() + +if(NOT DEFINED VCPKG_TARGET_TRIPLET) + # Check if generator is multiconfig + get_property(LL_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + + if(WIN32) + if(LL_GENERATOR_IS_MULTI_CONFIG) + set(VCPKG_TARGET_TRIPLET "x64-windows-secondlife") + else() + if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(VCPKG_TARGET_TRIPLET "x64-windows-secondlife") + else() + set(VCPKG_TARGET_TRIPLET "x64-windows-secondlife-release") + endif() + endif() + elseif(APPLE) + if(DEFINED CMAKE_OSX_ARCHITECTURES) + set(OS_PLATFORM "${CMAKE_OSX_ARCHITECTURES}") + else() + cmake_host_system_information(RESULT OS_PLATFORM QUERY OS_PLATFORM) + endif() + if(LL_GENERATOR_IS_MULTI_CONFIG) + if(OS_PLATFORM STREQUAL arm64) + set(VCPKG_TARGET_TRIPLET "arm64-osx-secondlife") + else() + set(VCPKG_TARGET_TRIPLET "x64-osx-secondlife") + endif() + else() + if(OS_PLATFORM STREQUAL arm64) + if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(VCPKG_TARGET_TRIPLET "arm64-osx-secondlife") + else() + set(VCPKG_TARGET_TRIPLET "arm64-osx-secondlife-release") + endif() + else() + if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(VCPKG_TARGET_TRIPLET "x64-osx-secondlife") + else() + set(VCPKG_TARGET_TRIPLET "x64-osx-secondlife-release") + endif() + endif() + endif() + else() + if(LL_GENERATOR_IS_MULTI_CONFIG) + set(VCPKG_TARGET_TRIPLET "x64-linux-secondlife") + else() + if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(VCPKG_TARGET_TRIPLET "x64-linux-secondlife") + else() + set(VCPKG_TARGET_TRIPLET "x64-linux-secondlife-release") + endif() + endif() + endif() +endif() diff --git a/indra/cmake/BuildPackagesInfo.cmake b/indra/cmake/BuildPackagesInfo.cmake index 659ba9d5795..22f58de0b56 100644 --- a/indra/cmake/BuildPackagesInfo.cmake +++ b/indra/cmake/BuildPackagesInfo.cmake @@ -1,7 +1,11 @@ # -*- cmake -*- # Construct the version and copyright information based on package data. +include_guard() + +# TODO: Reenable once solution found to vcpkg license generation +return() + include(Python) -include(FindAutobuild) # packages-formatter.py runs autobuild install --versions, which needs to know # the build_directory, which (on Windows) depends on AUTOBUILD_ADDRSIZE. @@ -10,11 +14,11 @@ include(FindAutobuild) # run_build_test.py. add_custom_command(OUTPUT packages-info.txt COMMENT "Generating packages-info.txt for the about box" - MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/../autobuild.xml - DEPENDS ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py - ${CMAKE_SOURCE_DIR}/../autobuild.xml - COMMAND ${PYTHON_EXECUTABLE} - ${CMAKE_SOURCE_DIR}/cmake/run_build_test.py -DAUTOBUILD_ADDRSIZE=${ADDRESS_SIZE} -DAUTOBUILD=${AUTOBUILD_EXECUTABLE} - ${PYTHON_EXECUTABLE} - ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py "${VIEWER_CHANNEL}" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}" "${AUTOBUILD_INSTALL_DIR}" > packages-info.txt + MAIN_DEPENDENCY ${INDRA_SOURCE_DIR}/../autobuild.xml + DEPENDS ${SCRIPTS_DIR}/packages-formatter.py + ${INDRA_SOURCE_DIR}/../autobuild.xml + COMMAND ${Python3_EXECUTABLE} + ${INDRA_SOURCE_DIR}/cmake/run_build_test.py -DAUTOBUILD_ADDRSIZE=${ADDRESS_SIZE} -DAUTOBUILD=${AUTOBUILD_EXECUTABLE} + ${Python3_EXECUTABLE} + ${SCRIPTS_DIR}/packages-formatter.py "${VIEWER_CHANNEL}" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}" "${AUTOBUILD_INSTALL_DIR}" > packages-info.txt ) diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake index 6939f9a4da7..ec3a9548836 100644 --- a/indra/cmake/BuildVersion.cmake +++ b/indra/cmake/BuildVersion.cmake @@ -1,8 +1,10 @@ # -*- cmake -*- -# Construct the viewer version number based on the indra/VIEWER_VERSION file +set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside") + +# Construct the viewer version number based on the indra/VIEWER_VERSION file if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/newview/ - set(VIEWER_VERSION_BASE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/newview/VIEWER_VERSION.txt") + set(VIEWER_VERSION_BASE_FILE "${INDRA_SOURCE_DIR}/newview/VIEWER_VERSION.txt") if ( EXISTS ${VIEWER_VERSION_BASE_FILE} ) file(STRINGS ${VIEWER_VERSION_BASE_FILE} VIEWER_SHORT_VERSION REGEX "^[0-9]+\\.[0-9]+\\.[0-9]+") @@ -14,15 +16,15 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n set(VIEWER_VERSION_REVISION $ENV{revision}) message(STATUS "Revision (from environment): ${VIEWER_VERSION_REVISION}") - elseif (DEFINED ENV{AUTOBUILD_BUILD_ID}) - set(VIEWER_VERSION_REVISION $ENV{AUTOBUILD_BUILD_ID}) - message(STATUS "Revision (from autobuild environment): ${VIEWER_VERSION_REVISION}") + elseif (DEFINED ENV{GITHUB_RUN_ID}) + set(VIEWER_VERSION_REVISION $ENV{GITHUB_RUN_ID}) + message(STATUS "Revision (from github environment): ${VIEWER_VERSION_REVISION}") - else (DEFINED ENV{revision}) - find_program(GIT git) - if (DEFINED GIT ) + else () + find_package(Git) + if (Git_FOUND) execute_process( - COMMAND ${GIT} rev-list --count HEAD + COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD OUTPUT_VARIABLE VIEWER_VERSION_REVISION OUTPUT_STRIP_TRAILING_WHITESPACE ) @@ -32,10 +34,10 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n message(STATUS "Revision not set (repository not found?); using 0") set(VIEWER_VERSION_REVISION 0 ) endif ("${VIEWER_VERSION_REVISION}" MATCHES "^[0-9]+$") - else (DEFINED GIT ) - message(STATUS "Revision not set: 'git' found; using 0") + else () + message(STATUS "Revision not set: 'git' not found; using 0") set(VIEWER_VERSION_REVISION 0) - endif (DEFINED GIT) + endif () endif (DEFINED ENV{revision}) message(STATUS "Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") else ( EXISTS ${VIEWER_VERSION_BASE_FILE} ) diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake index 5f5c55f0e95..02280b6d379 100644 --- a/indra/cmake/CEFPlugin.cmake +++ b/indra/cmake/CEFPlugin.cmake @@ -1,40 +1,22 @@ # -*- cmake -*- -include(Linking) -include(Prebuilt) - include_guard() -add_library( ll::cef INTERFACE IMPORTED ) - -use_prebuilt_binary(dullahan) -target_include_directories( ll::cef SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/cef) - -if (WINDOWS) - target_link_libraries( ll::cef INTERFACE - ${ARCH_PREBUILT_DIRS_RELEASE}/libcef.lib - ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.lib - ${ARCH_PREBUILT_DIRS_RELEASE}/dullahan.lib - ) -elseif (DARWIN) - FIND_LIBRARY(APPKIT_LIBRARY AppKit) - if (NOT APPKIT_LIBRARY) - message(FATAL_ERROR "AppKit not found") - endif() +add_library(ll::cef INTERFACE IMPORTED) - set(CEF_LIBRARY "'${ARCH_PREBUILT_DIRS_RELEASE}/Chromium\ Embedded\ Framework.framework'") - if (NOT CEF_LIBRARY) - message(FATAL_ERROR "CEF not found") - endif() - target_link_libraries( ll::cef INTERFACE - ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a - ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a +if(DARWIN) + find_library(APPKIT_LIBRARY AppKit REQUIRED) + find_library(DULLAHAN_LIBRARY_RELEASE NAMES dullahan REQUIRED) + find_library(LIBCEF_DLL_WRAPPER_LIBRARY_RELEASE NAMES cef_dll_wrapper REQUIRED) + target_link_libraries(ll::cef INTERFACE + ${DULLAHAN_LIBRARY_RELEASE} + ${LIBCEF_DLL_WRAPPER_LIBRARY_RELEASE} ${APPKIT_LIBRARY} ) +else() + find_library(LIBCEF_LIBRARY_RELEASE NAMES cef libcef PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" REQUIRED NO_DEFAULT_PATH) + find_library(LIBCEF_DLL_WRAPPER_LIBRARY_RELEASE NAMES cef_dll_wrapper PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" REQUIRED NO_DEFAULT_PATH) + find_library(DULLAHAN_LIBRARY_RELEASE NAMES dullahan PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" REQUIRED NO_DEFAULT_PATH) + target_link_libraries(ll::cef INTERFACE ${DULLAHAN_LIBRARY_RELEASE} ${LIBCEF_DLL_WRAPPER_LIBRARY_RELEASE} ${LIBCEF_LIBRARY_RELEASE}) +endif() -elseif (LINUX) - target_link_libraries( ll::cef INTERFACE - ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a - ${ARCH_PREBUILT_DIRS_RELEASE}/libcef.so - ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a - ) -endif (WINDOWS) +target_include_directories(ll::cef SYSTEM INTERFACE ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/cef) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index fa5008c3739..e8c5910a0ee 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -1,29 +1,22 @@ # -*- cmake -*- -include(00-Common) - -project(cmake) - set(cmake_SOURCE_FILES - CMakeLists.txt 00-Common.cmake APR.cmake - Audio.cmake Boost.cmake + BootstrapVcpkg.cmake bugsplat.cmake BuildPackagesInfo.cmake BuildVersion.cmake CEFPlugin.cmake - CEFPlugin.cmake CMakeCopyIfDifferent.cmake + Collada-Dom.cmake Copy3rdPartyLibs.cmake CURL.cmake - DeploySharedLibs.cmake Discord.cmake - DragDrop.cmake EXPAT.cmake - FindAutobuild.cmake FindPipeWire.cmake + FontConfig.cmake FreeType.cmake GLEXT.cmake GLIB.cmake @@ -31,29 +24,27 @@ set(cmake_SOURCE_FILES GStreamer10Plugin.cmake Havok.cmake Hunspell.cmake + JPEG.cmake + LibVLCPlugin.cmake + Linking.cmake LLAddBuildTest.cmake - LLAppearance.cmake - LLAudio.cmake - LLCommon.cmake - LLImage.cmake LLKDU.cmake LLPhysicsExtensions.cmake - LLPrimitive.cmake - LLSharedLibs.cmake LLTestCommand.cmake - LLWindow.cmake - Linking.cmake Meshoptimizer.cmake + Mikktspace.cmake + NanoSVG.cmake NDOF.cmake - OPENAL.cmake + NVAPI.cmake + OpenAL.cmake OpenGL.cmake OpenJPEG.cmake OpenSSL.cmake - PNG.cmake + OpenXR.cmake PluginAPI.cmake - Prebuilt.cmake - PulseAudio.cmake + PNG.cmake Python.cmake + run_build_test.py SDL3.cmake SSE2NEON.cmake TemplateCheck.cmake @@ -65,9 +56,7 @@ set(cmake_SOURCE_FILES UnixInstall.cmake Variables.cmake VHACD.cmake - ViewerMiscLibs.cmake - VisualLeakDetector.cmake - LibVLCPlugin.cmake + Vorbis.cmake WebRTC.cmake xxHash.cmake ZLIBNG.cmake @@ -75,8 +64,10 @@ set(cmake_SOURCE_FILES source_group("Shared Rules" FILES ${cmake_SOURCE_FILES}) +source_group("CMake Rules" FILES CMakeLists.txt) + set(master_SOURCE_FILES - ../CMakeLists.txt + ${CMAKE_SOURCE_DIR}/CMakeLists.txt ) source_group("Master Rules" FILES ${master_SOURCE_FILES}) diff --git a/indra/cmake/CURL.cmake b/indra/cmake/CURL.cmake index b1595d57a89..92a6f0d9fdf 100644 --- a/indra/cmake/CURL.cmake +++ b/indra/cmake/CURL.cmake @@ -1,19 +1,11 @@ # -*- cmake -*- -include(Prebuilt) -include(Linking) - include_guard() add_library( ll::libcurl INTERFACE IMPORTED ) -use_system_binary(libcurl) -use_prebuilt_binary(curl) - -find_library(CURL_LIBRARY - NAMES - libcurl.lib - libcurl.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::libcurl INTERFACE ${CURL_LIBRARY} ll::openssl ll::nghttp2 ll::zlib-ng) +find_package(CURL REQUIRED) +target_link_libraries(ll::libcurl INTERFACE CURL::libcurl) -target_include_directories( ll::libcurl SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) +if(LINUX OR DARWIN) + find_library(NGHTTP2_LIBRARIES nghttp2 REQUIRED) + target_link_libraries(ll::libcurl INTERFACE ${NGHTTP2_LIBRARIES}) +endif() diff --git a/indra/cmake/Collada-Dom.cmake b/indra/cmake/Collada-Dom.cmake new file mode 100644 index 00000000000..79e8ec9feab --- /dev/null +++ b/indra/cmake/Collada-Dom.cmake @@ -0,0 +1,37 @@ +# -*- cmake -*- +include_guard() +include(ZLIBNG) + +add_library( ll::colladadom INTERFACE IMPORTED ) + +find_path(COLLADA_DOM_INCLUDE_DIRS NAMES dae.h PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/collada-dom" REQUIRED NO_DEFAULT_PATH) + +target_include_directories(ll::colladadom SYSTEM INTERFACE "${COLLADA_DOM_INCLUDE_DIRS}" "${COLLADA_DOM_INCLUDE_DIRS}/1.4") + +if(WINDOWS) + target_compile_definitions(ll::colladadom INTERFACE DOM_DYNAMIC=1) +endif() + + +find_library(COLLADA14_LIBRARY_RELEASE + NAMES collada14dom + PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" + REQUIRED + NO_DEFAULT_PATH +) + +target_link_libraries(ll::colladadom INTERFACE optimized ${COLLADA14_LIBRARY_RELEASE}) + +find_library(COLLADA14_LIBRARY_DEBUG + NAMES collada14dom + PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" + NO_DEFAULT_PATH +) + +if (NOT COLLADA14_LIBRARY_DEBUG STREQUAL "COLLADA14_LIBRARY_DEBUG-NOTFOUND") + target_link_libraries(ll::colladadom INTERFACE debug ${COLLADA14_LIBRARY_DEBUG}) +endif() + +find_package(minizip CONFIG REQUIRED) +find_package(LibXml2 REQUIRED) +target_link_libraries(ll::colladadom INTERFACE LibXml2::LibXml2 MINIZIP::minizip ZLIB::ZLIB) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 9925be5fecb..888d7912150 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -3,13 +3,9 @@ # The copy_win_libs folder contains file lists and a script used to # copy dlls, exes and such needed to run the SecondLife from within # VisualStudio. - +include_guard() include(CMakeCopyIfDifferent) include(Linking) -if (USE_DISCORD) - include(Discord) -endif () -include(OPENAL) # When we copy our dependent libraries, we almost always want to copy them to # both the Release and the RelWithDebInfo staging directories. This has @@ -18,7 +14,21 @@ include(OPENAL) # Pass FROM_DIR, TARGETS and the files to copy. TO_DIR is implicit. # to_staging_dirs diverges from copy_if_different in that it appends to TARGETS. macro(to_staging_dirs from_dir targets) - set( targetDir "${SHARED_LIB_STAGING_DIR}") + set(targetDir "${SHARED_LIB_STAGING_DIR}") + copy_if_different("${from_dir}" "${targetDir}" out_targets ${ARGN}) + + list(APPEND "${targets}" "${out_targets}") +endmacro() + +macro(to_viewer_staging_dirs from_dir targets) + set(targetDir "${VIEWER_STAGING_DIR}") + copy_if_different("${from_dir}" "${targetDir}" out_targets ${ARGN}) + + list(APPEND "${targets}" "${out_targets}") +endmacro() + +macro(to_viewer_staging_subdirs sub_dir from_dir targets) + set(targetDir "${VIEWER_STAGING_DIR}/${sub_dir}") copy_if_different("${from_dir}" "${targetDir}" out_targets ${ARGN}) list(APPEND "${targets}" "${out_targets}") @@ -30,215 +40,87 @@ endmacro() if(WINDOWS) #******************************* # VIVOX - *NOTE: no debug version - set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}") - - # ND, it seems there is no such thing defined. At least when building a viewer - # Does this maybe matter on some LL buildserver? Otherwise this and the snippet using slvoice_src_dir - # can all go - if( ARCH_PREBUILT_BIN_RELEASE ) - set(slvoice_src_dir "${ARCH_PREBUILT_BIN_RELEASE}") - endif() - set(slvoice_files SLVoice.exe ) - if (ADDRESS_SIZE EQUAL 64) - list(APPEND vivox_libs - vivoxsdk_x64.dll - ortp_x64.dll - ) - else (ADDRESS_SIZE EQUAL 64) - list(APPEND vivox_libs - vivoxsdk.dll - ortp.dll - ) - endif (ADDRESS_SIZE EQUAL 64) - - #******************************* - # Misc shared libs - - set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") - set(release_files - openjp2.dll + set(vivox_lib_dir "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/slvoice/windows64") + list(APPEND vivox_libs + vivoxsdk_x64.dll + ortp_x64.dll + SLVoice.exe ) - # Filenames are different for 32/64 bit BugSplat file and we don't - # have any control over them so need to branch. - if (USE_BUGSPLAT) - if(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} BugSplat.dll) - set(release_files ${release_files} BugSplatRc.dll) - set(release_files ${release_files} BsSndRpt.exe) - else(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} BugSplat64.dll) - set(release_files ${release_files} BugSplatRc64.dll) - set(release_files ${release_files} BsSndRpt64.exe) - endif(ADDRESS_SIZE EQUAL 32) - endif (USE_BUGSPLAT) - - if (TARGET ll::discord_sdk) - list(APPEND release_files discord_partner_sdk.dll) - endif () + set(vcpkg_lib_dir "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin") - if (TARGET ll::openal) - list(APPEND release_files openal32.dll alut.dll) - endif () + # Files that vcpkg fails to automatically stage + set(release_libs "legacy.dll") # OpenSSL legacy engine #******************************* # Copy MS C runtime dlls, required for packaging. - if (MSVC80) - set(MSVC_VER 80) - elseif (MSVC_VERSION EQUAL 1600) # VisualStudio 2010 - MESSAGE(STATUS "MSVC_VERSION ${MSVC_VERSION}") - elseif (MSVC_VERSION EQUAL 1800) # VisualStudio 2013, which is (sigh) VS 12 - set(MSVC_VER 120) - elseif (MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) # Visual Studio 2017 - set(MSVC_VER 140) - set(MSVC_TOOLSET_VER 141) - elseif (MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1930) # Visual Studio 2019 - set(MSVC_VER 140) - set(MSVC_TOOLSET_VER 142) - elseif (MSVC_VERSION GREATER_EQUAL 1930 AND MSVC_VERSION LESS 1950) # Visual Studio 2022 - set(MSVC_VER 140) - set(MSVC_TOOLSET_VER 143) - elseif (MSVC_VERSION GREATER_EQUAL 1950 AND MSVC_VERSION LESS 1970) # Visual Studio 2026 - set(MSVC_VER 140) - set(MSVC_TOOLSET_VER 145) - else (MSVC80) - MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake") - endif (MSVC80) - - if (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR}) - if(ADDRESS_SIZE EQUAL 32) - set(redist_find_path "$ENV{VCTOOLSREDISTDIR}x86\\Microsoft.VC${MSVC_TOOLSET_VER}.CRT") - else(ADDRESS_SIZE EQUAL 32) - set(redist_find_path "$ENV{VCTOOLSREDISTDIR}x64\\Microsoft.VC${MSVC_TOOLSET_VER}.CRT") - endif(ADDRESS_SIZE EQUAL 32) - get_filename_component(redist_path "${redist_find_path}" ABSOLUTE) - MESSAGE(STATUS "VC Runtime redist path: ${redist_path}") - endif (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR}) - - if(ADDRESS_SIZE EQUAL 32) - # this folder contains the 32bit DLLs.. (yes really!) - set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/SysWOW64") - else(ADDRESS_SIZE EQUAL 32) - # this folder contains the 64bit DLLs.. (yes really!) - set(registry_find_path "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Windows;Directory]/System32") - endif(ADDRESS_SIZE EQUAL 32) - - # Having a string containing the system registry path is a start, but to - # get CMake to actually read the registry, we must engage some other - # operation. - get_filename_component(registry_path "${registry_find_path}" ABSOLUTE) - - # These are candidate DLL names. Empirically, VS versions before 2015 have - # msvcp*.dll and msvcr*.dll. VS 2017 has msvcp*.dll and vcruntime*.dll. - # Check each of them. - foreach(release_msvc_file - msvcp${MSVC_VER}.dll - msvcp${MSVC_VER}_1.dll - msvcp${MSVC_VER}_2.dll - msvcp${MSVC_VER}_atomic_wait.dll - msvcp${MSVC_VER}_codecvt_ids.dll - msvcr${MSVC_VER}.dll - vccorlib${MSVC_VER}.dll - vcruntime${MSVC_VER}.dll - vcruntime${MSVC_VER}_1.dll - vcruntime${MSVC_VER}_threads.dll - ) - if(redist_path AND EXISTS "${redist_path}/${release_msvc_file}") - MESSAGE(STATUS "Copying redist file from ${redist_path}/${release_msvc_file}") - to_staging_dirs( - ${redist_path} - third_party_targets - ${release_msvc_file}) - elseif(EXISTS "${registry_path}/${release_msvc_file}") - MESSAGE(STATUS "Copying redist file from ${registry_path}/${release_msvc_file}") - to_staging_dirs( - ${registry_path} - third_party_targets - ${release_msvc_file}) - else() - # This isn't a WARNING because, as noted above, every VS version - # we've observed has only a subset of the specified DLL names. - MESSAGE(STATUS "Redist lib ${release_msvc_file} not found") - endif() + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE) + include(InstallRequiredSystemLibraries) + + foreach(system_lib_file IN LISTS CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS) + get_filename_component(system_lib_directory ${system_lib_file} DIRECTORY) + get_filename_component(system_lib_filename ${system_lib_file} NAME ) + MESSAGE(DEBUG "Copying redist file from ${system_lib_directory}/${system_lib_filename}") + to_staging_dirs( + ${system_lib_directory} + third_party_targets + ${system_lib_filename} + ) + to_viewer_staging_dirs( + ${system_lib_directory} + third_party_targets + ${system_lib_filename} + ) + to_viewer_staging_subdirs( + "llplugin" + ${system_lib_directory} + third_party_targets + ${system_lib_filename} + ) endforeach() + to_viewer_staging_dirs( + ${vcpkg_lib_dir} + third_party_targets + ${release_libs} + ) + + to_viewer_staging_dirs( + ${vivox_lib_dir} + third_party_targets + ${vivox_libs} + ) elseif(DARWIN) - set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}") - set(slvoice_files SLVoice) + set(vivox_lib_dir "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/slvoice/darwin64") set(vivox_libs libortp.dylib libvivoxsdk.dylib ) - set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}") - set(debug_files - ) - set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") - set(release_files - libndofdev.dylib - ) - - if (TARGET ll::discord_sdk) - list(APPEND release_files libdiscord_partner_sdk.dylib) - endif () - - if (TARGET ll::openal) - list(APPEND release_files libalut.dylib libopenal.dylib) - endif () + set(slvoice_files SLVoice) + set(vcpkg_lib_dir "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib") + set(release_libs + "libhunspell-1.7.0.dylib" + ) elseif(LINUX) - # linux is weird, multiple side by side configurations aren't supported - # and we don't seem to have any debug shared libs built yet anyways... - set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}") - set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}") - set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}") - - set(vivox_lib_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(vivox_lib_dir "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/slvoice/linux") set(vivox_libs libsndfile.so.1 libortp.so libvivoxoal.so.1 + libvivoxplatform.so libvivoxsdk.so ) set(slvoice_files SLVoice) - # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables - # or ARCH_PREBUILT_DIRS - set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}") - set(debug_files - ) - # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables - # or ARCH_PREBUILT_DIRS - set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") - # *FIX - figure out what to do with duplicate libalut.so here -brad - set(release_files - ) - - if( USE_AUTOBUILD_3P ) - list( APPEND release_files - libSDL3.so - libSDL3.so.0 - libSDL3.so.0.2.24 - ) - endif() - + set(vcpkg_lib_dir "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib") + set(release_libs "") else(WINDOWS) message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...") - set(vivox_lib_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux") + set(vcpkg_lib_dir "") + set(vivox_lib_dir "") set(vivox_libs "") - # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables - # or ARCH_PREBUILT_DIRS - set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/debug") - set(debug_files "") - # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables - # or ARCH_PREBUILT_DIRS - set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/release") - set(release_files "") - - set(debug_llkdu_src "") - set(debug_llkdu_dst "") - set(release_llkdu_src "") - set(release_llkdu_dst "") - set(relwithdebinfo_llkdu_dst "") + set(slvoice_files "") endif(WINDOWS) @@ -246,42 +128,13 @@ endif(WINDOWS) # Done building the file lists, now set up the copy commands. ################################################################ -# Curiously, slvoice_files are only copied to SHARED_LIB_STAGING_DIR_RELEASE. -# It's unclear whether this is oversight or intentional, but anyway leave the -# single copy_if_different command rather than using to_staging_dirs. - -if( slvoice_src_dir ) - copy_if_different( - ${slvoice_src_dir} - "${SHARED_LIB_STAGING_DIR_RELEASE}" - out_targets - ${slvoice_files} - ) - list(APPEND third_party_targets ${out_targets}) -endif() - -to_staging_dirs( - ${vivox_lib_dir} - third_party_targets - ${vivox_libs} - ) - to_staging_dirs( - ${release_src_dir} + ${vcpkg_lib_dir} third_party_targets - ${release_files} - ) + ${release_libs} +) add_custom_target( stage_third_party_libs ALL DEPENDS ${third_party_targets} ) - -if(DARWIN) - # Support our "@executable_path/../Resources" load path for executables - # that end up in any of the above SHARED_LIB_STAGING_DIR_MUMBLE - # directories. - add_custom_command( TARGET stage_third_party_libs POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink ${SHARED_LIB_STAGING_DIR} ${CMAKE_BINARY_DIR}/sharedlibs/Resources - ) -endif() diff --git a/indra/cmake/CubemapToEquirectangularJS.cmake b/indra/cmake/CubemapToEquirectangularJS.cmake deleted file mode 100644 index bfe29260051..00000000000 --- a/indra/cmake/CubemapToEquirectangularJS.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# -*- cmake -*- -use_prebuilt_binary(cubemaptoequirectangular) - -# Main JS file -configure_file("${AUTOBUILD_INSTALL_DIR}/js/CubemapToEquirectangular.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/CubemapToEquirectangular.js" COPYONLY) diff --git a/indra/cmake/DeploySharedLibs.cmake b/indra/cmake/DeploySharedLibs.cmake deleted file mode 100644 index fe9ffcd8f1b..00000000000 --- a/indra/cmake/DeploySharedLibs.cmake +++ /dev/null @@ -1,70 +0,0 @@ -# DeploySharedLibs.cmake -# This is a script to be run at build time! Its not part of the cmake configuration! -# See indra/cmake/LLSharedLibs.cmake for a macro that simplifies adding a command to a target to run this script. - -# This script requires a few cmake variable to be set on the command line: -# BIN_NAME= The full path the the binary to search for dependecies. -# SEARCH_DIRS= The full paths to dirs to search for dependencies. -# DST_PATH= The full path where the dependecies will be copied. - -include(GetPrerequisites) - -message(STATUS "Getting recursive dependencies for file: ${BIN_NAME}") - -set(EXCLUDE_SYSTEM 1) -set(RECURSE 1) -get_filename_component(EXE_PATH ${BIN_NAME} PATH) - -get_prerequisites( ${BIN_NAME} RESULTS ${EXCLUDE_SYSTEM} ${RECURSE} "${EXE_PATH}" "${SEARCH_DIRS}" ) - -foreach(DEP ${RESULTS}) - Message(STATUS "Processing dependency: ${DEP}") - get_filename_component(DEP_FILE ${DEP} NAME) - set(DEP_FILES ${DEP_FILES} ${DEP_FILE}) -endforeach(DEP) - -if(DEP_FILES) - list(REMOVE_DUPLICATES DEP_FILES) -endif(DEP_FILES) - -foreach(DEP_FILE ${DEP_FILES}) - if(FOUND_FILES) - list(FIND FOUND_FILES ${DEP_FILE} FOUND) - else(FOUND_FILES) - set(FOUND -1) - endif(FOUND_FILES) - - if(FOUND EQUAL -1) - find_path(DEP_PATH ${DEP_FILE} PATHS ${SEARCH_DIRS} NO_DEFAULT_PATH) - if(DEP_PATH) - set(FOUND_FILES ${FOUND_FILES} "${DEP_PATH}/${DEP_FILE}") - set(DEP_PATH NOTFOUND) #reset DEP_PATH for the next find_path call. - else(DEP_PATH) - set(MISSING_FILES ${MISSING_FILES} ${DEP_FILE}) - endif(DEP_PATH) - endif(FOUND EQUAL -1) -endforeach(DEP_FILE) - -if(MISSING_FILES) - message("Missing:") - foreach(FILE ${MISSING_FILES}) - message(" ${FILE}") - endforeach(FILE) - message("Searched in:") - foreach(SEARCH_DIR ${SEARCH_DIRS}) - message(" ${SEARCH_DIR}") - endforeach(SEARCH_DIR) - message(FATAL_ERROR "Failed") -endif(MISSING_FILES) - -if(FOUND_FILES) - foreach(FILE ${FOUND_FILES}) - get_filename_component(DST_FILE ${FILE} NAME) - set(DST_FILE "${DST_PATH}/${DST_FILE}") - message(STATUS "Copying ${FILE} to ${DST_FILE}") - execute_process( - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FILE} ${DST_FILE} - ) - endforeach(FILE ${FOUND_FILES}) -endif(FOUND_FILES) - diff --git a/indra/cmake/Discord.cmake b/indra/cmake/Discord.cmake index 0e63d053500..d62ef92021c 100644 --- a/indra/cmake/Discord.cmake +++ b/indra/cmake/Discord.cmake @@ -1,16 +1,10 @@ -include(Prebuilt) - include_guard() -option(USE_DISCORD "Enable Discord SDK" OFF) +add_library(ll::discord_sdk INTERFACE IMPORTED) if(USE_DISCORD) - add_library(ll::discord_sdk INTERFACE IMPORTED) - target_compile_definitions(ll::discord_sdk INTERFACE LL_DISCORD=1) - use_prebuilt_binary(discord_sdk) - find_library(DISCORD_SDK_LIBRARY NAMES discord_partner_sdk diff --git a/indra/cmake/DragDrop.cmake b/indra/cmake/DragDrop.cmake deleted file mode 100644 index 26e7828830d..00000000000 --- a/indra/cmake/DragDrop.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -*- cmake -*- - -set(OS_DRAG_DROP ON CACHE BOOL "Build the viewer with OS level drag and drop turned on or off") - -if (OS_DRAG_DROP) - if (WINDOWS) - add_definitions(-DLL_OS_DRAGDROP_ENABLED=1) - endif (WINDOWS) - if (DARWIN) - add_definitions(-DLL_OS_DRAGDROP_ENABLED=1) - endif (DARWIN) - if (LINUX) - add_definitions(-DLL_OS_DRAGDROP_ENABLED=1) - endif (LINUX) -endif (OS_DRAG_DROP) - diff --git a/indra/cmake/EXPAT.cmake b/indra/cmake/EXPAT.cmake index fe6dced7959..b908ec51683 100644 --- a/indra/cmake/EXPAT.cmake +++ b/indra/cmake/EXPAT.cmake @@ -1,22 +1,6 @@ # -*- cmake -*- -include(Prebuilt) - include_guard() add_library(ll::expat INTERFACE IMPORTED) -use_system_binary(expat) -use_prebuilt_binary(expat) - -if (WINDOWS) - target_compile_definitions(ll::expat INTERFACE XML_STATIC=1) -endif () - -find_library(EXPAT_LIBRARY - NAMES - libexpat.lib - libexpat.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::expat INTERFACE ${EXPAT_LIBRARY}) - -target_include_directories(ll::expat SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) +find_package(expat CONFIG REQUIRED) +target_link_libraries(ll::expat INTERFACE expat::expat) diff --git a/indra/cmake/ExamplePlugin.cmake b/indra/cmake/ExamplePlugin.cmake deleted file mode 100644 index 62340354749..00000000000 --- a/indra/cmake/ExamplePlugin.cmake +++ /dev/null @@ -1,6 +0,0 @@ -# -*- cmake -*- -include(Linking) -include(Prebuilt) - -set(EXAMPLEPLUGIN ON CACHE BOOL - "EXAMPLEPLUGIN support for the llplugin/llmedia test apps.") diff --git a/indra/cmake/FindAutobuild.cmake b/indra/cmake/FindAutobuild.cmake deleted file mode 100644 index 79287d4e01c..00000000000 --- a/indra/cmake/FindAutobuild.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# -*- cmake -*- -# -# Find the autobuild tool -# -# Output variables: -# -# AUTOBUILD_EXECUTABLE - path to autobuild executable - - - -IF (NOT AUTOBUILD_EXECUTABLE) - - # If cmake was executed by autobuild, autobuild will have set the AUTOBUILD env var - IF (DEFINED ENV{AUTOBUILD}) - SET(AUTOBUILD_EXECUTABLE $ENV{AUTOBUILD}) - ELSE (DEFINED ENV{AUTOBUILD}) - IF(WIN32) - SET(AUTOBUILD_EXE_NAMES autobuild.exe autobuild.cmd) - ELSE(WIN32) - SET(AUTOBUILD_EXE_NAMES autobuild) - ENDIF(WIN32) - - SET(AUTOBUILD_EXECUTABLE) - FIND_PROGRAM( - AUTOBUILD_EXECUTABLE - NAMES ${AUTOBUILD_EXE_NAMES} - PATHS - ENV PATH - ${CMAKE_SOURCE_DIR}/.. - ${CMAKE_SOURCE_DIR}/../.. - ${CMAKE_SOURCE_DIR}/../../.. - PATH_SUFFIXES "/autobuild/bin/" - ) - ENDIF (DEFINED ENV{AUTOBUILD}) - - IF (NOT AUTOBUILD_EXECUTABLE) - IF (AUTOBUILD_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find autobuild executable") - ENDIF (AUTOBUILD_FIND_REQUIRED) - ENDIF (NOT AUTOBUILD_EXECUTABLE) - - MARK_AS_ADVANCED(AUTOBUILD_EXECUTABLE) -ENDIF (NOT AUTOBUILD_EXECUTABLE) diff --git a/indra/cmake/FindSCP.cmake b/indra/cmake/FindSCP.cmake deleted file mode 100644 index ea02102908e..00000000000 --- a/indra/cmake/FindSCP.cmake +++ /dev/null @@ -1,40 +0,0 @@ -# -*- cmake -*- -# -# Find the OpenSSH scp ("secure copy") or Putty pscp command. -# -# Input variables: -# SCP_FIND_REQUIRED - set this if configuration should fail without scp -# -# Output variables: -# -# SCP_FOUND - set if scp was found -# SCP_EXECUTABLE - path to scp or pscp executable -# SCP_BATCH_FLAG - how to put scp/pscp into batch mode - -SET(SCP_EXECUTABLE) -IF (WINDOWS) - FIND_PROGRAM(SCP_EXECUTABLE NAMES pscp pscp.exe) -ELSE (WINDOWS) - FIND_PROGRAM(SCP_EXECUTABLE NAMES scp scp.exe) -ENDIF (WINDOWS) - -IF (SCP_EXECUTABLE) - SET(SCP_FOUND ON) -ELSE (SCP_EXECUTABLE) - SET(SCP_FOUND OFF) -ENDIF (SCP_EXECUTABLE) - -IF (SCP_FOUND) - GET_FILENAME_COMPONENT(_scp_name ${SCP_EXECUTABLE} NAME_WE) - IF (_scp_name STREQUAL scp) - SET(SCP_BATCH_FLAG -B) - ELSE (_scp_name STREQUAL scp) - SET(SCP_BATCH_FLAG -batch) - ENDIF (_scp_name STREQUAL scp) -ELSE (SCP_FOUND) - IF (SCP_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find scp or pscp executable") - ENDIF (SCP_FIND_REQUIRED) -ENDIF (SCP_FOUND) - -MARK_AS_ADVANCED(SCP_EXECUTABLE SCP_FOUND SCP_BATCH_FLAG) diff --git a/indra/cmake/FontConfig.cmake b/indra/cmake/FontConfig.cmake new file mode 100644 index 00000000000..02d3a7e1f62 --- /dev/null +++ b/indra/cmake/FontConfig.cmake @@ -0,0 +1,10 @@ +# -*- cmake -*- +include_guard() + +if (LINUX) + add_library(ll::fontconfig INTERFACE IMPORTED) + + find_package(Fontconfig REQUIRED) + target_link_libraries(ll::fontconfig INTERFACE Fontconfig::Fontconfig) +endif (LINUX) + diff --git a/indra/cmake/FreeType.cmake b/indra/cmake/FreeType.cmake index eb018c09e99..068b6d76fc2 100644 --- a/indra/cmake/FreeType.cmake +++ b/indra/cmake/FreeType.cmake @@ -1,20 +1,6 @@ # -*- cmake -*- -include(Prebuilt) -include(Linking) -include(PNG) -include(ZLIBNG) - include_guard() -add_library( ll::freetype INTERFACE IMPORTED ) - -use_system_binary(freetype) -use_prebuilt_binary(freetype) -target_include_directories( ll::freetype SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/freetype2/) - -find_library(FREETYPE_LIBRARY - NAMES - freetype.lib - libfreetype.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) +add_library(ll::freetype INTERFACE IMPORTED) -target_link_libraries(ll::freetype INTERFACE ${FREETYPE_LIBRARY} ll::libpng ll::zlib-ng) +find_package(Freetype REQUIRED) +target_link_libraries(ll::freetype INTERFACE Freetype::Freetype) diff --git a/indra/cmake/GLEXT.cmake b/indra/cmake/GLEXT.cmake index 2124cc2fc8c..8ebb3865a27 100644 --- a/indra/cmake/GLEXT.cmake +++ b/indra/cmake/GLEXT.cmake @@ -1,8 +1,7 @@ # -*- cmake -*- -include(Prebuilt) +include_guard() add_library(ll::glext INTERFACE IMPORTED) -use_system_binary(glext) -use_prebuilt_binary(glext) - +find_path(OPENGL_REGISTRY_INCLUDE_DIRS "GL/glcorearb.h" REQUIRED) +target_include_directories(ll::glext SYSTEM INTERFACE ${OPENGL_REGISTRY_INCLUDE_DIRS}) diff --git a/indra/cmake/GLIB.cmake b/indra/cmake/GLIB.cmake index f52cbb7f871..593f47b0bf9 100644 --- a/indra/cmake/GLIB.cmake +++ b/indra/cmake/GLIB.cmake @@ -1,7 +1,5 @@ include_guard() -include(Prebuilt) - add_library( ll::glib INTERFACE IMPORTED ) add_library( ll::glib_headers INTERFACE IMPORTED ) add_library( ll::gio INTERFACE IMPORTED ) diff --git a/indra/cmake/GLM.cmake b/indra/cmake/GLM.cmake index 84b155f6c5d..1b533839f4c 100644 --- a/indra/cmake/GLM.cmake +++ b/indra/cmake/GLM.cmake @@ -1,7 +1,6 @@ # -*- cmake -*- -include(Prebuilt) +include_guard() +add_library(ll::glm INTERFACE IMPORTED) -add_library( ll::glm INTERFACE IMPORTED ) - -use_system_binary( glm ) -use_prebuilt_binary(glm) +find_package(glm CONFIG REQUIRED) +target_link_libraries(ll::glm INTERFACE glm::glm-header-only) diff --git a/indra/cmake/GStreamer10Plugin.cmake b/indra/cmake/GStreamer10Plugin.cmake index 01522db3a38..18f7f0e4db8 100644 --- a/indra/cmake/GStreamer10Plugin.cmake +++ b/indra/cmake/GStreamer10Plugin.cmake @@ -2,7 +2,6 @@ include_guard() -include(Prebuilt) include(GLIB) add_library( ll::gstreamer10 INTERFACE IMPORTED ) @@ -23,5 +22,5 @@ if (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) endif (GSTREAMER10_FOUND AND GSTREAMER10_PLUGINS_BASE_FOUND) if (GSTREAMER10) - add_definitions(-DLL_GSTREAMER10_ENABLED=1) + add_compile_definitions(LL_GSTREAMER10_ENABLED=1) endif (GSTREAMER10) diff --git a/indra/cmake/Havok.cmake b/indra/cmake/Havok.cmake index 64e33f6c83b..446c840117f 100644 --- a/indra/cmake/Havok.cmake +++ b/indra/cmake/Havok.cmake @@ -1,7 +1,12 @@ # -*- cmake -*- -include(Prebuilt) include_guard() +# TODO: Remove once Havok is integrated into vcpkg +return() + +include(Prebuilt) + + use_prebuilt_binary(havok-source) set(Havok_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/havok/Source) diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake index b063363bc02..30cd70f13df 100644 --- a/indra/cmake/Hunspell.cmake +++ b/indra/cmake/Hunspell.cmake @@ -1,24 +1,9 @@ # -*- cmake -*- -include(Linking) -include(Prebuilt) - include_guard() -use_prebuilt_binary(dictionaries) - -add_library( ll::hunspell INTERFACE IMPORTED ) -use_system_binary(hunspell) -use_prebuilt_binary(libhunspell) - -if (WINDOWS) - target_compile_definitions( ll::hunspell INTERFACE HUNSPELL_STATIC=1) -endif() -find_library(HUNSPELL_LIBRARY - NAMES - libhunspell.lib - libhunspell-1.7.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) +add_library(ll::hunspell INTERFACE IMPORTED) -target_link_libraries(ll::hunspell INTERFACE ${HUNSPELL_LIBRARY}) +find_package(PkgConfig REQUIRED) -target_include_directories( ll::hunspell SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/hunspell) +pkg_check_modules(hunspell REQUIRED IMPORTED_TARGET GLOBAL hunspell) +target_link_libraries(ll::hunspell INTERFACE PkgConfig::hunspell) diff --git a/indra/cmake/JPEG.cmake b/indra/cmake/JPEG.cmake index 49880e7f727..551e17f8178 100644 --- a/indra/cmake/JPEG.cmake +++ b/indra/cmake/JPEG.cmake @@ -1,23 +1,6 @@ # -*- cmake -*- -include(Prebuilt) - -include(Linking) - include_guard() -add_library( ll::libjpeg INTERFACE IMPORTED ) - -use_system_binary(libjpeg) -use_prebuilt_binary(libjpeg-turbo) - -find_library(JPEG_LIBRARY - NAMES - jpeg - jpeg-static - jpeg-static.lib - jpeg.lib - libjpeg.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::libjpeg INTERFACE ${JPEG_LIBRARY}) +add_library(ll::libjpeg INTERFACE IMPORTED) -target_include_directories(ll::libjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) +find_package(JPEG REQUIRED) +target_link_libraries(ll::libjpeg INTERFACE JPEG::JPEG) diff --git a/indra/cmake/JPEGEncoderBasic.cmake b/indra/cmake/JPEGEncoderBasic.cmake deleted file mode 100644 index 0d2a3231bbb..00000000000 --- a/indra/cmake/JPEGEncoderBasic.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# -*- cmake -*- -use_prebuilt_binary(jpegencoderbasic) - -# Main JS file -configure_file("${AUTOBUILD_INSTALL_DIR}/js/jpeg_encoder_basic.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/jpeg_encoder_basic.js" COPYONLY) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index bd2f894c97a..f9e66951af6 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -2,14 +2,11 @@ include_guard() -if( NOT LL_TESTS ) +if(NOT BUILD_TESTING) return() endif() -include(00-Common) include(LLTestCommand) -include(bugsplat) -include(Tut) #***************************************************************************** # LL_ADD_PROJECT_UNIT_TESTS @@ -34,23 +31,18 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) # Setup includes, paths, etc set(alltest_SOURCE_FILES ) - set(alltest_DEP_TARGETS - # needed by the test harness itself - llcommon - ) - set(alltest_LIBRARIES lltut_runner_lib llcommon + ll::tut ) if(NOT "${project}" STREQUAL "llmath") # add llmath as a dep unless the tested module *is* llmath! - list(APPEND alltest_DEP_TARGETS llmath) list(APPEND alltest_LIBRARIES llmath ) endif() # Headers, for convenience in targets. - set(alltest_HEADER_FILES ${CMAKE_SOURCE_DIR}/test/test.h) + set(alltest_HEADER_FILES ${INDRA_SOURCE_DIR}/test/test.h) # start the source test executable definitions set(${project}_TEST_OUTPUT "") @@ -95,20 +87,18 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) GET_OPT_SOURCE_FILE_PROPERTY(${name}_test_additional_INCLUDE_DIRS ${source} LL_TEST_ADDITIONAL_INCLUDE_DIRS) target_include_directories (PROJECT_${project}_TEST_${name} PRIVATE ${${name}_test_additional_INCLUDE_DIRS} ) - target_include_directories (PROJECT_${project}_TEST_${name} PRIVATE ${LIBS_OPEN_DIR}/test ) + target_include_directories (PROJECT_${project}_TEST_${name} PRIVATE ${INDRA_SOURCE_DIR}/test ${INDRA_SOURCE_DIR}/llmath ${INDRA_SOURCE_DIR}/llui) set_target_properties(PROJECT_${project}_TEST_${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}") if (DARWIN) set_target_properties(PROJECT_${project}_TEST_${name} PROPERTIES BUILD_WITH_INSTALL_RPATH 1 - INSTALL_RPATH "@executable_path/Resources" + INSTALL_RPATH "@executable_path/Frameworks" ) endif(DARWIN) - if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(PROJECT_${project}_TEST_${name} REUSE_FROM llprecompiled) - endif () + target_precompile_headers(PROJECT_${project}_TEST_${name} REUSE_FROM llprecompiled_exe) # # Per-codefile additional / external project dep and lib dep property extraction @@ -126,24 +116,31 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) # Add to project target_link_libraries(PROJECT_${project}_TEST_${name} ${alltest_LIBRARIES} ${${name}_test_additional_PROJECTS} ${${name}_test_additional_LIBRARIES} ) - add_dependencies( PROJECT_${project}_TEST_${name} ${alltest_DEP_TARGETS}) # Compile-time Definitions GET_OPT_SOURCE_FILE_PROPERTY(${name}_test_additional_CFLAGS ${source} LL_TEST_ADDITIONAL_CFLAGS) + target_compile_options(PROJECT_${project}_TEST_${name} PRIVATE ${${name}_test_additional_CFLAGS}) + + # Add to Tests folder in IDE set_target_properties(PROJECT_${project}_TEST_${name} PROPERTIES - COMPILE_FLAGS "${${name}_test_additional_CFLAGS}" - COMPILE_DEFINITIONS "LL_TEST=${name};LL_TEST_${name}" - FOLDER "Tests" + FOLDER "Tests/${project}" + ) + + target_compile_definitions(PROJECT_${project}_TEST_${name} PRIVATE + "LL_TEST=${name}" + "LL_TEST_${name}" ) + if(LL_TEST_VERBOSE) message("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_additional_CFLAGS ${${name}_test_additional_CFLAGS}") endif() - if (DARWIN) + if (WINDOWS) + target_link_options(PROJECT_${project}_TEST_${name} PRIVATE $<$:/DEBUG:NONE>) + elseif (DARWIN) # test binaries always need to be signed for local development set_target_properties(PROJECT_${project}_TEST_${name} PROPERTIES - OSX_ARCHITECTURES ${LL_MACOS_TEST_ARCHITECTURE} XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-") endif () @@ -194,6 +191,7 @@ FUNCTION(LL_ADD_INTEGRATION_TEST testname additional_source_files library_dependencies + testproject # variable args ) if(TEST_DEBUG) @@ -207,6 +205,7 @@ FUNCTION(LL_ADD_INTEGRATION_TEST set(libraries lltut_runner_lib + ll::tut ${library_dependencies} ) @@ -219,27 +218,24 @@ FUNCTION(LL_ADD_INTEGRATION_TEST set_target_properties(INTEGRATION_TEST_${testname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}" - COMPILE_DEFINITIONS "LL_TEST=${testname};LL_TEST_${testname}" - FOLDER "Tests" + FOLDER "Tests/${testproject}" ) + target_compile_definitions(INTEGRATION_TEST_${testname} PRIVATE + "LL_TEST=${testname}" + "LL_TEST_${testname}" + ) - # The following was copied to llcorehttp/CMakeLists.txt's texture_load target. - # Any changes made here should be replicated there. if (WINDOWS) - set_target_properties(INTEGRATION_TEST_${testname} - PROPERTIES - LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:CONSOLE" - ) - endif () + target_link_options(INTEGRATION_TEST_${testname} PRIVATE $<$:/DEBUG:NONE>) + endif() if (DARWIN) # test binaries always need to be signed for local development set_target_properties(INTEGRATION_TEST_${testname} PROPERTIES - OSX_ARCHITECTURES ${LL_MACOS_TEST_ARCHITECTURE} XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" BUILD_WITH_INSTALL_RPATH 1 - INSTALL_RPATH "@executable_path/Resources" + INSTALL_RPATH "@executable_path/Frameworks" ) endif () @@ -249,12 +245,8 @@ FUNCTION(LL_ADD_INTEGRATION_TEST endif() target_link_libraries(INTEGRATION_TEST_${testname} ${libraries}) - target_include_directories (INTEGRATION_TEST_${testname} PRIVATE ${LIBS_OPEN_DIR}/test ) - - if (USE_PRECOMPILED_HEADERS) - target_include_directories (INTEGRATION_TEST_${testname} PRIVATE ${LIBS_OPEN_DIR}/llmath ) - target_precompile_headers(INTEGRATION_TEST_${testname} REUSE_FROM llprecompiled) - endif () + target_include_directories (INTEGRATION_TEST_${testname} PRIVATE ${INDRA_SOURCE_DIR}/test ${INDRA_SOURCE_DIR}/llmath ${INDRA_SOURCE_DIR}/llui) + target_precompile_headers(INTEGRATION_TEST_${testname} REUSE_FROM llprecompiled_exe) # Create the test running command set(test_command ${ARGN}) @@ -303,7 +295,7 @@ MACRO(SET_TEST_PATH LISTVAR) # We typically build/package only Release variants of third-party # libraries, so append the Release staging dir in case the library being # sought doesn't have a debug variant. - set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib) + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} ${SHARED_LIB_STAGING_DIR}/Release/Frameworks /usr/lib) ELSE(WINDOWS) # Linux uses a single staging directory anyway. set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib) diff --git a/indra/cmake/LLAppearance.cmake b/indra/cmake/LLAppearance.cmake deleted file mode 100644 index bf34b13714a..00000000000 --- a/indra/cmake/LLAppearance.cmake +++ /dev/null @@ -1,10 +0,0 @@ -# -*- cmake -*- - -include(Variables) -include(Boost) -include(LLCoreHttp) - - - - - diff --git a/indra/cmake/LLAudio.cmake b/indra/cmake/LLAudio.cmake deleted file mode 100644 index c842c69bfec..00000000000 --- a/indra/cmake/LLAudio.cmake +++ /dev/null @@ -1,3 +0,0 @@ -# -*- cmake -*- - -include(Audio) diff --git a/indra/cmake/LLCA.cmake b/indra/cmake/LLCA.cmake deleted file mode 100644 index 412a5a99a49..00000000000 --- a/indra/cmake/LLCA.cmake +++ /dev/null @@ -1,4 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -use_prebuilt_binary(llca) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake deleted file mode 100644 index dd43ca49166..00000000000 --- a/indra/cmake/LLCommon.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# -*- cmake -*- - -include(APR) -include(Boost) -include(EXPAT) -include(Tracy) -include(xxHash) -include(ZLIBNG) diff --git a/indra/cmake/LLCoreHttp.cmake b/indra/cmake/LLCoreHttp.cmake deleted file mode 100644 index 22ed5fef9cb..00000000000 --- a/indra/cmake/LLCoreHttp.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# -*- cmake -*- - -include(CURL) -include(OpenSSL) -include(NGHTTP2) diff --git a/indra/cmake/LLImage.cmake b/indra/cmake/LLImage.cmake deleted file mode 100644 index 8e0b44dfe49..00000000000 --- a/indra/cmake/LLImage.cmake +++ /dev/null @@ -1,4 +0,0 @@ -# -*- cmake -*- - -#include(JPEG) -include(PNG) diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake index 03f3fd16192..efcab3ebcbb 100644 --- a/indra/cmake/LLKDU.cmake +++ b/indra/cmake/LLKDU.cmake @@ -1,36 +1,20 @@ # -*- cmake -*- - -# USE_KDU can be set when launching cmake as an option using the argument -DUSE_KDU:BOOL=ON -# When building using proprietary binaries though (i.e. having access to LL private servers), -# we always build with KDU -if (INSTALL_PROPRIETARY) - set(USE_KDU ON CACHE BOOL "Use Kakadu library.") -endif (INSTALL_PROPRIETARY) - include_guard() add_library( ll::kdu INTERFACE IMPORTED ) if (USE_KDU) - include(Prebuilt) - use_prebuilt_binary(kdu) - find_library(KDU_LIBRARY NAMES kdu kdu.lib libkdu.a - PATHS - "${ARCH_PREBUILT_DIRS_RELEASE}" - "${AUTOBUILD_INSTALL_DIR}/lib" - PATH_SUFFIXES release - REQUIRED - NO_DEFAULT_PATH) + REQUIRED) target_link_libraries(ll::kdu INTERFACE ${KDU_LIBRARY}) + find_path(KDU_INCLUDE_DIRS NAMES kdu_arch.h PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/kdu" REQUIRED NO_DEFAULT_PATH) target_include_directories( ll::kdu SYSTEM INTERFACE - ${AUTOBUILD_INSTALL_DIR}/include/kdu - ${LIBS_OPEN_DIR}/llkdu + ${KDU_INCLUDE_DIRS} ) target_compile_definitions(ll::kdu INTERFACE KDU_NO_THREADS=1) endif (USE_KDU) diff --git a/indra/cmake/LLMath.cmake b/indra/cmake/LLMath.cmake deleted file mode 100644 index e841d2ac78e..00000000000 --- a/indra/cmake/LLMath.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# -*- cmake -*- - -include(Variables) -include(Mikktspace) - diff --git a/indra/cmake/LLPhysicsExtensions.cmake b/indra/cmake/LLPhysicsExtensions.cmake index 84722b45a7e..cbd0b88d6e5 100644 --- a/indra/cmake/LLPhysicsExtensions.cmake +++ b/indra/cmake/LLPhysicsExtensions.cmake @@ -1,18 +1,15 @@ # -*- cmake -*- -include(Prebuilt) - # There are three possible solutions to provide the llphysicsextensions: # - The full source package, selected by -DHAVOK:BOOL=ON # - The stub source package, selected by -DHAVOK:BOOL=OFF # - The prebuilt package available to those with sublicenses, selected by -DHAVOK_TPV:BOOL=ON -if (INSTALL_PROPRIETARY) - set(HAVOK ON CACHE BOOL "Use Havok physics library") -endif (INSTALL_PROPRIETARY) - include_guard() add_library( llphysicsextensions_impl INTERFACE IMPORTED ) +# TODO: Reenable once Havok is integrated into vcpkg +return() + # Note that the use_prebuilt_binary macros below do not in fact include binaries; # the llphysicsextensions_* packages are source only and are built here. diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake deleted file mode 100644 index 2699f8efee1..00000000000 --- a/indra/cmake/LLPrimitive.cmake +++ /dev/null @@ -1,58 +0,0 @@ -# -*- cmake -*- - -# these should be moved to their own cmake file -include(Prebuilt) -include(Linking) -include(Boost) - -include_guard() - -add_library( ll::minizip-ng INTERFACE IMPORTED ) -add_library( ll::libxml INTERFACE IMPORTED ) -add_library( ll::colladadom INTERFACE IMPORTED ) - -# ND, needs fixup in collada conan pkg -if( USE_CONAN ) - target_include_directories( ll::colladadom SYSTEM INTERFACE - "${CONAN_INCLUDE_DIRS_COLLADADOM}/collada-dom/" - "${CONAN_INCLUDE_DIRS_COLLADADOM}/collada-dom/1.4/" ) -endif() - -use_system_binary( colladadom ) - -use_prebuilt_binary(colladadom) -use_prebuilt_binary(minizip-ng) # needed for colladadom -use_prebuilt_binary(libxml2) - -find_library(MINIZIPNG_LIBRARY - NAMES - minizip.lib - libminizip.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::minizip-ng INTERFACE ${MINIZIPNG_LIBRARY}) - -find_library(LIBXML2_LIBRARY - NAMES - libxml2.lib - libxml2.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::libxml INTERFACE ${LIBXML2_LIBRARY}) - -if (WINDOWS) - target_link_libraries( ll::libxml INTERFACE Bcrypt.lib) -endif() - -target_include_directories( ll::colladadom SYSTEM INTERFACE - ${LIBS_PREBUILT_DIR}/include/collada - ${LIBS_PREBUILT_DIR}/include/collada/1.4 - ) - -find_library(COLLADADOM_LIBRARY - NAMES - libcollada14dom23-s.lib - collada14dom - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::colladadom INTERFACE ${COLLADADOM_LIBRARY} ll::boost ll::libxml ll::minizip-ng) diff --git a/indra/cmake/LLSharedLibs.cmake b/indra/cmake/LLSharedLibs.cmake deleted file mode 100644 index 48149129d62..00000000000 --- a/indra/cmake/LLSharedLibs.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# ll_deploy_sharedlibs_command -# target_exe: the cmake target of the executable for which the shared libs will be deployed. -macro(ll_deploy_sharedlibs_command target_exe) - set(TARGET_LOCATION $) - get_filename_component(OUTPUT_PATH ${TARGET_LOCATION} PATH) - - # It's not clear that this does anything useful for us on Darwin. It has - # been broken for some time now; the BIN_NAME was being constructed as a - # ridiculous nonexistent path with duplicated segments. Fixing that only - # produces ominous spammy warnings: at the time the command below is run, we - # have not yet populated the nested mac-crash-logger.app/Contents/Resources - # with the .dylibs with which it was linked. Moreover, the form of the - # embedded @executable_path/../Resources/mumble.dylib pathname confuses the - # GetPrerequisites.cmake tool invoked by DeploySharedLibs.cmake. It seems - # clear that we have long since accomplished by other means what this was - # originally supposed to do. Skipping it only eliminates an annoying - # non-fatal error. - if(NOT DARWIN) - if(WINDOWS) - SET_TEST_PATH(SEARCH_DIRS) - LIST(APPEND SEARCH_DIRS "$ENV{SystemRoot}/system32") - elseif(LINUX) - SET_TEST_PATH(SEARCH_DIRS) - set(OUTPUT_PATH ${OUTPUT_PATH}/lib) - endif(WINDOWS) - - add_custom_command( - TARGET ${target_exe} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - "-DBIN_NAME=\"${TARGET_LOCATION}\"" - "-DSEARCH_DIRS=\"${SEARCH_DIRS}\"" - "-DDST_PATH=\"${OUTPUT_PATH}\"" - "-P" - "${CMAKE_SOURCE_DIR}/cmake/DeploySharedLibs.cmake" - ) - endif(NOT DARWIN) - -endmacro(ll_deploy_sharedlibs_command) diff --git a/indra/cmake/LLTestCommand.cmake b/indra/cmake/LLTestCommand.cmake index f75c23a5de2..07bdb803263 100644 --- a/indra/cmake/LLTestCommand.cmake +++ b/indra/cmake/LLTestCommand.cmake @@ -4,14 +4,14 @@ MACRO(LL_TEST_COMMAND OUTVAR LD_LIBRARY_PATH) # cannot return a value. And yet, variables you set inside a FUNCTION are # local. Try a MACRO instead. SET(value - ${PYTHON_EXECUTABLE} - "${CMAKE_SOURCE_DIR}/cmake/run_build_test.py") + ${Python3_EXECUTABLE} + "${INDRA_SOURCE_DIR}/cmake/run_build_test.py") FOREACH(dir ${LD_LIBRARY_PATH}) LIST(APPEND value "-l${dir}") ENDFOREACH(dir) - # Enough different tests want to be able to find CMake's PYTHON_EXECUTABLE + # Enough different tests want to be able to find CMake's Python3_EXECUTABLE # that we should just pop it into the environment for everybody. - LIST(APPEND value "-DPYTHON=${PYTHON_EXECUTABLE}") + LIST(APPEND value "-DPYTHON=${Python3_EXECUTABLE}") LIST(APPEND value ${ARGN}) SET(${OUTVAR} ${value}) ##IF(LL_TEST_VERBOSE) diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake deleted file mode 100644 index 1f12dec1f65..00000000000 --- a/indra/cmake/LLWindow.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -*- cmake -*- -include_guard() - -include(Variables) -include(Prebuilt) -include(GLEXT) -include(SDL3) diff --git a/indra/cmake/LibVLCPlugin.cmake b/indra/cmake/LibVLCPlugin.cmake index a38c660a339..ba01e1bb664 100644 --- a/indra/cmake/LibVLCPlugin.cmake +++ b/indra/cmake/LibVLCPlugin.cmake @@ -1,35 +1,16 @@ # -*- cmake -*- -include(Linking) -include(Prebuilt) - include_guard() -add_library( ll::libvlc INTERFACE IMPORTED ) - -set(LIBVLCPLUGIN ON CACHE BOOL - "LIBVLCPLUGIN support for the llplugin/llmedia test apps.") - -if (LIBVLCPLUGIN) - if(LINUX) - find_package(PkgConfig REQUIRED) - - pkg_check_modules(libvlc REQUIRED IMPORTED_TARGET libvlc) - target_link_libraries( ll::libvlc INTERFACE PkgConfig::libvlc) - return() - endif() - - use_prebuilt_binary(vlc-bin) - find_library(VLC_LIBRARY - NAMES - libvlc.lib - libvlc.dylib - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) +add_library(ll::libvlc INTERFACE IMPORTED) - find_library(VLCCORE_LIBRARY - NAMES - libvlccore.lib - libvlccore.dylib - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) +if(WINDOWS OR DARWIN) + find_library(LIBVLC_LIBRARY_RELEASE NAMES vlc PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" NO_DEFAULT_PATH REQUIRED) + find_library(LIBVLCCORE_LIBRARY_RELEASE NAMES vlccore PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" NO_DEFAULT_PATH REQUIRED) + target_link_libraries(ll::libvlc INTERFACE ${LIBVLC_LIBRARY_RELEASE} ${LIBVLCCORE_LIBRARY_RELEASE}) + target_include_directories(ll::libvlc SYSTEM INTERFACE ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include) +else() + find_package(PkgConfig REQUIRED) - target_link_libraries(ll::libvlc INTERFACE ${VLC_LIBRARY} ${VLCCORE_LIBRARY}) + pkg_check_modules(libvlc REQUIRED IMPORTED_TARGET libvlc) + target_link_libraries(ll::libvlc INTERFACE PkgConfig::libvlc) endif() diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake index 900a64e2dd4..4f525cfa5b5 100644 --- a/indra/cmake/Linking.cmake +++ b/indra/cmake/Linking.cmake @@ -3,55 +3,37 @@ include_guard() include(Variables) -set(ARCH_PREBUILT_DIRS ${AUTOBUILD_INSTALL_DIR}/lib) -set(ARCH_PREBUILT_DIRS_PLUGINS ${AUTOBUILD_INSTALL_DIR}/plugins) -set(ARCH_PREBUILT_DIRS_RELEASE ${AUTOBUILD_INSTALL_DIR}/lib/release) -set(ARCH_PREBUILT_DIRS_DEBUG ${AUTOBUILD_INSTALL_DIR}/lib/debug) -if (WINDOWS OR DARWIN ) - # Kludge for older cmake versions, 3.20+ is needed to use a genex in add_custom_command( OUTPUT ... ) - # Using this will work okay-ish, as Debug is not supported anyway. But for property multi config and also - # ninja support the genex version is preferred. - if(${CMAKE_VERSION} VERSION_LESS "3.20.0") - if(CMAKE_BUILD_TYPE MATCHES Release) - set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/Release) - elseif (CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) - set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/RelWithDebInfo) - endif() - else() - set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/$,$,>) - set(SYMBOLS_STAGING_DIR ${CMAKE_BINARY_DIR}/symbols/$,$,>/${VIEWER_CHANNEL}) - endif() +set(SYMBOLS_STAGING_DIR ${INDRA_BINARY_DIR}/symbols/$,$/,>${VIEWER_CHANNEL}) - if( DARWIN ) - set( SHARED_LIB_STAGING_DIR ${SHARED_LIB_STAGING_DIR}/Resources) +if (WINDOWS OR DARWIN) + set(SHARED_LIB_STAGING_DIR ${INDRA_BINARY_DIR}/sharedlibs/$,$,>) + + if(DARWIN) + set(SHARED_LIB_STAGING_DIR ${SHARED_LIB_STAGING_DIR}/Frameworks) + set(VIEWER_STAGING_DIR ${INDRA_BINARY_DIR}/newview/$,$,>) + else() + set(VIEWER_STAGING_DIR ${INDRA_BINARY_DIR}/newview/$,$,packaged>) endif() - set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/$,$,>) -elseif (LINUX) - set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/lib) - set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/bin) -endif () + set(EXE_STAGING_DIR ${INDRA_BINARY_DIR}/sharedlibs/$,$,>) +elseif(LINUX) + set(SHARED_LIB_STAGING_DIR ${INDRA_BINARY_DIR}/sharedlibs/$,$,>/lib) + set(EXE_STAGING_DIR ${INDRA_BINARY_DIR}/sharedlibs/$,$,>/bin) + set(VIEWER_STAGING_DIR ${INDRA_BINARY_DIR}/newview/$,$,packaged>) +endif() -# Autobuild packages must provide 'release' versions of libraries, but may provide versions for -# specific build types. AUTOBUILD_LIBS_INSTALL_DIRS lists first the build type directory and then -# the 'release' directory (as a default fallback). -# *NOTE - we have to take special care to use CMAKE_CFG_INTDIR on IDE generators (like mac and -# windows) and CMAKE_BUILD_TYPE on Makefile based generators (like linux). The reason for this is -# that CMAKE_BUILD_TYPE is essentially meaningless at configuration time for IDE generators and -# CMAKE_CFG_INTDIR is meaningless at build time for Makefile generators -if(NOT DARWIN) - link_directories(${AUTOBUILD_INSTALL_DIR}/lib/$>) - link_directories(${AUTOBUILD_INSTALL_DIR}/lib/release) -endif(NOT DARWIN) +# Setup threading options +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) -add_library( ll::oslibraries INTERFACE IMPORTED ) +add_library(ll::oslibraries INTERFACE IMPORTED) -if (LINUX) - target_link_libraries( ll::oslibraries INTERFACE - dl - pthread +if(LINUX) + target_link_libraries(ll::oslibraries INTERFACE + ${CMAKE_DL_LIBS} + Threads::Threads rt) elseif (WINDOWS) - target_link_libraries( ll::oslibraries INTERFACE + target_link_libraries(ll::oslibraries INTERFACE advapi32 shell32 ws2_32 @@ -65,7 +47,7 @@ elseif (WINDOWS) ole32 dbghelp rpcrt4.lib - legacy_stdio_definitions + Threads::Threads ) else() find_library(COREFOUNDATION_LIBRARY CoreFoundation) @@ -87,6 +69,7 @@ else() ${COREAUDIO_LIBRARY} ${AUDIOTOOLBOX_LIBRARY} ${COREGRAPHICS_LIBRARY} + Threads::Threads ) endif() diff --git a/indra/cmake/Meshoptimizer.cmake b/indra/cmake/Meshoptimizer.cmake index af1c51f032a..71b53cba545 100644 --- a/indra/cmake/Meshoptimizer.cmake +++ b/indra/cmake/Meshoptimizer.cmake @@ -1,20 +1,6 @@ # -*- cmake -*- - -include(Linking) -include(Prebuilt) - include_guard() -add_library( ll::meshoptimizer INTERFACE IMPORTED ) - -use_system_binary(meshoptimizer) -use_prebuilt_binary(meshoptimizer) - -find_library(MESHOPTIMIZER_LIBRARY - NAMES - meshoptimizer.lib - libmeshoptimizer.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::meshoptimizer INTERFACE ${MESHOPTIMIZER_LIBRARY}) +add_library(ll::meshoptimizer INTERFACE IMPORTED) -target_include_directories(ll::meshoptimizer SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/meshoptimizer) +find_package(meshoptimizer CONFIG REQUIRED) +target_link_libraries(ll::meshoptimizer INTERFACE meshoptimizer::meshoptimizer) diff --git a/indra/cmake/Mikktspace.cmake b/indra/cmake/Mikktspace.cmake index 9fd2becba4f..ca9d502e9e9 100644 --- a/indra/cmake/Mikktspace.cmake +++ b/indra/cmake/Mikktspace.cmake @@ -1,6 +1,5 @@ # -*- cmake -*- -include(Prebuilt) +include_guard() +add_library(ll::mikktspace INTERFACE IMPORTED) +target_include_directories(ll::mikktspace SYSTEM INTERFACE ${INDRA_SOURCE_DIR}/externals/mikktspace/) -if (NOT USESYSTEMLIBS) - use_prebuilt_binary(mikktspace) -endif (NOT USESYSTEMLIBS) diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake index 60b29a57fe4..4156e78910a 100644 --- a/indra/cmake/NDOF.cmake +++ b/indra/cmake/NDOF.cmake @@ -1,32 +1,37 @@ # -*- cmake -*- -include(Prebuilt) - -set(NDOF ON CACHE BOOL "Use NDOF space navigator joystick library.") - include_guard() -add_library( ll::ndof INTERFACE IMPORTED ) +add_library(ll::ndof INTERFACE IMPORTED) -if (NDOF) - if (WINDOWS OR DARWIN) - use_prebuilt_binary(libndofdev) - elseif (LINUX) - use_prebuilt_binary(open-libndofdev) - endif (WINDOWS OR DARWIN) +if (USE_NDOF) + target_compile_definitions(ll::ndof INTERFACE LIB_NDOF=1) - find_library(NDOF_LIBRARY - NAMES - libndofdev - ndofdev - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) + find_library(NDOF_LIBRARY_RELEASE + NAMES + libndofdev + ndofdev + PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" + REQUIRED + NO_DEFAULT_PATH + ) + + target_link_libraries(ll::ndof INTERFACE optimized ${NDOF_LIBRARY_RELEASE}) + + find_library(NDOF_LIBRARY_DEBUG + NAMES + libndofdev + ndofdev + PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" + NO_DEFAULT_PATH + ) + + if (NOT NDOF_LIBRARY_DEBUG STREQUAL "NDOF_LIBRARY_DEBUG-NOTFOUND") + target_link_libraries(ll::ndof INTERFACE debug ${NDOF_LIBRARY_DEBUG}) + endif() if (LINUX) include(SDL3) - target_link_libraries(ll::ndof INTERFACE ${NDOF_LIBRARY} ll::SDL3) - else() - target_link_libraries(ll::ndof INTERFACE ${NDOF_LIBRARY}) + target_link_libraries(ll::ndof INTERFACE ll::SDL3) endif() - - target_compile_definitions(ll::ndof INTERFACE LIB_NDOF=1) -endif (NDOF) +endif (USE_NDOF) diff --git a/indra/cmake/NGHTTP2.cmake b/indra/cmake/NGHTTP2.cmake deleted file mode 100644 index e81204d7166..00000000000 --- a/indra/cmake/NGHTTP2.cmake +++ /dev/null @@ -1,17 +0,0 @@ -include(Linking) -include(Prebuilt) - -include_guard() -add_library( ll::nghttp2 INTERFACE IMPORTED ) - -use_system_binary(nghttp2) -use_prebuilt_binary(nghttp2) - -find_library(NGHTTP2_LIBRARY - NAMES - nghttp2.lib - libnghttp2.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::nghttp2 INTERFACE ${NGHTTP2_LIBRARY}) -target_include_directories( ll::nghttp2 SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/nghttp2) diff --git a/indra/cmake/NVAPI.cmake b/indra/cmake/NVAPI.cmake index ff5a5428e09..39dbcaa4a86 100644 --- a/indra/cmake/NVAPI.cmake +++ b/indra/cmake/NVAPI.cmake @@ -1,13 +1,12 @@ # -*- cmake -*- -include(Prebuilt) +include_guard() -set(NVAPI ON CACHE BOOL "Use NVAPI.") +add_library(ll::nvapi INTERFACE IMPORTED) -if (NVAPI) +if (USE_NVAPI) if (WINDOWS) - add_library( ll::nvapi INTERFACE IMPORTED ) - target_link_libraries( ll::nvapi INTERFACE nvapi) - use_prebuilt_binary(nvapi) + find_library(NVAPI_LIBRARY nvapi64 REQUIRED) + target_link_libraries(ll::nvapi INTERFACE ${NVAPI_LIBRARY}) endif (WINDOWS) -endif (NVAPI) +endif (USE_NVAPI) diff --git a/indra/cmake/NanoSVG.cmake b/indra/cmake/NanoSVG.cmake new file mode 100644 index 00000000000..746ee5dbdcc --- /dev/null +++ b/indra/cmake/NanoSVG.cmake @@ -0,0 +1,6 @@ +# -*- cmake -*- +include_guard() +add_library(ll::nanosvg INTERFACE IMPORTED) + +find_package(NanoSVG CONFIG REQUIRED) +target_link_libraries(ll::nanosvg INTERFACE NanoSVG::nanosvg NanoSVG::nanosvgrast) diff --git a/indra/cmake/OPENAL.cmake b/indra/cmake/OPENAL.cmake deleted file mode 100644 index 523a2d16f66..00000000000 --- a/indra/cmake/OPENAL.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# -*- cmake -*- -include(Linking) -include(Prebuilt) - -include_guard() - -# ND: Turn this off by default, the openal code in the viewer isn't very well maintained, seems -# to have memory leaks, has no option to play music streams -# It probably makes sense to to completely remove it - -set(USE_OPENAL ON CACHE BOOL "Enable OpenAL") -# ND: To streamline arguments passed, switch from OPENAL to USE_OPENAL -# To not break all old build scripts convert old arguments but warn about it -if(OPENAL) - message( WARNING "Use of the OPENAL argument is deprecated, please switch to USE_OPENAL") - set(USE_OPENAL ${OPENAL}) -endif() - -if (USE_OPENAL) - add_library( ll::openal INTERFACE IMPORTED ) - target_include_directories( ll::openal SYSTEM INTERFACE "${LIBS_PREBUILT_DIR}/include/AL") - target_compile_definitions( ll::openal INTERFACE LL_OPENAL=1) - use_prebuilt_binary(openal) - - find_library(OPENAL_LIBRARY - NAMES - OpenAL32 - openal - OpenAL32.lib - libopenal.dylib - libopenal.so - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - find_library(ALUT_LIBRARY - NAMES - alut - alut.lib - libalut.dylib - libalut.so - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - - target_link_libraries(ll::openal INTERFACE ${OPENAL_LIBRARY} ${ALUT_LIBRARY}) - -endif () diff --git a/indra/cmake/OpenAL.cmake b/indra/cmake/OpenAL.cmake new file mode 100644 index 00000000000..fe8ea573d62 --- /dev/null +++ b/indra/cmake/OpenAL.cmake @@ -0,0 +1,11 @@ +# -*- cmake -*- +include_guard() + +if (USE_OPENAL) + add_library( ll::openal INTERFACE IMPORTED ) + target_compile_definitions( ll::openal INTERFACE LL_OPENAL=1) + + find_package(OpenAL CONFIG REQUIRED) + find_package(FreeALUT CONFIG REQUIRED) + target_link_libraries(ll::openal INTERFACE FreeALUT::alut OpenAL::OpenAL) +endif () diff --git a/indra/cmake/OpenGL.cmake b/indra/cmake/OpenGL.cmake index bf7cd8366a9..59feaa42c73 100644 --- a/indra/cmake/OpenGL.cmake +++ b/indra/cmake/OpenGL.cmake @@ -1,6 +1,4 @@ # -*- cmake -*- - -include(Variables) -include(Prebuilt) -include(FindOpenGL) +include_guard() +find_package(OpenGL REQUIRED) diff --git a/indra/cmake/OpenJPEG.cmake b/indra/cmake/OpenJPEG.cmake index 95e71fd78e8..b198baa5c39 100644 --- a/indra/cmake/OpenJPEG.cmake +++ b/indra/cmake/OpenJPEG.cmake @@ -1,22 +1,6 @@ # -*- cmake -*- include_guard() +add_library(ll::openjpeg INTERFACE IMPORTED) -include(Prebuilt) -include(Linking) - -add_library( ll::openjpeg INTERFACE IMPORTED ) - -use_system_binary(openjpeg) -use_prebuilt_binary(openjpeg) - -find_library(OPENJPEG_LIBRARY - NAMES - openjp2 - openjp2.lib - libopenjp2.a - libopenjp2.so - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::openjpeg INTERFACE ${OPENJPEG_LIBRARY}) - -target_include_directories(ll::openjpeg SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/openjpeg) +find_package(OpenJPEG CONFIG REQUIRED) +target_link_libraries(ll::openjpeg INTERFACE openjp2) diff --git a/indra/cmake/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake index 9d33f2e0dec..b7e10a4b197 100644 --- a/indra/cmake/OpenSSL.cmake +++ b/indra/cmake/OpenSSL.cmake @@ -1,30 +1,6 @@ # -*- cmake -*- -include(Prebuilt) -include(Linking) - include_guard() add_library( ll::openssl INTERFACE IMPORTED ) -use_system_binary(openssl) -use_prebuilt_binary(openssl) - -find_library(SSL_LIBRARY - NAMES - libssl.lib - libssl.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -find_library(CRYPTO_LIBRARY - NAMES - libcrypto.lib - libcrypto.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::openssl INTERFACE ${SSL_LIBRARY} ${CRYPTO_LIBRARY}) - -if (WINDOWS) - target_link_libraries(ll::openssl INTERFACE Crypt32.lib) -endif (WINDOWS) - -target_include_directories(ll::openssl SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) - +find_package(OpenSSL REQUIRED) +target_link_libraries(ll::openssl INTERFACE OpenSSL::SSL OpenSSL::Crypto) diff --git a/indra/cmake/OpenXR.cmake b/indra/cmake/OpenXR.cmake index 7cc1be634b4..a0c0c552d96 100644 --- a/indra/cmake/OpenXR.cmake +++ b/indra/cmake/OpenXR.cmake @@ -1,25 +1,7 @@ # -*- cmake -*- - -include(Prebuilt) - include_guard() -add_library( ll::openxr INTERFACE IMPORTED ) - -option(USE_OPENXR "Enable building with OpenXR support" OFF) +add_library(ll::openxr INTERFACE IMPORTED) if(USE_OPENXR) - if(USE_CONAN ) - target_link_libraries( ll::openxr INTERFACE CONAN_PKG::openxr ) - return() - endif() - - use_prebuilt_binary(openxr) - if (WINDOWS) - target_link_libraries( ll::openxr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/openxr_loader.lib ) - else() - target_link_libraries( ll::openxr INTERFACE ${ARCH_PREBUILT_DIRS_RELEASE}/libopenxr_loader.a ) - endif (WINDOWS) - - if( NOT LINUX ) - target_include_directories( ll::openxr SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include) - endif() + find_package(OpenXR CONFIG REQUIRED) + target_link_libraries(ll::openxr INTERFACE OpenXR::headers OpenXR::openxr_loader) endif() diff --git a/indra/cmake/PNG.cmake b/indra/cmake/PNG.cmake index 6a66f40385e..0e77c506daa 100644 --- a/indra/cmake/PNG.cmake +++ b/indra/cmake/PNG.cmake @@ -1,19 +1,6 @@ # -*- cmake -*- -include(Prebuilt) -include(Linking) -include(ZLIBNG) - include_guard() -add_library( ll::libpng INTERFACE IMPORTED ) - -use_system_binary(libpng) -use_prebuilt_binary(libpng) - -find_library(LIBPNG_LIBRARY - NAMES - libpng16.lib - libpng16.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) +add_library(ll::libpng INTERFACE IMPORTED) -target_link_libraries(ll::libpng INTERFACE ${LIBPNG_LIBRARY} ll::zlib-ng) -target_include_directories(ll::libpng SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/libpng16) +find_package(PNG REQUIRED) +target_link_libraries(ll::libpng INTERFACE PNG::PNG) diff --git a/indra/cmake/PluginAPI.cmake b/indra/cmake/PluginAPI.cmake index a2bf13db2c9..a660aa201ad 100644 --- a/indra/cmake/PluginAPI.cmake +++ b/indra/cmake/PluginAPI.cmake @@ -1,4 +1,5 @@ # -*- cmake -*- +include_guard() include(OpenGL) @@ -17,4 +18,4 @@ endif (WINDOWS) target_link_libraries( ll::pluginlibraries INTERFACE OpenGL::GL) -target_include_directories( ll::pluginlibraries INTERFACE ${CMAKE_SOURCE_DIR}/llimage ${CMAKE_SOURCE_DIR}/llrender) +target_include_directories( ll::pluginlibraries INTERFACE ${INDRA_SOURCE_DIR}/llimage ${INDRA_SOURCE_DIR}/llrender) diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake deleted file mode 100644 index d0ab341d949..00000000000 --- a/indra/cmake/Prebuilt.cmake +++ /dev/null @@ -1,71 +0,0 @@ -# -*- cmake -*- -include_guard() - -include(FindAutobuild) - -set(PREBUILD_TRACKING_DIR ${AUTOBUILD_INSTALL_DIR}/cmake_tracking) -# For the library installation process; -# see cmake/Prebuild.cmake for the counterpart code. -if ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${PREBUILD_TRACKING_DIR}/sentinel_installed") - file(MAKE_DIRECTORY ${PREBUILD_TRACKING_DIR}) - file(WRITE ${PREBUILD_TRACKING_DIR}/sentinel_installed "0") -endif ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${PREBUILD_TRACKING_DIR}/sentinel_installed") - -# The use_prebuilt_binary macro handles automated installation of package -# dependencies using autobuild. The goal is that 'autobuild install' should -# only be run when we know we need to install a new package. This should be -# the case in a clean checkout, or if autobuild.xml has been updated since the -# last run (encapsulated by the file ${PREBUILD_TRACKING_DIR}/sentinel_installed), -# or if a previous attempt to install the package has failed (the exit status -# of previous attempts is serialized in the file -# ${PREBUILD_TRACKING_DIR}/${_binary}_installed) -macro (use_prebuilt_binary _binary) - if( NOT DEFINED ${_binary}_installed ) - set( ${_binary}_installed "") - endif() - - if("${${_binary}_installed}" STREQUAL "" AND EXISTS "${PREBUILD_TRACKING_DIR}/${_binary}_installed") - file(READ ${PREBUILD_TRACKING_DIR}/${_binary}_installed "${_binary}_installed") - if(DEBUG_PREBUILT) - message(STATUS "${_binary}_installed: \"${${_binary}_installed}\"") - endif(DEBUG_PREBUILT) - endif("${${_binary}_installed}" STREQUAL "" AND EXISTS "${PREBUILD_TRACKING_DIR}/${_binary}_installed") - - if(${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0) - if(DEBUG_PREBUILT) - message(STATUS "cd ${CMAKE_SOURCE_DIR} && ${AUTOBUILD_EXECUTABLE} install - --install-dir=${AUTOBUILD_INSTALL_DIR} - ${_binary} ") - endif(DEBUG_PREBUILT) - message(STATUS "Installing ${_binary}...") - execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}" - install - --skip-source-environment - --install-dir=${AUTOBUILD_INSTALL_DIR} - ${_binary} - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" - RESULT_VARIABLE ${_binary}_installed - ) - file(WRITE ${PREBUILD_TRACKING_DIR}/${_binary}_installed "${${_binary}_installed}") - endif(${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0) - - if(NOT ${_binary}_installed EQUAL 0) - message(FATAL_ERROR - "Failed to download or unpack prebuilt '${_binary}'." - " Process returned ${${_binary}_installed}.") - endif (NOT ${_binary}_installed EQUAL 0) -endmacro (use_prebuilt_binary _binary) - -#Sadly we need a macro here, otherwise the return() will not properly work -macro ( use_system_binary package ) - if( USE_CONAN ) - target_link_libraries( ll::${package} INTERFACE CONAN_PKG::${package} ) - foreach( extra_pkg "${ARGN}" ) - if( extra_pkg ) - target_link_libraries( ll::${package} INTERFACE CONAN_PKG::${extra_pkg} ) - endif() - endforeach() - return() - endif() -endmacro() - diff --git a/indra/cmake/PulseAudio.cmake b/indra/cmake/PulseAudio.cmake deleted file mode 100644 index 303db97db6c..00000000000 --- a/indra/cmake/PulseAudio.cmake +++ /dev/null @@ -1,4 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -message( FATAL_ERROR "Pulseaudio cmake file is broken" ) diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index 428f9e33267..0683bafbf5c 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -1,3 +1,5 @@ +include_guard() + # Allow explicit Python path via environment variable if(DEFINED ENV{PYTHON}) set(Python3_ROOT_DIR "$ENV{PYTHON}") @@ -10,9 +12,8 @@ if(WINDOWS) set(Python3_FIND_REGISTRY FIRST CACHE STRING "Python search order") endif() +# We always want to find the active virtual env first +set(Python3_FIND_VIRTUALENV FIRST) + # Find Python 3 interpreter find_package(Python3 REQUIRED COMPONENTS Interpreter) - -# Set legacy variable name for compatibility with existing code -set(PYTHON_EXECUTABLE "${Python3_EXECUTABLE}" CACHE FILEPATH "Python interpreter for builds") -mark_as_advanced(PYTHON_EXECUTABLE) diff --git a/indra/cmake/SDL3.cmake b/indra/cmake/SDL3.cmake index fe9012de171..eb884a0c697 100644 --- a/indra/cmake/SDL3.cmake +++ b/indra/cmake/SDL3.cmake @@ -1,26 +1,10 @@ # -*- cmake -*- include_guard() -include(Linking) -include(Prebuilt) - add_library(ll::SDL3 INTERFACE IMPORTED) -if (LINUX) - set(USE_SDL_WINDOW ON CACHE BOOL "Build with SDL window backend") -else() - set(USE_SDL_WINDOW OFF CACHE BOOL "Build with SDL window backend") -endif (LINUX) - -if(USE_SDL_WINDOW) - use_system_binary(SDL3) - use_prebuilt_binary(SDL3) - - find_library( SDL3_LIBRARY - NAMES SDL3 SDL3.lib libSDL3.so libSDL3.dylib - PATHS "${LIBS_PREBUILT_DIR}/lib/release" REQUIRED) - - target_link_libraries(ll::SDL3 INTERFACE ${SDL3_LIBRARY}) - target_include_directories(ll::SDL3 SYSTEM INTERFACE "${LIBS_PREBUILT_DIR}/include/") - -endif(USE_SDL_WINDOW) +if(NOT USE_SDL_WINDOW) + return() +endif() +find_package(SDL3 CONFIG REQUIRED) +target_link_libraries(ll::SDL3 INTERFACE SDL3::SDL3) diff --git a/indra/cmake/SSE2NEON.cmake b/indra/cmake/SSE2NEON.cmake index 797f2af80e2..612f74ec4ee 100644 --- a/indra/cmake/SSE2NEON.cmake +++ b/indra/cmake/SSE2NEON.cmake @@ -1,12 +1,8 @@ # -*- cmake -*- - -include(Prebuilt) - +include_guard() add_library(ll::sse2neon INTERFACE IMPORTED) -if (DARWIN) - use_system_binary(sse2neon) - use_prebuilt_binary(sse2neon) - - target_include_directories( ll::sse2neon SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/sse2neon) +if(DARWIN OR BUILD_TARGET_IS_ARM64) + find_path(SSE2NEON_INCLUDE_DIRS "sse2neon/sse2neon.h" REQUIRED) + target_include_directories(ll::sse2neon SYSTEM INTERFACE ${SSE2NEON_INCLUDE_DIRS}) endif() diff --git a/indra/cmake/TemplateCheck.cmake b/indra/cmake/TemplateCheck.cmake index 2fada2eda97..f4968b22b6d 100644 --- a/indra/cmake/TemplateCheck.cmake +++ b/indra/cmake/TemplateCheck.cmake @@ -2,11 +2,14 @@ include(Python) +set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py") +set(TEMPLATE_VERIFIER_MASTER_URL "https://github.com/secondlife/master-message-template/raw/master/message_template.msg" CACHE STRING "Location of the master message template") + macro (check_message_template _target) add_custom_command( TARGET ${_target} PRE_LINK - COMMAND ${PYTHON_EXECUTABLE} + COMMAND ${Python3_EXECUTABLE} ARGS ${SCRIPTS_DIR}/template_verifier.py --mode=development --cache_master --master_url=${TEMPLATE_VERIFIER_MASTER_URL} ${TEMPLATE_VERIFIER_OPTIONS} COMMENT "Verifying message template - See http://wiki.secondlife.com/wiki/Template_verifier.py" diff --git a/indra/cmake/ThreeJS.cmake b/indra/cmake/ThreeJS.cmake deleted file mode 100644 index 528adcbb25b..00000000000 --- a/indra/cmake/ThreeJS.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# -*- cmake -*- -use_prebuilt_binary(threejs) - -# Main three.js file -configure_file("${AUTOBUILD_INSTALL_DIR}/js/three.min.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/three.min.js" COPYONLY) - -# Controls to move around the scene using mouse or keyboard -configure_file("${AUTOBUILD_INSTALL_DIR}/js/OrbitControls.js" "${CMAKE_SOURCE_DIR}/newview/skins/default/html/common/equirectangular/js/OrbitControls.js" COPYONLY) diff --git a/indra/cmake/TinyEXR.cmake b/indra/cmake/TinyEXR.cmake index e741c07f6e5..c0f53cb70e3 100644 --- a/indra/cmake/TinyEXR.cmake +++ b/indra/cmake/TinyEXR.cmake @@ -1,7 +1,6 @@ # -*- cmake -*- -include(Prebuilt) - -use_prebuilt_binary(tinyexr) - -set(TINYEXR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinyexr) +include_guard() +add_library(ll::tinyexr INTERFACE IMPORTED) +find_package(tinyexr CONFIG REQUIRED) +target_link_libraries(ll::tinyexr INTERFACE unofficial::tinyexr::tinyexr) diff --git a/indra/cmake/TinyGLTF.cmake b/indra/cmake/TinyGLTF.cmake index 92b2de309fe..244ba443894 100644 --- a/indra/cmake/TinyGLTF.cmake +++ b/indra/cmake/TinyGLTF.cmake @@ -1,7 +1,6 @@ # -*- cmake -*- -include(Prebuilt) - -use_prebuilt_binary(tinygltf) - -set(TINYGLTF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tinygltf) +include_guard() +add_library( ll::tinygltf INTERFACE IMPORTED ) +find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h" REQUIRED) +target_include_directories(ll::tinygltf SYSTEM INTERFACE ${TINYGLTF_INCLUDE_DIRS}) diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake index cb09337d15e..4e8c418aebd 100644 --- a/indra/cmake/Tracy.cmake +++ b/indra/cmake/Tracy.cmake @@ -1,42 +1,20 @@ # -*- cmake -*- -include(Prebuilt) - include_guard() -add_library( ll::tracy INTERFACE IMPORTED ) - -# default Tracy profiling on for test builds, but off for all others -string(TOLOWER ${VIEWER_CHANNEL} channel_lower) -if(channel_lower MATCHES "^second life test") - option(USE_TRACY "Use Tracy profiler." ON) -else() - option(USE_TRACY "Use Tracy profiler." OFF) -endif() +add_library(ll::tracy INTERFACE IMPORTED) if (USE_TRACY) - option(USE_TRACY_ON_DEMAND "Use on-demand Tracy profiling." ON) - option(USE_TRACY_LOCAL_ONLY "Disallow remote Tracy profiling." OFF) - option(USE_TRACY_GPU "Use Tracy GPU profiling" OFF) - - use_system_binary(tracy) - use_prebuilt_binary(tracy) - - target_include_directories( ll::tracy SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/tracy) - - target_compile_definitions(ll::tracy INTERFACE -DTRACY_ENABLE=1 -DTRACY_ONLY_IPV4=1) - - if (USE_TRACY_ON_DEMAND) - target_compile_definitions(ll::tracy INTERFACE -DTRACY_ON_DEMAND=1) - endif () - - if (USE_TRACY_LOCAL_ONLY) - target_compile_definitions(ll::tracy INTERFACE -DTRACY_NO_BROADCAST=1 -DTRACY_ONLY_LOCALHOST=1) - endif () + find_package(Tracy CONFIG REQUIRED) if (USE_TRACY_GPU AND NOT DARWIN) # Tracy OpenGL mode is incompatible with macOS/iOS - target_compile_definitions(ll::tracy INTERFACE -DLL_PROFILER_ENABLE_TRACY_OPENGL=1) + target_compile_definitions(ll::tracy INTERFACE LL_PROFILER_ENABLE_TRACY_OPENGL=1) endif () # See: indra/llcommon/llprofiler.h - add_compile_definitions(LL_PROFILER_CONFIGURATION=3) + # Additionally we only want tracy support in RelWithDebInfo and Release builds. + target_compile_definitions(ll::tracy INTERFACE $<$:LL_PROFILER_CONFIGURATION=3> $<$:LL_PROFILER_CONFIGURATION=1>) + target_link_libraries(ll::tracy INTERFACE $<$:Tracy::TracyClient>) +else() + # See: indra/llcommon/llprofiler.h + target_compile_definitions(ll::tracy INTERFACE LL_PROFILER_CONFIGURATION=1) endif (USE_TRACY) diff --git a/indra/cmake/Tut.cmake b/indra/cmake/Tut.cmake index ad938308033..711038c1656 100644 --- a/indra/cmake/Tut.cmake +++ b/indra/cmake/Tut.cmake @@ -1,4 +1,4 @@ # -*- cmake -*- -include(Prebuilt) - -use_prebuilt_binary(tut) +include_guard() +add_library(ll::tut INTERFACE IMPORTED) +target_include_directories(ll::tut SYSTEM INTERFACE ${INDRA_SOURCE_DIR}/externals/tut/) diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index f2776b21e15..1f8e7ac11f7 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -1,21 +1,17 @@ # -*- cmake -*- -include(Prebuilt) +include_guard() + include(FreeType) include(GLIB) -include_guard() -add_library( ll::uilibraries INTERFACE IMPORTED ) +add_library(ll::uilibraries INTERFACE IMPORTED) if (LINUX) - if( USE_CONAN ) - return() - endif() - find_package(PkgConfig REQUIRED) pkg_check_modules(WAYLAND_CLIENT wayland-client) if(WAYLAND_CLIENT_FOUND) - target_include_directories(ll::uilibraries INTERFACE ${WAYLAND_CLIENT_INCLUDE_DIRS}) + target_include_directories(ll::uilibraries SYSTEM INTERFACE ${WAYLAND_CLIENT_INCLUDE_DIRS}) target_compile_definitions(ll::uilibraries INTERFACE LL_WAYLAND=1) else() message("pkgconfig could not find wayland client, compiling without full wayland support") @@ -29,19 +25,23 @@ if (LINUX) endif() - target_link_libraries( ll::uilibraries INTERFACE + target_link_libraries(ll::uilibraries INTERFACE ll::fontconfig ll::freetype - ll::SDL3 ll::glib ll::gio ) - -endif (LINUX) -if( WINDOWS ) - target_link_libraries( ll::uilibraries INTERFACE +elseif(DARWIN) + target_link_libraries(ll::uilibraries INTERFACE + ${CARBON_LIBRARY} + ) +elseif(WINDOWS) + target_link_libraries(ll::uilibraries INTERFACE + comdlg32 # Common Dialogs for ChooseColor + ole32 + dxgi + d3d9 opengl32 - comdlg32 dxguid kernel32 odbc32 @@ -54,8 +54,3 @@ if( WINDOWS ) imm32 ) endif() - -target_include_directories( ll::uilibraries SYSTEM INTERFACE - ${LIBS_PREBUILT_DIR}/include - ) - diff --git a/indra/cmake/VHACD.cmake b/indra/cmake/VHACD.cmake index 9f37f32b2d8..be856dcaabe 100644 --- a/indra/cmake/VHACD.cmake +++ b/indra/cmake/VHACD.cmake @@ -1,9 +1,6 @@ # -*- cmake -*- -include(Prebuilt) - +include_guard() add_library(ll::vhacd INTERFACE IMPORTED) -use_system_binary(vhacd) -use_prebuilt_binary(vhacd) - -target_include_directories(ll::vhacd SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/vhacd/) +find_path(V_HACD_INCLUDE_DIRS "VHACD.h" REQUIRED) +target_include_directories(ll::vhacd SYSTEM INTERFACE ${V_HACD_INCLUDE_DIRS}) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 81a8f87cd37..4e5b85a79d2 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -11,213 +11,48 @@ include_guard() -# Switches set here and in 00-Common.cmake must agree with -# https://bitbucket.org/lindenlab/viewer-build-variables/src/tip/variables -# Reading $LL_BUILD is an attempt to directly use those switches. -if ("$ENV{AUTOBUILD_ADDRSIZE}" STREQUAL "" AND "${AUTOBUILD_ADDRSIZE_ENV}" STREQUAL "" ) - message(FATAL_ERROR "Environment variable AUTOBUILD_ADDRSIZE must be set") -elseif("$ENV{AUTOBUILD_ADDRSIZE}" STREQUAL "") - set( ENV{AUTOBUILD_ADDRSIZE} "${AUTOBUILD_ADDRSIZE_ENV}" ) - message( "Setting ENV{AUTOBUILD_ADDRSIZE} to cached variable ${AUTOBUILD_ADDRSIZE_ENV}" ) +# Location of scripts directory +set(SCRIPTS_DIR ${INDRA_SOURCE_DIR}/../scripts) + +# Select arch based on requested target processor +string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} processor_lower) +if(processor_lower STREQUAL "arm64" OR processor_lower STREQUAL "aarch64") + set(ARCH arm64) + set(BUILD_TARGET_IS_ARM64 ON CACHE INTERNAL "ARM64 BUILD" FORCE) else() - set( AUTOBUILD_ADDRSIZE_ENV "$ENV{AUTOBUILD_ADDRSIZE}" CACHE STRING "Save environment AUTOBUILD_ADDRSIZE" FORCE ) -endif () - -if ("$ENV{AUTOBUILD_PLATFORM}" STREQUAL "" AND "${AUTOBUILD_PLATFORM_ENV}" STREQUAL "" ) - message(FATAL_ERROR "Environment variable AUTOBUILD_PLATFORM must be set") -elseif("$ENV{AUTOBUILD_PLATFORM}" STREQUAL "") - set( ENV{AUTOBUILD_PLATFORM} "${AUTOBUILD_PLATFORM_ENV}" ) - message( "Setting ENV{AUTOBUILD_PLATFORM} to cached variable ${AUTOBUILD_PLATFORM_ENV}" ) -else() - set( AUTOBUILD_PLATFORM_ENV "$ENV{AUTOBUILD_PLATFORM}" CACHE STRING "Save environment AUTOBUILD_PLATFORM" FORCE ) -endif () - -# Switches set here and in 00-Common.cmake must agree with -# https://bitbucket.org/lindenlab/viewer-build-variables/src/tip/variables -# Reading $LL_BUILD is an attempt to directly use those switches. -if ("$ENV{LL_BUILD_RELEASE}" STREQUAL "" AND "${LL_BUILD_RELEASE_ENV}" STREQUAL "" ) - message(FATAL_ERROR "Environment variable LL_BUILD_RELEASE must be set") -elseif("$ENV{LL_BUILD_RELEASE}" STREQUAL "") - set( ENV{LL_BUILD_RELEASE} "${LL_BUILD_RELEASE_ENV}" ) - message( "Setting ENV{LL_BUILD_RELEASE} to cached variable ${LL_BUILD_RELEASE_ENV}" ) -else() - set( LL_BUILD_RELEASE_ENV "$ENV{LL_BUILD_RELEASE}" CACHE STRING "Save environment RELEASE" FORCE ) -endif () - -if ("$ENV{LL_BUILD_RELWITHDEBINFO}" STREQUAL "" AND "${LL_BUILD_RELWITHDEBINFO_ENV}" STREQUAL "" ) - message(FATAL_ERROR "Environment variable LL_BUILD_RELWITHDEBINFO must be set") -elseif("$ENV{LL_BUILD_RELWITHDEBINFO}" STREQUAL "") - set( ENV{LL_BUILD_RELWITHDEBINFO} "${LL_BUILD_RELWITHDEBINFO_ENV}" ) - message( "Setting ENV{LL_BUILD_RELWITHDEBINFO} to cached variable ${LL_BUILD_RELWITHDEBINFO_ENV}" ) -else() - set( LL_BUILD_RELWITHDEBINFO_ENV "$ENV{LL_BUILD_RELWITHDEBINFO}" CACHE STRING "Save environment RELWITHDEBINFO" FORCE ) -endif () - -# Relative and absolute paths to subtrees. -if(NOT DEFINED COMMON_CMAKE_DIR) - set(COMMON_CMAKE_DIR "${CMAKE_SOURCE_DIR}/cmake") -endif(NOT DEFINED COMMON_CMAKE_DIR) - -set(LIBS_CLOSED_PREFIX) -set(LIBS_OPEN_PREFIX) -set(SCRIPTS_PREFIX ../scripts) -set(VIEWER_PREFIX) -set(INTEGRATION_TESTS_PREFIX) -set(LL_TESTS OFF CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation") -set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)") -set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism") -set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files") - -if(LIBS_CLOSED_DIR) - file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR) -else(LIBS_CLOSED_DIR) - set(LIBS_CLOSED_DIR ${CMAKE_SOURCE_DIR}/${LIBS_CLOSED_PREFIX}) -endif(LIBS_CLOSED_DIR) -if(LIBS_COMMON_DIR) - file(TO_CMAKE_PATH "${LIBS_COMMON_DIR}" LIBS_COMMON_DIR) -else(LIBS_COMMON_DIR) - set(LIBS_COMMON_DIR ${CMAKE_SOURCE_DIR}/${LIBS_OPEN_PREFIX}) -endif(LIBS_COMMON_DIR) -set(LIBS_OPEN_DIR ${LIBS_COMMON_DIR}) - -set(SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/${SCRIPTS_PREFIX}) -set(VIEWER_DIR ${CMAKE_SOURCE_DIR}/${VIEWER_PREFIX}) - -set(AUTOBUILD_INSTALL_DIR ${CMAKE_BINARY_DIR}/packages) - -set(LIBS_PREBUILT_DIR ${AUTOBUILD_INSTALL_DIR} CACHE PATH - "Location of prebuilt libraries.") - -if (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) - # We use this as a marker that you can try to use the proprietary libraries. - set(INSTALL_PROPRIETARY ON CACHE BOOL "Install proprietary binaries") -endif (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) -set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py") -set(TEMPLATE_VERIFIER_MASTER_URL "https://github.com/secondlife/master-message-template/raw/master/message_template.msg" CACHE STRING "Location of the master message template") - -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING - "Build type. One of: Release RelWithDebInfo" FORCE) -endif (NOT CMAKE_BUILD_TYPE) - -# If someone has specified an address size, use that to determine the -# architecture. Otherwise, let the architecture specify the address size. -if (ADDRESS_SIZE EQUAL 32) - set(ARCH i686) -elseif (ADDRESS_SIZE EQUAL 64) set(ARCH x86_64) -else (ADDRESS_SIZE EQUAL 32) - # Note we cannot use if(DARWIN) here, this variable is set way lower - if( ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" ) - set(ADDRESS_SIZE 64) - set(ARCH x86_64) - else() - # Use Python's platform.machine() since uname -m isn't available everywhere. - # Even if you can assume cygwin uname -m, the answer depends on whether - # you're running 32-bit cygwin or 64-bit cygwin! But even 32-bit Python will - # report a 64-bit processor. - execute_process(COMMAND - "${PYTHON_EXECUTABLE}" "-c" - "import platform; print( platform.machine() )" - OUTPUT_VARIABLE ARCH OUTPUT_STRIP_TRAILING_WHITESPACE) - string( REGEX MATCH ".*(64)$" RE_MATCH "${ARCH}" ) - if( RE_MATCH AND ${CMAKE_MATCH_1} STREQUAL "64" ) - set(ADDRESS_SIZE 64) - set(ARCH x86_64) - else() - set(ADDRESS_SIZE 32) - set(ARCH i686) - endif() - endif() -endif (ADDRESS_SIZE EQUAL 32) - -if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - set(WINDOWS ON BOOL FORCE) -endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - -if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(LINUX ON BOOl FORCE) - - if (ADDRESS_SIZE EQUAL 32) - set(DEB_ARCHITECTURE i386) - set(FIND_LIBRARY_USE_LIB64_PATHS OFF) - set(CMAKE_SYSTEM_LIBRARY_PATH /usr/lib32 ${CMAKE_SYSTEM_LIBRARY_PATH}) - else (ADDRESS_SIZE EQUAL 32) - set(DEB_ARCHITECTURE amd64) - set(FIND_LIBRARY_USE_LIB64_PATHS ON) - endif (ADDRESS_SIZE EQUAL 32) - - execute_process(COMMAND dpkg-architecture -a${DEB_ARCHITECTURE} -qDEB_HOST_MULTIARCH - RESULT_VARIABLE DPKG_RESULT - OUTPUT_VARIABLE DPKG_ARCH - OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) - #message (STATUS "DPKG_RESULT ${DPKG_RESULT}, DPKG_ARCH ${DPKG_ARCH}") - if (DPKG_RESULT EQUAL 0) - set(CMAKE_LIBRARY_ARCHITECTURE ${DPKG_ARCH}) - set(CMAKE_SYSTEM_LIBRARY_PATH /usr/lib/${DPKG_ARCH} /usr/local/lib/${DPKG_ARCH} ${CMAKE_SYSTEM_LIBRARY_PATH}) - endif (DPKG_RESULT EQUAL 0) - - # Only turn on headless if we can find osmesa libraries. - find_package(PkgConfig) - pkg_check_modules(OSMESA IMPORTED_TARGET GLOBAL osmesa) - if (OSMESA_FOUND) - set(BUILD_HEADLESS ON CACHE BOOL "Build headless libraries.") - endif (OSMESA_FOUND) - -endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - -if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(DARWIN 1) + set(BUILD_TARGET_IS_X86_64 ON CACHE INTERNAL "X86_64 BUILD" FORCE) +endif() - string(REGEX MATCH "-mmacosx-version-min=([^ ]+)" scratch "$ENV{LL_BUILD}") - set(CMAKE_OSX_DEPLOYMENT_TARGET "${CMAKE_MATCH_1}" CACHE STRING "macOS Deploy Target" FORCE) - message(STATUS "CMAKE_OSX_DEPLOYMENT_TARGET = '${CMAKE_OSX_DEPLOYMENT_TARGET}'") +# Only 64-bit architectures are supported +set(ADDRESS_SIZE 64) - # Use dwarf symbols for most libraries for compilation speed - set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf") - - string(REGEX MATCH "-O([^ ]*)" scratch "$ENV{LL_BUILD}") - set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL "${CMAKE_MATCH_1}") - message(STATUS "CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL = '${CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL}'") +# Determine build platform +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(WINDOWS ON CACHE INTERNAL "Windows Build" FORCE) +elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(LINUX ON CACHE INTERNAL "Linux Build" FORCE) +elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(DARWIN ON CACHE INTERNAL "Darwin Build" FORCE) +endif () - set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) - set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO) - set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS sse4.2) - # we must hard code this to off for now. xcode's built in signing does not - # handle embedded app bundles such as CEF and others. Any signing for local - # development must be done after the build as we do in viewer_manifest.py for - # released builds - # https://stackoverflow.com/a/54296008 - # With Xcode 14.1, apparently you must take drastic steps to prevent - # implicit signing. - set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED NO) - set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED NO) - # "-" represents "Sign to Run Locally" and empty string represents "Do Not Sign" - set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "") - set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "") - set(CMAKE_XCODE_ATTRIBUTE_DISABLE_MANUAL_TARGET_ORDER_BUILD_WARNING YES) - set(CMAKE_XCODE_ATTRIBUTE_GCC_WARN_64_TO_32_BIT_CONVERSION NO) - set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "macOS Build Arch" FORCE) - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") - set(LL_MACOS_TEST_ARCHITECTURE "arm64") +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(COMPILER_IS_MSVC ON CACHE INTERNAL "MSVC BUILD" FORCE) +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + set(COMPILER_IS_CLANG_CL ON CACHE INTERNAL "CLANG-CL BUILD" FORCE) else() - set(LL_MACOS_TEST_ARCHITECTURE "x86_64") + set(COMPILER_IS_CLANG ON CACHE INTERNAL "CLANG BUILD" FORCE) endif() -endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - -# Default deploy grid -set(GRID agni CACHE STRING "Target Grid") - -set(VIEWER_CHANNEL "Second Life Test" CACHE STRING "Viewer Channel Name") - -set(ENABLE_SIGNING OFF CACHE BOOL "Enable signing the viewer") -set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if necessary.") - -set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside") - -set(USE_PRECOMPILED_HEADERS ON CACHE BOOL "Enable use of precompiled header directives where supported.") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(COMPILER_IS_GCC ON CACHE INTERNAL "GCC BUILD" FORCE) +endif () -source_group("CMake Rules" FILES CMakeLists.txt) +# Check if generator is multiconfig get_property(LL_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +# Compatibility with legacy cmake flags +if(DEFINED LL_TESTS) + set(BUILD_TESTING ${LL_TESTS} CACHE BOOL "Build and run unit and integration tests: disable for build timing runs to reduce variation" FORCE) +endif() diff --git a/indra/cmake/ViewerManager.cmake b/indra/cmake/ViewerManager.cmake deleted file mode 100644 index 7150ffc4d17..00000000000 --- a/indra/cmake/ViewerManager.cmake +++ /dev/null @@ -1,3 +0,0 @@ -include (Prebuilt) -use_prebuilt_binary(viewer-manager) - diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake deleted file mode 100644 index 23fd477ba89..00000000000 --- a/indra/cmake/ViewerMiscLibs.cmake +++ /dev/null @@ -1,20 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -if (LINUX) - #use_prebuilt_binary(libuuid) - add_library( ll::fontconfig INTERFACE IMPORTED ) - - find_package(Fontconfig REQUIRED) - target_link_libraries( ll::fontconfig INTERFACE Fontconfig::Fontconfig ) -endif (LINUX) - -if( NOT USE_CONAN ) - use_prebuilt_binary(libhunspell) -endif() - -use_prebuilt_binary(slvoice) - -use_prebuilt_binary(nanosvg) -use_prebuilt_binary(viewer-fonts) -use_prebuilt_binary(emoji_shortcodes) diff --git a/indra/cmake/VisualLeakDetector.cmake b/indra/cmake/VisualLeakDetector.cmake deleted file mode 100644 index 6a20148b47b..00000000000 --- a/indra/cmake/VisualLeakDetector.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -*- cmake -*- - - set(INCLUDE_VLD_CMAKE OFF CACHE BOOL "Build the Windows viewer with Visual Leak Detector turned on or off") - - if (INCLUDE_VLD_CMAKE) - - if (WINDOWS) - add_definitions(-DINCLUDE_VLD=1) - endif (WINDOWS) - - endif (INCLUDE_VLD_CMAKE) - diff --git a/indra/cmake/Vorbis.cmake b/indra/cmake/Vorbis.cmake new file mode 100644 index 00000000000..dd2e57b8c6a --- /dev/null +++ b/indra/cmake/Vorbis.cmake @@ -0,0 +1,6 @@ +# -*- cmake -*- +include_guard() +add_library(ll::vorbis INTERFACE IMPORTED) + +find_package(Vorbis CONFIG REQUIRED) +target_link_libraries(ll::vorbis INTERFACE Vorbis::vorbisfile Vorbis::vorbisenc Vorbis::vorbis) diff --git a/indra/cmake/VulkanGltf.cmake b/indra/cmake/VulkanGltf.cmake deleted file mode 100644 index 94541d53073..00000000000 --- a/indra/cmake/VulkanGltf.cmake +++ /dev/null @@ -1,5 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -use_prebuilt_binary(vulkan_gltf) - diff --git a/indra/cmake/WebRTC.cmake b/indra/cmake/WebRTC.cmake index 7fefaa41522..7d9b681b028 100644 --- a/indra/cmake/WebRTC.cmake +++ b/indra/cmake/WebRTC.cmake @@ -1,24 +1,16 @@ # -*- cmake -*- include_guard() -include(Linking) -include(Prebuilt) +add_library(ll::webrtc INTERFACE IMPORTED) -add_library( ll::webrtc INTERFACE IMPORTED ) -target_include_directories( ll::webrtc SYSTEM INTERFACE "${LIBS_PREBUILT_DIR}/include/webrtc" "${LIBS_PREBUILT_DIR}/include/webrtc/third_party/abseil-cpp") -use_prebuilt_binary(webrtc) - -find_library(WEBRTC_LIBRARY - NAMES - webrtc - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries( ll::webrtc INTERFACE ${WEBRTC_LIBRARY} ) +find_library(WEBRTC_LIBRARY_RELEASE NAMES webrtc PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" REQUIRED NO_DEFAULT_PATH) +target_link_libraries(ll::webrtc INTERFACE ${WEBRTC_LIBRARY_RELEASE}) +target_include_directories(ll::webrtc SYSTEM INTERFACE "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/webrtc" "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/webrtc/third_party/abseil-cpp") if (DARWIN) - target_link_libraries( ll::webrtc INTERFACE ll::oslibraries ) + target_link_libraries(ll::webrtc INTERFACE ll::oslibraries) elseif (LINUX) - target_link_libraries( ll::webrtc INTERFACE X11 ) + target_link_libraries(ll::webrtc INTERFACE X11) endif () diff --git a/indra/cmake/ZLIBNG.cmake b/indra/cmake/ZLIBNG.cmake index 9f8f12d973a..65144b0b2fe 100644 --- a/indra/cmake/ZLIBNG.cmake +++ b/indra/cmake/ZLIBNG.cmake @@ -1,26 +1,7 @@ # -*- cmake -*- -include(Prebuilt) -include(Linking) - include_guard() -add_library( ll::zlib-ng INTERFACE IMPORTED ) - -if(USE_CONAN ) - target_link_libraries( ll::zlib-ng INTERFACE CONAN_PKG::zlib ) - return() -endif() - -use_prebuilt_binary(zlib-ng) - -find_library(ZLIBNG_LIBRARY - NAMES - zlib.lib - libz.a - PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH) - -target_link_libraries(ll::zlib-ng INTERFACE ${ZLIBNG_LIBRARY}) +add_library(ll::zlib-ng INTERFACE IMPORTED) -if( NOT LINUX ) - target_include_directories( ll::zlib-ng SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/zlib-ng) -endif() +find_package(ZLIB REQUIRED) +target_link_libraries(ll::zlib-ng INTERFACE ZLIB::ZLIB) diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake index 0ba12e68ebc..1dc5a8e3aaf 100644 --- a/indra/cmake/bugsplat.cmake +++ b/indra/cmake/bugsplat.cmake @@ -1,49 +1,35 @@ -if (INSTALL_PROPRIETARY AND NOT LINUX) - # Note that viewer_manifest.py makes decision based on BUGSPLAT_DB and not USE_BUGSPLAT - if (BUGSPLAT_DB) - set(USE_BUGSPLAT ON CACHE BOOL "Use the BugSplat crash reporting system") - else (BUGSPLAT_DB) - set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") - endif (BUGSPLAT_DB) -else () - set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system") - set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name") -endif () - include_guard() -add_library( ll::bugsplat INTERFACE IMPORTED ) +add_library(ll::bugsplat INTERFACE IMPORTED) -if (USE_BUGSPLAT AND NOT LINUX) - include(Prebuilt) - use_prebuilt_binary(bugsplat) - if (WINDOWS) - target_link_libraries( ll::bugsplat INTERFACE - ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib - ) - target_include_directories( ll::bugsplat SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/bugsplat) - elseif (DARWIN) - find_library(BUGSPLAT_LIBRARIES BugsplatMac REQUIRED - NO_DEFAULT_PATH PATHS "${ARCH_PREBUILT_DIRS_RELEASE}") - find_library(CRASHREPORTED_LIBRARIES CrashReporter REQUIRED - NO_DEFAULT_PATH PATHS "${ARCH_PREBUILT_DIRS_RELEASE}") - find_library(HOCKEYSDK_LIBRARIES HockeySDK REQUIRED - NO_DEFAULT_PATH PATHS "${ARCH_PREBUILT_DIRS_RELEASE}") - target_link_libraries( ll::bugsplat INTERFACE +if(USE_BUGSPLAT AND NOT LINUX) + if(WINDOWS) + find_library(BUGSPLAT_LIBRARIES BugSplat64 REQUIRED) + target_link_libraries( ll::bugsplat INTERFACE ${BUGSPLAT_LIBRARIES}) + + find_path(BUGSPLAT_INCLUDE_DIRS "bugsplat/BugSplat.h" REQUIRED) + target_include_directories(ll::bugsplat SYSTEM INTERFACE ${BUGSPLAT_INCLUDE_DIRS}) + elseif(DARWIN) + find_library(BUGSPLAT_LIBRARIES BugSplatMac REQUIRED) + target_link_libraries(ll::bugsplat INTERFACE ${BUGSPLAT_LIBRARIES} - ${CRASHREPORTED_LIBRARIES} - ${HOCKEYSDK_LIBRARIES} ) - else (WINDOWS) + else () message(FATAL_ERROR "BugSplat is not supported; add -DUSE_BUGSPLAT=OFF") - endif (WINDOWS) + endif() if( NOT BUGSPLAT_DB ) - message( FATAL_ERROR "You need to set BUGSPLAT_DB when setting USE_BUGSPLAT" ) + message(FATAL_ERROR "You need to set BUGSPLAT_DB when setting USE_BUGSPLAT") endif() - set_property( TARGET ll::bugsplat APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS LL_BUGSPLAT) -else() - set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system" FORCE) - set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name" FORCE) -endif () + target_compile_definitions(ll::bugsplat INTERFACE LL_BUGSPLAT=1) +endif() +if (USE_BUGSPLAT) + if (BUGSPLAT_DB) + message(STATUS "Building with BugSplat; database '${BUGSPLAT_DB}'") + else (BUGSPLAT_DB) + message(WARNING "Building with BugSplat, but no database name set (BUGSPLAT_DB)") + endif (BUGSPLAT_DB) +else (USE_BUGSPLAT) + message(STATUS "Not building with BugSplat") +endif (USE_BUGSPLAT) diff --git a/indra/cmake/xxHash.cmake b/indra/cmake/xxHash.cmake index e4f8517d9bf..81c75b8b982 100644 --- a/indra/cmake/xxHash.cmake +++ b/indra/cmake/xxHash.cmake @@ -1,5 +1,7 @@ # -*- cmake -*- include_guard() -include(Prebuilt) -use_prebuilt_binary(xxhash) +add_library(ll::xxhash INTERFACE IMPORTED) + +find_package(xxHash CONFIG REQUIRED) +target_link_libraries(ll::xxhash INTERFACE xxHash::xxhash) diff --git a/indra/copy_win_scripts/CMakeLists.txt b/indra/copy_win_scripts/CMakeLists.txt index 93a8c1d6d21..aec8f9ab669 100644 --- a/indra/copy_win_scripts/CMakeLists.txt +++ b/indra/copy_win_scripts/CMakeLists.txt @@ -1,35 +1,35 @@ # -*- cmake -*- -# The copy_win_scripts folder contains scripts handy for launching the +# The copy_win_scripts folder contains scripts handy for launching the # from the windows command line on windows. -# The cmake target created copies the scripts to the -# build directory being used, which where the scripts +# The cmake target created copies the scripts to the +# build directory being used, which where the scripts # need to be executed from. include(CMakeCopyIfDifferent) -set(win_scripts-src ${CMAKE_SOURCE_DIR}/copy_win_scripts) -set(win_scripts-dst ${CMAKE_BINARY_DIR}/batch) +set(win_scripts-src ${INDRA_SOURCE_DIR}/copy_win_scripts) +set(win_scripts-dst ${INDRA_BINARY_DIR}/batch) set(file-list - llstart.py - start-client.py - start-servers.py + llstart.py + start-client.py + start-servers.py stop-servers.py user_config.py ) foreach(file ${file-list}) - if(EXISTS ${win_scripts-src}/${file}) + if(EXISTS ${win_scripts-src}/${file}) set(win_scripts-files ${win_scripts-files} ${file}) endif(EXISTS ${win_scripts-src}/${file}) endforeach(file ${file-list}) copy_if_different( - ${win_scripts-src} - ${win_scripts-dst} - win_scripts-targets - ${win_scripts-files} + ${win_scripts-src} + ${win_scripts-dst} + win_scripts-targets + ${win_scripts-files} ) add_custom_target(copy_win_scripts ALL DEPENDS ${win_scripts-targets}) diff --git a/indra/externals/README.md b/indra/externals/README.md new file mode 100644 index 00000000000..7f7774aa07e --- /dev/null +++ b/indra/externals/README.md @@ -0,0 +1,7 @@ +# Externals + +This directory contains vendored external resources which are unsuited for vcpkg or upstream are no longer active + +* js - ThreeJS and JPEGEncoder +* mikktspace - Blender Mikktspace - code relatively static and unchanging +* tut - TUT unit testing library - Upstream inactive \ No newline at end of file diff --git a/indra/externals/js/CUBEMAPTOEQUIRECTANGULAR_LICENSE.txt b/indra/externals/js/CUBEMAPTOEQUIRECTANGULAR_LICENSE.txt new file mode 100644 index 00000000000..03b02499f58 --- /dev/null +++ b/indra/externals/js/CUBEMAPTOEQUIRECTANGULAR_LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Jaume Sanchez Elias, http://www.clicktorelease.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/indra/externals/js/CubemapToEquirectangular.js b/indra/externals/js/CubemapToEquirectangular.js new file mode 100644 index 00000000000..27ac5bf9753 --- /dev/null +++ b/indra/externals/js/CubemapToEquirectangular.js @@ -0,0 +1,208 @@ +// Copyright (C) 2016 Jaume Sanchez Elias, http://www.clicktorelease.com +// https://github.com/spite/THREE.CubemapToEquirectangular +// +// Modified by Callum Prentice (callum@lindenlab.com) 2021-07-28 to use +// external jpeg encoder and write XMP metadata + +(function () { + "use strict"; + + var root = this; + + var has_require = typeof require !== "undefined"; + + var THREE = root.THREE || (has_require && require("three")); + if (!THREE) throw new Error("CubemapToEquirectangular requires three.js"); + + var vertexShader = ` +attribute vec3 position; +attribute vec2 uv; + +uniform mat4 projectionMatrix; +uniform mat4 modelViewMatrix; + +varying vec2 vUv; + +void main() { + + vUv = vec2( 1.- uv.x, uv.y ); + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + +} +`; + + var fragmentShader = ` +precision mediump float; + +uniform samplerCube map; + +varying vec2 vUv; + +#define M_PI 3.1415926535897932384626433832795 + +void main() { + + vec2 uv = vUv; + + float longitude = uv.x * 2. * M_PI - M_PI + M_PI / 2.; + float latitude = uv.y * M_PI; + + vec3 dir = vec3( + - sin( longitude ) * sin( latitude ), + cos( latitude ), + - cos( longitude ) * sin( latitude ) + ); + normalize( dir ); + + gl_FragColor = vec4( textureCube( map, dir ).rgb, 1. ); + +} +`; + + function CubemapToEquirectangular(renderer, provideCubeCamera, eqr_width, eqr_height) { + this.width = 1; + this.height = 1; + + this.renderer = renderer; + + this.material = new THREE.RawShaderMaterial({ + uniforms: { + map: { type: "t", value: null }, + }, + vertexShader: vertexShader, + fragmentShader: fragmentShader, + side: THREE.DoubleSide, + }); + + this.scene = new THREE.Scene(); + this.quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(1, 1), this.material); + this.scene.add(this.quad); + this.camera = new THREE.OrthographicCamera(1 / -2, 1 / 2, 1 / 2, 1 / -2, -10000, 10000); + + this.canvas = document.createElement("canvas"); + this.ctx = this.canvas.getContext("2d"); + + this.cubeCamera = null; + this.attachedCamera = null; + + this.setSize(eqr_width, eqr_height); + + var gl = this.renderer.getContext(); + this.cubeMapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE); + + if (provideCubeCamera) { + this.getCubeCamera(eqr_height); + } + } + + CubemapToEquirectangular.prototype.setSize = function (width, height) { + this.width = width; + this.height = height; + + this.quad.scale.set(this.width, this.height, 1); + + this.camera.left = this.width / -2; + this.camera.right = this.width / 2; + this.camera.top = this.height / 2; + this.camera.bottom = this.height / -2; + + this.camera.updateProjectionMatrix(); + + this.output = new THREE.WebGLRenderTarget(this.width, this.height, { + minFilter: THREE.LinearFilter, + magFilter: THREE.LinearFilter, + wrapS: THREE.ClampToEdgeWrapping, + wrapT: THREE.ClampToEdgeWrapping, + format: THREE.RGBAFormat, + type: THREE.UnsignedByteType, + }); + + this.canvas.width = this.width; + this.canvas.height = this.height; + }; + + CubemapToEquirectangular.prototype.getCubeCamera = function (size) { + var options = { + format: THREE.RGBAFormat, + magFilter: THREE.LinearFilter, + minFilter: THREE.LinearFilter, + }; + const renderTarget = new THREE.WebGLCubeRenderTarget(size, options); + this.cubeCamera = new THREE.CubeCamera(0.1, 1000, renderTarget); + + return this.cubeCamera; + }; + + CubemapToEquirectangular.prototype.attachCubeCamera = function (camera) { + this.getCubeCamera(); + this.attachedCamera = camera; + }; + + // http://stackoverflow.com/a/5100158/603983 + CubemapToEquirectangular.prototype.dataURItoBlob = function (dataURI) { + // convert base64/URLEncoded data component to raw binary data held in a string + var byteString; + if (dataURI.split(",")[0].indexOf("base64") >= 0) byteString = atob(dataURI.split(",")[1]); + else byteString = unescape(dataURI.split(",")[1]); + + // separate out the mime component + var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0]; + + // write the bytes of the string to a typed array + var ia = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + return new Blob([ia], { type: mimeString }); + }; + + CubemapToEquirectangular.prototype.convert = function (cubeCamera, suggested_filename, xmp_details) { + this.quad.material.uniforms.map.value = cubeCamera.renderTarget.texture; + this.renderer.setRenderTarget(this.output); + this.renderer.render(this.scene, this.camera); + + var pixels = new Uint8Array(4 * this.width * this.height); + this.renderer.readRenderTargetPixels(this.output, 0, 0, this.width, this.height, pixels); + + var imageData = new ImageData(new Uint8ClampedArray(pixels), this.width, this.height); + + var encoder = new JPEGEncoder(90); + var jpegURI = encoder.encode(imageData, 90, xmp_details); + var blob = this.dataURItoBlob(jpegURI); + + var url = URL.createObjectURL(blob); + var anchor = document.createElement("a"); + anchor.href = url; + anchor.setAttribute("download", suggested_filename); + anchor.className = "download-js-link"; + anchor.innerHTML = "downloading..."; + anchor.style.display = "none"; + document.body.appendChild(anchor); + setTimeout(function () { + anchor.click(); + document.body.removeChild(anchor); + }, 1); + + this.renderer.setRenderTarget(null); + }; + + CubemapToEquirectangular.prototype.update = function (camera, scene, suggested_filename, xmp_details) { + var autoClear = this.renderer.autoClear; + this.renderer.autoClear = true; + this.cubeCamera.position.copy(camera.position); + this.cubeCamera.update(this.renderer, scene); + this.renderer.autoClear = autoClear; + + this.convert(this.cubeCamera, suggested_filename, xmp_details); + }; + + if (typeof exports !== "undefined") { + if (typeof module !== "undefined" && module.exports) { + exports = module.exports = CubemapToEquirectangular; + } + exports.CubemapToEquirectangular = CubemapToEquirectangular; + } else { + root.CubemapToEquirectangular = CubemapToEquirectangular; + } +}.call(this)); diff --git a/indra/externals/js/JPEG_ENCODER_BASIC_LICENSE.txt b/indra/externals/js/JPEG_ENCODER_BASIC_LICENSE.txt new file mode 100644 index 00000000000..68cdc620d36 --- /dev/null +++ b/indra/externals/js/JPEG_ENCODER_BASIC_LICENSE.txt @@ -0,0 +1,39 @@ +/* + + Basic GUI blocking jpeg encoder ported to JavaScript and optimized by + Andreas Ritter, www.bytestrom.eu, 11/2009. + + Example usage is given at the bottom of this file. + + --------- + + Copyright (c) 2008, Adobe Systems Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Adobe Systems Incorporated nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/indra/externals/js/OrbitControls.js b/indra/externals/js/OrbitControls.js new file mode 100644 index 00000000000..64de448d075 --- /dev/null +++ b/indra/externals/js/OrbitControls.js @@ -0,0 +1,1110 @@ +( function () { + + // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). + // + // Orbit - left mouse / touch: one-finger move + // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish + // Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move + + const _changeEvent = { + type: 'change' + }; + const _startEvent = { + type: 'start' + }; + const _endEvent = { + type: 'end' + }; + + class OrbitControls extends THREE.EventDispatcher { + + constructor( object, domElement ) { + + super(); + if ( domElement === undefined ) console.warn( 'THREE.OrbitControls: The second parameter "domElement" is now mandatory.' ); + if ( domElement === document ) console.error( 'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' ); + this.object = object; + this.domElement = domElement; + this.domElement.style.touchAction = 'none'; // disable touch scroll + // Set to false to disable this control + + this.enabled = true; // "target" sets the location of focus, where the object orbits around + + this.target = new THREE.Vector3(); // How far you can dolly in and out ( PerspectiveCamera only ) + + this.minDistance = 0; + this.maxDistance = Infinity; // How far you can zoom in and out ( OrthographicCamera only ) + + this.minZoom = 0; + this.maxZoom = Infinity; // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + + this.minPolarAngle = 0; // radians + + this.maxPolarAngle = Math.PI; // radians + // How far you can orbit horizontally, upper and lower limits. + // If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI ) + + this.minAzimuthAngle = - Infinity; // radians + + this.maxAzimuthAngle = Infinity; // radians + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + + this.enableDamping = false; + this.dampingFactor = 0.05; // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. + // Set to false to disable zooming + + this.enableZoom = true; + this.zoomSpeed = 1.0; // Set to false to disable rotating + + this.enableRotate = true; + this.rotateSpeed = 1.0; // Set to false to disable panning + + this.enablePan = true; + this.panSpeed = 1.0; + this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up + + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60 + // The four arrow keys + + this.keys = { + LEFT: 'ArrowLeft', + UP: 'ArrowUp', + RIGHT: 'ArrowRight', + BOTTOM: 'ArrowDown' + }; // Mouse buttons + + this.mouseButtons = { + LEFT: THREE.MOUSE.ROTATE, + MIDDLE: THREE.MOUSE.DOLLY, + RIGHT: THREE.MOUSE.PAN + }; // Touch fingers + + this.touches = { + ONE: THREE.TOUCH.ROTATE, + TWO: THREE.TOUCH.DOLLY_PAN + }; // for reset + + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; // the target DOM element for key events + + this._domElementKeyEvents = null; // + // public methods + // + + this.getPolarAngle = function () { + + return spherical.phi; + + }; + + this.getAzimuthalAngle = function () { + + return spherical.theta; + + }; + + this.getDistance = function () { + + return this.object.position.distanceTo( this.target ); + + }; + + this.listenToKeyEvents = function ( domElement ) { + + domElement.addEventListener( 'keydown', onKeyDown ); + this._domElementKeyEvents = domElement; + + }; + + this.saveState = function () { + + scope.target0.copy( scope.target ); + scope.position0.copy( scope.object.position ); + scope.zoom0 = scope.object.zoom; + + }; + + this.reset = function () { + + scope.target.copy( scope.target0 ); + scope.object.position.copy( scope.position0 ); + scope.object.zoom = scope.zoom0; + scope.object.updateProjectionMatrix(); + scope.dispatchEvent( _changeEvent ); + scope.update(); + state = STATE.NONE; + + }; // this method is exposed, but perhaps it would be better if we can make it private... + + + this.update = function () { + + const offset = new THREE.Vector3(); // so camera.up is the orbit axis + + const quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) ); + const quatInverse = quat.clone().invert(); + const lastPosition = new THREE.Vector3(); + const lastQuaternion = new THREE.Quaternion(); + const twoPI = 2 * Math.PI; + return function update() { + + const position = scope.object.position; + offset.copy( position ).sub( scope.target ); // rotate offset to "y-axis-is-up" space + + offset.applyQuaternion( quat ); // angle from z-axis around y-axis + + spherical.setFromVector3( offset ); + + if ( scope.autoRotate && state === STATE.NONE ) { + + rotateLeft( getAutoRotationAngle() ); + + } + + if ( scope.enableDamping ) { + + spherical.theta += sphericalDelta.theta * scope.dampingFactor; + spherical.phi += sphericalDelta.phi * scope.dampingFactor; + + } else { + + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + + } // restrict theta to be between desired limits + + + let min = scope.minAzimuthAngle; + let max = scope.maxAzimuthAngle; + + if ( isFinite( min ) && isFinite( max ) ) { + + if ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI; + if ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI; + + if ( min <= max ) { + + spherical.theta = Math.max( min, Math.min( max, spherical.theta ) ); + + } else { + + spherical.theta = spherical.theta > ( min + max ) / 2 ? Math.max( min, spherical.theta ) : Math.min( max, spherical.theta ); + + } + + } // restrict phi to be between desired limits + + + spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) ); + spherical.makeSafe(); + spherical.radius *= scale; // restrict radius to be between desired limits + + spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); // move target to panned location + + if ( scope.enableDamping === true ) { + + scope.target.addScaledVector( panOffset, scope.dampingFactor ); + + } else { + + scope.target.add( panOffset ); + + } + + offset.setFromSpherical( spherical ); // rotate offset back to "camera-up-vector-is-up" space + + offset.applyQuaternion( quatInverse ); + position.copy( scope.target ).add( offset ); + scope.object.lookAt( scope.target ); + + if ( scope.enableDamping === true ) { + + sphericalDelta.theta *= 1 - scope.dampingFactor; + sphericalDelta.phi *= 1 - scope.dampingFactor; + panOffset.multiplyScalar( 1 - scope.dampingFactor ); + + } else { + + sphericalDelta.set( 0, 0, 0 ); + panOffset.set( 0, 0, 0 ); + + } + + scale = 1; // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if ( zoomChanged || lastPosition.distanceToSquared( scope.object.position ) > EPS || 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { + + scope.dispatchEvent( _changeEvent ); + lastPosition.copy( scope.object.position ); + lastQuaternion.copy( scope.object.quaternion ); + zoomChanged = false; + return true; + + } + + return false; + + }; + + }(); + + this.dispose = function () { + + scope.domElement.removeEventListener( 'contextmenu', onContextMenu ); + scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); + scope.domElement.removeEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.removeEventListener( 'wheel', onMouseWheel ); + scope.domElement.removeEventListener( 'pointermove', onPointerMove ); + scope.domElement.removeEventListener( 'pointerup', onPointerUp ); + + if ( scope._domElementKeyEvents !== null ) { + + scope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + + } //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? + + }; // + // internals + // + + + const scope = this; + const STATE = { + NONE: - 1, + ROTATE: 0, + DOLLY: 1, + PAN: 2, + TOUCH_ROTATE: 3, + TOUCH_PAN: 4, + TOUCH_DOLLY_PAN: 5, + TOUCH_DOLLY_ROTATE: 6 + }; + let state = STATE.NONE; + const EPS = 0.000001; // current position in spherical coordinates + + const spherical = new THREE.Spherical(); + const sphericalDelta = new THREE.Spherical(); + let scale = 1; + const panOffset = new THREE.Vector3(); + let zoomChanged = false; + const rotateStart = new THREE.Vector2(); + const rotateEnd = new THREE.Vector2(); + const rotateDelta = new THREE.Vector2(); + const panStart = new THREE.Vector2(); + const panEnd = new THREE.Vector2(); + const panDelta = new THREE.Vector2(); + const dollyStart = new THREE.Vector2(); + const dollyEnd = new THREE.Vector2(); + const dollyDelta = new THREE.Vector2(); + const pointers = []; + const pointerPositions = {}; + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow( 0.95, scope.zoomSpeed ); + + } + + function rotateLeft( angle ) { + + sphericalDelta.theta -= angle; + + } + + function rotateUp( angle ) { + + sphericalDelta.phi -= angle; + + } + + const panLeft = function () { + + const v = new THREE.Vector3(); + return function panLeft( distance, objectMatrix ) { + + v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix + + v.multiplyScalar( - distance ); + panOffset.add( v ); + + }; + + }(); + + const panUp = function () { + + const v = new THREE.Vector3(); + return function panUp( distance, objectMatrix ) { + + if ( scope.screenSpacePanning === true ) { + + v.setFromMatrixColumn( objectMatrix, 1 ); + + } else { + + v.setFromMatrixColumn( objectMatrix, 0 ); + v.crossVectors( scope.object.up, v ); + + } + + v.multiplyScalar( distance ); + panOffset.add( v ); + + }; + + }(); // deltaX and deltaY are in pixels; right and down are positive + + + const pan = function () { + + const offset = new THREE.Vector3(); + return function pan( deltaX, deltaY ) { + + const element = scope.domElement; + + if ( scope.object.isPerspectiveCamera ) { + + // perspective + const position = scope.object.position; + offset.copy( position ).sub( scope.target ); + let targetDistance = offset.length(); // half of the fov is center to top of screen + + targetDistance *= Math.tan( scope.object.fov / 2 * Math.PI / 180.0 ); // we use only clientHeight here so aspect ratio does not distort speed + + panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix ); + panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix ); + + } else if ( scope.object.isOrthographicCamera ) { + + // orthographic + panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix ); + panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix ); + + } else { + + // camera neither orthographic nor perspective + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' ); + scope.enablePan = false; + + } + + }; + + }(); + + function dollyOut( dollyScale ) { + + if ( scope.object.isPerspectiveCamera ) { + + scale /= dollyScale; + + } else if ( scope.object.isOrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; + + } + + } + + function dollyIn( dollyScale ) { + + if ( scope.object.isPerspectiveCamera ) { + + scale *= dollyScale; + + } else if ( scope.object.isOrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); + scope.enableZoom = false; + + } + + } // + // event callbacks - update the object state + // + + + function handleMouseDownRotate( event ) { + + rotateStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownDolly( event ) { + + dollyStart.set( event.clientX, event.clientY ); + + } + + function handleMouseDownPan( event ) { + + panStart.set( event.clientX, event.clientY ); + + } + + function handleMouseMoveRotate( event ) { + + rotateEnd.set( event.clientX, event.clientY ); + rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed ); + const element = scope.domElement; + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height + + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); + rotateStart.copy( rotateEnd ); + scope.update(); + + } + + function handleMouseMoveDolly( event ) { + + dollyEnd.set( event.clientX, event.clientY ); + dollyDelta.subVectors( dollyEnd, dollyStart ); + + if ( dollyDelta.y > 0 ) { + + dollyOut( getZoomScale() ); + + } else if ( dollyDelta.y < 0 ) { + + dollyIn( getZoomScale() ); + + } + + dollyStart.copy( dollyEnd ); + scope.update(); + + } + + function handleMouseMovePan( event ) { + + panEnd.set( event.clientX, event.clientY ); + panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); + pan( panDelta.x, panDelta.y ); + panStart.copy( panEnd ); + scope.update(); + + } + + function handleMouseUp() { // no-op + } + + function handleMouseWheel( event ) { + + if ( event.deltaY < 0 ) { + + dollyIn( getZoomScale() ); + + } else if ( event.deltaY > 0 ) { + + dollyOut( getZoomScale() ); + + } + + scope.update(); + + } + + function handleKeyDown( event ) { + + let needsUpdate = false; + + switch ( event.code ) { + + case scope.keys.UP: + pan( 0, scope.keyPanSpeed ); + needsUpdate = true; + break; + + case scope.keys.BOTTOM: + pan( 0, - scope.keyPanSpeed ); + needsUpdate = true; + break; + + case scope.keys.LEFT: + pan( scope.keyPanSpeed, 0 ); + needsUpdate = true; + break; + + case scope.keys.RIGHT: + pan( - scope.keyPanSpeed, 0 ); + needsUpdate = true; + break; + + } + + if ( needsUpdate ) { + + // prevent the browser from scrolling on cursor keys + event.preventDefault(); + scope.update(); + + } + + } + + function handleTouchStartRotate() { + + if ( pointers.length === 1 ) { + + rotateStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + + } else { + + const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); + const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + rotateStart.set( x, y ); + + } + + } + + function handleTouchStartPan() { + + if ( pointers.length === 1 ) { + + panStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + + } else { + + const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); + const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + panStart.set( x, y ); + + } + + } + + function handleTouchStartDolly() { + + const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX; + const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY; + const distance = Math.sqrt( dx * dx + dy * dy ); + dollyStart.set( 0, distance ); + + } + + function handleTouchStartDollyPan() { + + if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enablePan ) handleTouchStartPan(); + + } + + function handleTouchStartDollyRotate() { + + if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enableRotate ) handleTouchStartRotate(); + + } + + function handleTouchMoveRotate( event ) { + + if ( pointers.length == 1 ) { + + rotateEnd.set( event.pageX, event.pageY ); + + } else { + + const position = getSecondPointerPosition( event ); + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); + rotateEnd.set( x, y ); + + } + + rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed ); + const element = scope.domElement; + rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height + + rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight ); + rotateStart.copy( rotateEnd ); + + } + + function handleTouchMovePan( event ) { + + if ( pointers.length === 1 ) { + + panEnd.set( event.pageX, event.pageY ); + + } else { + + const position = getSecondPointerPosition( event ); + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); + panEnd.set( x, y ); + + } + + panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed ); + pan( panDelta.x, panDelta.y ); + panStart.copy( panEnd ); + + } + + function handleTouchMoveDolly( event ) { + + const position = getSecondPointerPosition( event ); + const dx = event.pageX - position.x; + const dy = event.pageY - position.y; + const distance = Math.sqrt( dx * dx + dy * dy ); + dollyEnd.set( 0, distance ); + dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) ); + dollyOut( dollyDelta.y ); + dollyStart.copy( dollyEnd ); + + } + + function handleTouchMoveDollyPan( event ) { + + if ( scope.enableZoom ) handleTouchMoveDolly( event ); + if ( scope.enablePan ) handleTouchMovePan( event ); + + } + + function handleTouchMoveDollyRotate( event ) { + + if ( scope.enableZoom ) handleTouchMoveDolly( event ); + if ( scope.enableRotate ) handleTouchMoveRotate( event ); + + } + + function handleTouchEnd() { // no-op + } // + // event handlers - FSM: listen for events and reset state + // + + + function onPointerDown( event ) { + + if ( scope.enabled === false ) return; + + if ( pointers.length === 0 ) { + + scope.domElement.setPointerCapture( event.pointerId ); + scope.domElement.addEventListener( 'pointermove', onPointerMove ); + scope.domElement.addEventListener( 'pointerup', onPointerUp ); + + } // + + + addPointer( event ); + + if ( event.pointerType === 'touch' ) { + + onTouchStart( event ); + + } else { + + onMouseDown( event ); + + } + + } + + function onPointerMove( event ) { + + if ( scope.enabled === false ) return; + + if ( event.pointerType === 'touch' ) { + + onTouchMove( event ); + + } else { + + onMouseMove( event ); + + } + + } + + function onPointerUp( event ) { + + if ( scope.enabled === false ) return; + + if ( event.pointerType === 'touch' ) { + + onTouchEnd(); + + } else { + + onMouseUp( event ); + + } + + removePointer( event ); // + + if ( pointers.length === 0 ) { + + scope.domElement.releasePointerCapture( event.pointerId ); + scope.domElement.removeEventListener( 'pointermove', onPointerMove ); + scope.domElement.removeEventListener( 'pointerup', onPointerUp ); + + } + + } + + function onPointerCancel( event ) { + + removePointer( event ); + + } + + function onMouseDown( event ) { + + let mouseAction; + + switch ( event.button ) { + + case 0: + mouseAction = scope.mouseButtons.LEFT; + break; + + case 1: + mouseAction = scope.mouseButtons.MIDDLE; + break; + + case 2: + mouseAction = scope.mouseButtons.RIGHT; + break; + + default: + mouseAction = - 1; + + } + + switch ( mouseAction ) { + + case THREE.MOUSE.DOLLY: + if ( scope.enableZoom === false ) return; + handleMouseDownDolly( event ); + state = STATE.DOLLY; + break; + + case THREE.MOUSE.ROTATE: + if ( event.ctrlKey || event.metaKey || event.shiftKey ) { + + if ( scope.enablePan === false ) return; + handleMouseDownPan( event ); + state = STATE.PAN; + + } else { + + if ( scope.enableRotate === false ) return; + handleMouseDownRotate( event ); + state = STATE.ROTATE; + + } + + break; + + case THREE.MOUSE.PAN: + if ( event.ctrlKey || event.metaKey || event.shiftKey ) { + + if ( scope.enableRotate === false ) return; + handleMouseDownRotate( event ); + state = STATE.ROTATE; + + } else { + + if ( scope.enablePan === false ) return; + handleMouseDownPan( event ); + state = STATE.PAN; + + } + + break; + + default: + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) { + + scope.dispatchEvent( _startEvent ); + + } + + } + + function onMouseMove( event ) { + + if ( scope.enabled === false ) return; + + switch ( state ) { + + case STATE.ROTATE: + if ( scope.enableRotate === false ) return; + handleMouseMoveRotate( event ); + break; + + case STATE.DOLLY: + if ( scope.enableZoom === false ) return; + handleMouseMoveDolly( event ); + break; + + case STATE.PAN: + if ( scope.enablePan === false ) return; + handleMouseMovePan( event ); + break; + + } + + } + + function onMouseUp( event ) { + + handleMouseUp( event ); + scope.dispatchEvent( _endEvent ); + state = STATE.NONE; + + } + + function onMouseWheel( event ) { + + if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE && state !== STATE.ROTATE ) return; + event.preventDefault(); + scope.dispatchEvent( _startEvent ); + handleMouseWheel( event ); + scope.dispatchEvent( _endEvent ); + + } + + function onKeyDown( event ) { + + if ( scope.enabled === false || scope.enablePan === false ) return; + handleKeyDown( event ); + + } + + function onTouchStart( event ) { + + trackPointer( event ); + + switch ( pointers.length ) { + + case 1: + switch ( scope.touches.ONE ) { + + case THREE.TOUCH.ROTATE: + if ( scope.enableRotate === false ) return; + handleTouchStartRotate(); + state = STATE.TOUCH_ROTATE; + break; + + case THREE.TOUCH.PAN: + if ( scope.enablePan === false ) return; + handleTouchStartPan(); + state = STATE.TOUCH_PAN; + break; + + default: + state = STATE.NONE; + + } + + break; + + case 2: + switch ( scope.touches.TWO ) { + + case THREE.TOUCH.DOLLY_PAN: + if ( scope.enableZoom === false && scope.enablePan === false ) return; + handleTouchStartDollyPan(); + state = STATE.TOUCH_DOLLY_PAN; + break; + + case THREE.TOUCH.DOLLY_ROTATE: + if ( scope.enableZoom === false && scope.enableRotate === false ) return; + handleTouchStartDollyRotate(); + state = STATE.TOUCH_DOLLY_ROTATE; + break; + + default: + state = STATE.NONE; + + } + + break; + + default: + state = STATE.NONE; + + } + + if ( state !== STATE.NONE ) { + + scope.dispatchEvent( _startEvent ); + + } + + } + + function onTouchMove( event ) { + + trackPointer( event ); + + switch ( state ) { + + case STATE.TOUCH_ROTATE: + if ( scope.enableRotate === false ) return; + handleTouchMoveRotate( event ); + scope.update(); + break; + + case STATE.TOUCH_PAN: + if ( scope.enablePan === false ) return; + handleTouchMovePan( event ); + scope.update(); + break; + + case STATE.TOUCH_DOLLY_PAN: + if ( scope.enableZoom === false && scope.enablePan === false ) return; + handleTouchMoveDollyPan( event ); + scope.update(); + break; + + case STATE.TOUCH_DOLLY_ROTATE: + if ( scope.enableZoom === false && scope.enableRotate === false ) return; + handleTouchMoveDollyRotate( event ); + scope.update(); + break; + + default: + state = STATE.NONE; + + } + + } + + function onTouchEnd( event ) { + + handleTouchEnd( event ); + scope.dispatchEvent( _endEvent ); + state = STATE.NONE; + + } + + function onContextMenu( event ) { + + if ( scope.enabled === false ) return; + event.preventDefault(); + + } + + function addPointer( event ) { + + pointers.push( event ); + + } + + function removePointer( event ) { + + delete pointerPositions[ event.pointerId ]; + + for ( let i = 0; i < pointers.length; i ++ ) { + + if ( pointers[ i ].pointerId == event.pointerId ) { + + pointers.splice( i, 1 ); + return; + + } + + } + + } + + function trackPointer( event ) { + + let position = pointerPositions[ event.pointerId ]; + + if ( position === undefined ) { + + position = new THREE.Vector2(); + pointerPositions[ event.pointerId ] = position; + + } + + position.set( event.pageX, event.pageY ); + + } + + function getSecondPointerPosition( event ) { + + const pointer = event.pointerId === pointers[ 0 ].pointerId ? pointers[ 1 ] : pointers[ 0 ]; + return pointerPositions[ pointer.pointerId ]; + + } // + + + scope.domElement.addEventListener( 'contextmenu', onContextMenu ); + scope.domElement.addEventListener( 'pointerdown', onPointerDown ); + scope.domElement.addEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.addEventListener( 'wheel', onMouseWheel, { + passive: false + } ); // force an update at start + + this.update(); + + } + + } // This set of controls performs orbiting, dollying (zooming), and panning. + // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). + // This is very similar to OrbitControls, another set of touch behavior + // + // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate + // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish + // Pan - left mouse, or arrow keys / touch: one-finger move + + + class MapControls extends OrbitControls { + + constructor( object, domElement ) { + + super( object, domElement ); + this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up + + this.mouseButtons.LEFT = THREE.MOUSE.PAN; + this.mouseButtons.RIGHT = THREE.MOUSE.ROTATE; + this.touches.ONE = THREE.TOUCH.PAN; + this.touches.TWO = THREE.TOUCH.DOLLY_ROTATE; + + } + + } + + THREE.MapControls = MapControls; + THREE.OrbitControls = OrbitControls; + +} )(); diff --git a/indra/externals/js/THREEJS_LICENSE.txt b/indra/externals/js/THREEJS_LICENSE.txt new file mode 100644 index 00000000000..5303437e406 --- /dev/null +++ b/indra/externals/js/THREEJS_LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright © 2010-2021 three.js authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/indra/externals/js/jpeg_encoder_basic.js b/indra/externals/js/jpeg_encoder_basic.js new file mode 100644 index 00000000000..bb9c52daca2 --- /dev/null +++ b/indra/externals/js/jpeg_encoder_basic.js @@ -0,0 +1,841 @@ +/* + + Basic GUI blocking jpeg encoder ported to JavaScript and optimized by + Andreas Ritter, www.bytestrom.eu, 11/2009. + + Example usage is given at the bottom of this file. + + --------- + + Copyright (c) 2008, Adobe Systems Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Adobe Systems Incorporated nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + Modified by Callum Prentice (callum@lindenlab.com) 2021-07-28 to + write XMP metadata using list of parameters passed to it +*/ + +function JPEGEncoder(quality) { + var self = this; + var fround = Math.round; + var ffloor = Math.floor; + var YTable = new Array(64); + var UVTable = new Array(64); + var fdtbl_Y = new Array(64); + var fdtbl_UV = new Array(64); + var YDC_HT; + var UVDC_HT; + var YAC_HT; + var UVAC_HT; + + var bitcode = new Array(65535); + var category = new Array(65535); + var outputfDCTQuant = new Array(64); + var DU = new Array(64); + var byteout = []; + var bytenew = 0; + var bytepos = 7; + + var YDU = new Array(64); + var UDU = new Array(64); + var VDU = new Array(64); + var clt = new Array(256); + var RGB_YUV_TABLE = new Array(2048); + var currentQuality; + + var ZigZag = [ + 0, 1, 5, 6,14,15,27,28, + 2, 4, 7,13,16,26,29,42, + 3, 8,12,17,25,30,41,43, + 9,11,18,24,31,40,44,53, + 10,19,23,32,39,45,52,54, + 20,22,33,38,46,51,55,60, + 21,34,37,47,50,56,59,61, + 35,36,48,49,57,58,62,63 + ]; + + var std_dc_luminance_nrcodes = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0]; + var std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11]; + var std_ac_luminance_nrcodes = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d]; + var std_ac_luminance_values = [ + 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12, + 0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07, + 0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, + 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, + 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16, + 0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39, + 0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, + 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, + 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69, + 0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79, + 0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, + 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98, + 0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7, + 0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, + 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, + 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4, + 0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, + 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea, + 0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, + 0xf9,0xfa + ]; + + var std_dc_chrominance_nrcodes = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0]; + var std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11]; + var std_ac_chrominance_nrcodes = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77]; + var std_ac_chrominance_values = [ + 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21, + 0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, + 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, + 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0, + 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34, + 0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, + 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38, + 0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48, + 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, + 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68, + 0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78, + 0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, + 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96, + 0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5, + 0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, + 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3, + 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2, + 0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, + 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9, + 0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, + 0xf9,0xfa + ]; + + function initQuantTables(sf){ + var YQT = [ + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68,109,103, 77, + 24, 35, 55, 64, 81,104,113, 92, + 49, 64, 78, 87,103,121,120,101, + 72, 92, 95, 98,112,100,103, 99 + ]; + + for (var i = 0; i < 64; i++) { + var t = ffloor((YQT[i]*sf+50)/100); + if (t < 1) { + t = 1; + } else if (t > 255) { + t = 255; + } + YTable[ZigZag[i]] = t; + } + var UVQT = [ + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + ]; + for (var j = 0; j < 64; j++) { + var u = ffloor((UVQT[j]*sf+50)/100); + if (u < 1) { + u = 1; + } else if (u > 255) { + u = 255; + } + UVTable[ZigZag[j]] = u; + } + var aasf = [ + 1.0, 1.387039845, 1.306562965, 1.175875602, + 1.0, 0.785694958, 0.541196100, 0.275899379 + ]; + var k = 0; + for (var row = 0; row < 8; row++) + { + for (var col = 0; col < 8; col++) + { + fdtbl_Y[k] = (1.0 / (YTable [ZigZag[k]] * aasf[row] * aasf[col] * 8.0)); + fdtbl_UV[k] = (1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0)); + k++; + } + } + } + + function computeHuffmanTbl(nrcodes, std_table){ + var codevalue = 0; + var pos_in_table = 0; + var HT = new Array(); + for (var k = 1; k <= 16; k++) { + for (var j = 1; j <= nrcodes[k]; j++) { + HT[std_table[pos_in_table]] = []; + HT[std_table[pos_in_table]][0] = codevalue; + HT[std_table[pos_in_table]][1] = k; + pos_in_table++; + codevalue++; + } + codevalue*=2; + } + return HT; + } + + function initHuffmanTbl() + { + YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values); + UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values); + YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values); + UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values); + } + + function initCategoryNumber() + { + var nrlower = 1; + var nrupper = 2; + for (var cat = 1; cat <= 15; cat++) { + //Positive numbers + for (var nr = nrlower; nr>0] = 38470 * i; + RGB_YUV_TABLE[(i+ 512)>>0] = 7471 * i + 0x8000; + RGB_YUV_TABLE[(i+ 768)>>0] = -11059 * i; + RGB_YUV_TABLE[(i+1024)>>0] = -21709 * i; + RGB_YUV_TABLE[(i+1280)>>0] = 32768 * i + 0x807FFF; + RGB_YUV_TABLE[(i+1536)>>0] = -27439 * i; + RGB_YUV_TABLE[(i+1792)>>0] = - 5329 * i; + } + } + + // IO functions + function writeBits(bs) + { + var value = bs[0]; + var posval = bs[1]-1; + while ( posval >= 0 ) { + if (value & (1 << posval) ) { + bytenew |= (1 << bytepos); + } + posval--; + bytepos--; + if (bytepos < 0) { + if (bytenew == 0xFF) { + writeByte(0xFF); + writeByte(0); + } + else { + writeByte(bytenew); + } + bytepos=7; + bytenew=0; + } + } + } + + function writeByte(value) + { + byteout.push(clt[value]); // write char directly instead of converting later + } + + function writeWord(value) + { + writeByte((value>>8)&0xFF); + writeByte((value )&0xFF); + } + + // DCT & quantization core + function fDCTQuant(data, fdtbl) + { + var d0, d1, d2, d3, d4, d5, d6, d7; + /* Pass 1: process rows. */ + var dataOff=0; + var i; + const I8 = 8; + const I64 = 64; + for (i=0; i 0.0) ? ((fDCTQuant + 0.5)|0) : ((fDCTQuant - 0.5)|0); + //outputfDCTQuant[i] = fround(fDCTQuant); + + } + return outputfDCTQuant; + } + + function writeAPP0() + { + writeWord(0xFFE0); // marker + writeWord(16); // length + writeByte(0x4A); // J + writeByte(0x46); // F + writeByte(0x49); // I + writeByte(0x46); // F + writeByte(0); // = "JFIF",'\0' + writeByte(1); // versionhi + writeByte(1); // versionlo + writeByte(0); // xyunits + writeWord(1); // xdensity + writeWord(1); // ydensity + writeByte(0); // thumbnwidth + writeByte(0); // thumbnheight + } + + function writeSOF0(width, height) + { + writeWord(0xFFC0); // marker + writeWord(17); // length, truecolor YUV JPG + writeByte(8); // precision + writeWord(height); + writeWord(width); + writeByte(3); // nrofcomponents + writeByte(1); // IdY + writeByte(0x11); // HVY + writeByte(0); // QTY + writeByte(2); // IdU + writeByte(0x11); // HVU + writeByte(1); // QTU + writeByte(3); // IdV + writeByte(0x11); // HVV + writeByte(1); // QTV + } + + function writeDQT() + { + writeWord(0xFFDB); // marker + writeWord(132); // length + writeByte(0); + for (var i=0; i<64; i++) { + writeByte(YTable[i]); + } + writeByte(1); + for (var j=0; j<64; j++) { + writeByte(UVTable[j]); + } + } + + function writeDHT() + { + writeWord(0xFFC4); // marker + writeWord(0x01A2); // length + + writeByte(0); // HTYDCinfo + for (var i=0; i<16; i++) { + writeByte(std_dc_luminance_nrcodes[i+1]); + } + for (var j=0; j<=11; j++) { + writeByte(std_dc_luminance_values[j]); + } + + writeByte(0x10); // HTYACinfo + for (var k=0; k<16; k++) { + writeByte(std_ac_luminance_nrcodes[k+1]); + } + for (var l=0; l<=161; l++) { + writeByte(std_ac_luminance_values[l]); + } + + writeByte(1); // HTUDCinfo + for (var m=0; m<16; m++) { + writeByte(std_dc_chrominance_nrcodes[m+1]); + } + for (var n=0; n<=11; n++) { + writeByte(std_dc_chrominance_values[n]); + } + + writeByte(0x11); // HTUACinfo + for (var o=0; o<16; o++) { + writeByte(std_ac_chrominance_nrcodes[o+1]); + } + for (var p=0; p<=161; p++) { + writeByte(std_ac_chrominance_values[p]); + } + } + + function writeSOS() + { + writeWord(0xFFDA); // marker + writeWord(12); // length + writeByte(3); // nrofcomponents + writeByte(1); // IdY + writeByte(0); // HTY + writeByte(2); // IdU + writeByte(0x11); // HTU + writeByte(3); // IdV + writeByte(0x11); // HTV + writeByte(0); // Ss + writeByte(0x3f); // Se + writeByte(0); // Bf + } + + function processDU(CDU, fdtbl, DC, HTDC, HTAC){ + var EOB = HTAC[0x00]; + var M16zeroes = HTAC[0xF0]; + var pos; + const I16 = 16; + const I63 = 63; + const I64 = 64; + var DU_DCT = fDCTQuant(CDU, fdtbl); + //ZigZag reorder + for (var j=0;j0)&&(DU[end0pos]==0); end0pos--) {}; + //end0pos = first element in reverse order !=0 + if ( end0pos == 0) { + writeBits(EOB); + return DC; + } + var i = 1; + var lng; + while ( i <= end0pos ) { + var startpos = i; + for (; (DU[i]==0) && (i<=end0pos); ++i) {} + var nrzeroes = i-startpos; + if ( nrzeroes >= I16 ) { + lng = nrzeroes>>4; + for (var nrmarker=1; nrmarker <= lng; ++nrmarker) + writeBits(M16zeroes); + nrzeroes = nrzeroes&0xF; + } + pos = 32767+DU[i]; + writeBits(HTAC[(nrzeroes<<4)+category[pos]]); + writeBits(bitcode[pos]); + i++; + } + if ( end0pos != I63 ) { + writeBits(EOB); + } + return DC; + } + + function initCharLookupTable(){ + var sfcc = String.fromCharCode; + for(var i=0; i < 256; i++){ ///// ACHTUNG // 255 + clt[i] = sfcc(i); + } + } + + this.encode = function(image, quality, xmp_details) // image data object + { + var toRaw = false; + + var time_start = new Date().getTime(); + + if(quality) setQuality(quality); + + // Initialize bit writer + byteout = new Array(); + bytenew=0; + bytepos=7; + + // Add JPEG headers + writeWord(0xFFD8); // SOI + writeAPP0(); + + // add XMP marker + writeWord(0xFFE1); + + // XMP identifier + var xap = "http://ns.adobe.com/xap/1.0/\0"; + + var xmp = ` + + + + + equirectangular + True + ${xmp_details.width} + ${xmp_details.height} + ${xmp_details.software} + ${xmp_details.software} + ${xmp_details.heading} + ${xmp_details.first_photo_date} + ${xmp_details.last_photo_date} + ${xmp_details.capture_software} + ${xmp_details.stitching_software} + ${xmp_details.pano_version} + ${xmp_details.actual_source_image_size} + ${xmp_details.scaled_source_image_size} + ${xmp_details.region_name} + ${xmp_details.region_url} + + + + + ` + + var headerLength = xap.length + xmp.length + 3; + writeWord(headerLength); + for (var i=0; i> 3;// /8 + col = ( pos & 7 ) * 4; // %8 + p = start + ( row * quadWidth ) + col; + + if(y+row >= height){ // padding bottom + p-= (quadWidth*(y+1+row-height)); + } + + if(x+col >= quadWidth){ // padding right + p-= ((x+col) - quadWidth +4) + } + + r = imageData[ p++ ]; + g = imageData[ p++ ]; + b = imageData[ p++ ]; + + /* // calculate YUV values dynamically + YDU[pos]=((( 0.29900)*r+( 0.58700)*g+( 0.11400)*b))-128; //-0x80 + UDU[pos]=(((-0.16874)*r+(-0.33126)*g+( 0.50000)*b)); + VDU[pos]=((( 0.50000)*r+(-0.41869)*g+(-0.08131)*b)); + */ + + // use lookup table (slightly faster) + YDU[pos] = ((RGB_YUV_TABLE[r] + RGB_YUV_TABLE[(g + 256)>>0] + RGB_YUV_TABLE[(b + 512)>>0]) >> 16)-128; + UDU[pos] = ((RGB_YUV_TABLE[(r + 768)>>0] + RGB_YUV_TABLE[(g + 1024)>>0] + RGB_YUV_TABLE[(b + 1280)>>0]) >> 16)-128; + VDU[pos] = ((RGB_YUV_TABLE[(r + 1280)>>0] + RGB_YUV_TABLE[(g + 1536)>>0] + RGB_YUV_TABLE[(b + 1792)>>0]) >> 16)-128; + + } + + DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + x+=32; + } + y+=8; + } + + //////////////////////////////////////////////////////////////// + + // Do the bit alignment of the EOI marker + if ( bytepos >= 0 ) { + var fillbits = []; + fillbits[1] = bytepos+1; + fillbits[0] = (1<<(bytepos+1))-1; + writeBits(fillbits); + } + + writeWord(0xFFD9); //EOI + + if(toRaw) { + var len = byteout.length; + var data = new Uint8Array(len); + + for (var i=0; i 100) { + quality = 100; + } + + if(currentQuality == quality) return // don't recalc if unchanged + + var sf = 0; + if (quality < 50) { + sf = Math.floor(5000 / quality); + } else { + sf = Math.floor(200 - quality*2); + } + + initQuantTables(sf); + currentQuality = quality; + } + + function init(){ + var time_start = new Date().getTime(); + if(!quality) quality = 50; + // Create tables + initCharLookupTable() + initHuffmanTbl(); + initCategoryNumber(); + initRGBYUVTable(); + + setQuality(quality); + var duration = new Date().getTime() - time_start; + } + + init(); + +}; + +/* Example usage. Quality is an int in the range [0, 100] +function example(quality){ + // Pass in an existing image from the page + var theImg = document.getElementById('testimage'); + // Use a canvas to extract the raw image data + var cvs = document.createElement('canvas'); + cvs.width = theImg.width; + cvs.height = theImg.height; + var ctx = cvs.getContext("2d"); + ctx.drawImage(theImg,0,0); + var theImgData = (ctx.getImageData(0, 0, cvs.width, cvs.height)); + // Encode the image and get a URI back, toRaw is false by default + var jpegURI = encoder.encode(theImgData, quality); + var img = document.createElement('img'); + img.src = jpegURI; + document.body.appendChild(img); +} + +Example usage for getting back raw data and transforming it to a blob. +Raw data is useful when trying to send an image over XHR or Websocket, +it uses around 30% less bytes then a Base64 encoded string. It can +also be useful if you want to save the image to disk using a FileWriter. + +NOTE: The browser you are using must support Blobs +function example(quality){ + // Pass in an existing image from the page + var theImg = document.getElementById('testimage'); + // Use a canvas to extract the raw image data + var cvs = document.createElement('canvas'); + cvs.width = theImg.width; + cvs.height = theImg.height; + var ctx = cvs.getContext("2d"); + ctx.drawImage(theImg,0,0); + var theImgData = (ctx.getImageData(0, 0, cvs.width, cvs.height)); + // Encode the image and get a URI back, set toRaw to true + var rawData = encoder.encode(theImgData, quality, true); + + blob = new Blob([rawData.buffer], {type: 'image/jpeg'}); + var jpegURI = URL.createObjectURL(blob); + + var img = document.createElement('img'); + img.src = jpegURI; + document.body.appendChild(img); +}*/ \ No newline at end of file diff --git a/indra/externals/js/three.min.js b/indra/externals/js/three.min.js new file mode 100644 index 00000000000..97ab9e4f8cf --- /dev/null +++ b/indra/externals/js/three.min.js @@ -0,0 +1,6 @@ +/** + * @license + * Copyright 2010-2021 Three.js Authors + * SPDX-License-Identifier: MIT + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).THREE={})}(this,(function(t){"use strict";const e="133dev",n=100,i=300,r=301,s=302,a=303,o=304,l=306,c=307,h=1e3,u=1001,d=1002,p=1003,m=1004,f=1005,g=1006,v=1007,y=1008,x=1009,_=1012,b=1014,M=1015,w=1016,S=1020,T=1022,E=1023,A=1026,L=1027,R=33776,C=33777,P=33778,I=33779,D=35840,N=35841,z=35842,B=35843,F=37492,O=37496,U=2300,H=2301,G=2302,k=2400,V=2401,W=2402,j=2500,q=2501,X=3e3,Y=3001,J=3007,Z=3002,Q=3004,K=3005,$=3006,tt=7680,et=35044,nt=35048,it="300 es";class rt{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e>8&255]+st[t>>16&255]+st[t>>24&255]+"-"+st[255&e]+st[e>>8&255]+"-"+st[e>>16&15|64]+st[e>>24&255]+"-"+st[63&n|128]+st[n>>8&255]+"-"+st[n>>16&255]+st[n>>24&255]+st[255&i]+st[i>>8&255]+st[i>>16&255]+st[i>>24&255]).toUpperCase()}function ht(t,e,n){return Math.max(e,Math.min(n,t))}function ut(t,e){return(t%e+e)%e}function dt(t,e,n){return(1-n)*t+n*e}function pt(t){return 0==(t&t-1)&&0!==t}function mt(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))}function ft(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))}var gt=Object.freeze({__proto__:null,DEG2RAD:ot,RAD2DEG:lt,generateUUID:ct,clamp:ht,euclideanModulo:ut,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverseLerp:function(t,e,n){return t!==e?(n-t)/(e-t):0},lerp:dt,damp:function(t,e,n,i){return dt(t,e,1-Math.exp(-n*i))},pingpong:function(t,e=1){return e-Math.abs(ut(t,2*e)-e)},smoothstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){return void 0!==t&&(at=t%2147483647),at=16807*at%2147483647,(at-1)/2147483646},degToRad:function(t){return t*ot},radToDeg:function(t){return t*lt},isPowerOfTwo:pt,ceilPowerOfTwo:mt,floorPowerOfTwo:ft,setQuaternionFromProperEuler:function(t,e,n,i,r){const s=Math.cos,a=Math.sin,o=s(n/2),l=a(n/2),c=s((e+i)/2),h=a((e+i)/2),u=s((e-i)/2),d=a((e-i)/2),p=s((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*h,l*u,l*d,o*c);break;case"YZY":t.set(l*d,o*h,l*u,o*c);break;case"ZXZ":t.set(l*u,l*d,o*h,o*c);break;case"XZX":t.set(o*h,l*m,l*p,o*c);break;case"YXY":t.set(l*p,o*h,l*m,o*c);break;case"ZYZ":t.set(l*m,l*p,o*h,o*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}}});class vt{constructor(t=0,e=0){this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t,e){return void 0!==e?(console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this)}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t,e){return void 0!==e?(console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this)}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e,n){return void 0!==n&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute()."),this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,s=this.y-t.y;return this.x=r*n-s*i+t.x,this.y=r*i+s*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}}vt.prototype.isVector2=!0;class yt{constructor(){this.elements=[1,0,0,0,1,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.")}set(t,e,n,i,r,s,a,o,l){const c=this.elements;return c[0]=t,c[1]=i,c[2]=a,c[3]=e,c[4]=r,c[5]=o,c[6]=n,c[7]=s,c[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[3],o=n[6],l=n[1],c=n[4],h=n[7],u=n[2],d=n[5],p=n[8],m=i[0],f=i[3],g=i[6],v=i[1],y=i[4],x=i[7],_=i[2],b=i[5],M=i[8];return r[0]=s*m+a*v+o*_,r[3]=s*f+a*y+o*b,r[6]=s*g+a*x+o*M,r[1]=l*m+c*v+h*_,r[4]=l*f+c*y+h*b,r[7]=l*g+c*x+h*M,r[2]=u*m+d*v+p*_,r[5]=u*f+d*y+p*b,r[8]=u*g+d*x+p*M,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8];return e*s*c-e*a*l-n*r*c+n*a*o+i*r*l-i*s*o}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=c*s-a*l,u=a*o-c*r,d=l*r-s*o,p=e*h+n*u+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return t[0]=h*m,t[1]=(i*l-c*n)*m,t[2]=(a*n-i*s)*m,t[3]=u*m,t[4]=(c*e-i*o)*m,t[5]=(i*r-a*e)*m,t[6]=d*m,t[7]=(n*o-l*e)*m,t[8]=(s*e-n*r)*m,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,n,i,r,s,a){const o=Math.cos(r),l=Math.sin(r);return this.set(n*o,n*l,-n*(o*s+l*a)+s+t,-i*l,i*o,-i*(-l*s+o*a)+a+e,0,0,1),this}scale(t,e){const n=this.elements;return n[0]*=t,n[3]*=t,n[6]*=t,n[1]*=e,n[4]*=e,n[7]*=e,this}rotate(t){const e=Math.cos(t),n=Math.sin(t),i=this.elements,r=i[0],s=i[3],a=i[6],o=i[1],l=i[4],c=i[7];return i[0]=e*r+n*o,i[3]=e*s+n*l,i[6]=e*a+n*c,i[1]=-n*r+e*o,i[4]=-n*s+e*l,i[7]=-n*a+e*c,this}translate(t,e){const n=this.elements;return n[0]+=t*n[2],n[3]+=t*n[5],n[6]+=t*n[8],n[1]+=e*n[2],n[4]+=e*n[5],n[7]+=e*n[8],this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<9;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}let xt;yt.prototype.isMatrix3=!0;class _t{static getDataURL(t){if(/^data:/i.test(t.src))return t.src;if("undefined"==typeof HTMLCanvasElement)return t.src;let e;if(t instanceof HTMLCanvasElement)e=t;else{void 0===xt&&(xt=document.createElementNS("http://www.w3.org/1999/xhtml","canvas")),xt.width=t.width,xt.height=t.height;const n=xt.getContext("2d");t instanceof ImageData?n.putImageData(t,0,0):n.drawImage(t,0,0,t.width,t.height),e=xt}return e.width>2048||e.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",t),e.toDataURL("image/jpeg",.6)):e.toDataURL("image/png")}}let bt=0;class Mt extends rt{constructor(t=Mt.DEFAULT_IMAGE,e=Mt.DEFAULT_MAPPING,n=1001,i=1001,r=1006,s=1008,a=1023,o=1009,l=1,c=3e3){super(),Object.defineProperty(this,"id",{value:bt++}),this.uuid=ct(),this.name="",this.image=t,this.mipmaps=[],this.mapping=e,this.wrapS=n,this.wrapT=i,this.magFilter=r,this.minFilter=s,this.anisotropy=l,this.format=a,this.internalFormat=null,this.type=o,this.offset=new vt(0,0),this.repeat=new vt(1,1),this.center=new vt(0,0),this.rotation=0,this.matrixAutoUpdate=!0,this.matrix=new yt,this.generateMipmaps=!0,this.premultiplyAlpha=!1,this.flipY=!0,this.unpackAlignment=4,this.encoding=c,this.version=0,this.onUpdate=null,this.isRenderTargetTexture=!1}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}clone(){return(new this.constructor).copy(this)}copy(t){return this.name=t.name,this.image=t.image,this.mipmaps=t.mipmaps.slice(0),this.mapping=t.mapping,this.wrapS=t.wrapS,this.wrapT=t.wrapT,this.magFilter=t.magFilter,this.minFilter=t.minFilter,this.anisotropy=t.anisotropy,this.format=t.format,this.internalFormat=t.internalFormat,this.type=t.type,this.offset.copy(t.offset),this.repeat.copy(t.repeat),this.center.copy(t.center),this.rotation=t.rotation,this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrix.copy(t.matrix),this.generateMipmaps=t.generateMipmaps,this.premultiplyAlpha=t.premultiplyAlpha,this.flipY=t.flipY,this.unpackAlignment=t.unpackAlignment,this.encoding=t.encoding,this}toJSON(t){const e=void 0===t||"string"==typeof t;if(!e&&void 0!==t.textures[this.uuid])return t.textures[this.uuid];const n={metadata:{version:4.5,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,mapping:this.mapping,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,type:this.type,encoding:this.encoding,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};if(void 0!==this.image){const i=this.image;if(void 0===i.uuid&&(i.uuid=ct()),!e&&void 0===t.images[i.uuid]){let e;if(Array.isArray(i)){e=[];for(let t=0,n=i.length;t1)switch(this.wrapS){case h:t.x=t.x-Math.floor(t.x);break;case u:t.x=t.x<0?0:1;break;case d:1===Math.abs(Math.floor(t.x)%2)?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x)}if(t.y<0||t.y>1)switch(this.wrapT){case h:t.y=t.y-Math.floor(t.y);break;case u:t.y=t.y<0?0:1;break;case d:1===Math.abs(Math.floor(t.y)%2)?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y)}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){!0===t&&this.version++}}function wt(t){return"undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap?_t.getDataURL(t):t.data?{data:Array.prototype.slice.call(t.data),width:t.width,height:t.height,type:t.data.constructor.name}:(console.warn("THREE.Texture: Unable to serialize Texture."),{})}Mt.DEFAULT_IMAGE=void 0,Mt.DEFAULT_MAPPING=i,Mt.prototype.isTexture=!0;class St{constructor(t=0,e=0,n=0,i=1){this.x=t,this.y=e,this.z=n,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,n,i){return this.x=t,this.y=e,this.z=n,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=void 0!==t.w?t.w:1,this}add(t,e){return void 0!==e?(console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this)}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t,e){return void 0!==e?(console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this)}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=this.w,s=t.elements;return this.x=s[0]*e+s[4]*n+s[8]*i+s[12]*r,this.y=s[1]*e+s[5]*n+s[9]*i+s[13]*r,this.z=s[2]*e+s[6]*n+s[10]*i+s[14]*r,this.w=s[3]*e+s[7]*n+s[11]*i+s[15]*r,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,n,i,r;const s=.01,a=.1,o=t.elements,l=o[0],c=o[4],h=o[8],u=o[1],d=o[5],p=o[9],m=o[2],f=o[6],g=o[10];if(Math.abs(c-u)o&&t>v?tv?o=0?1:-1,i=1-e*e;if(i>Number.EPSILON){const r=Math.sqrt(i),s=Math.atan2(r,e*n);t=Math.sin(t*s)/r,a=Math.sin(a*s)/r}const r=a*n;if(o=o*t+u*r,l=l*t+d*r,c=c*t+p*r,h=h*t+m*r,t===1-a){const t=1/Math.sqrt(o*o+l*l+c*c+h*h);o*=t,l*=t,c*=t,h*=t}}t[e]=o,t[e+1]=l,t[e+2]=c,t[e+3]=h}static multiplyQuaternionsFlat(t,e,n,i,r,s){const a=n[i],o=n[i+1],l=n[i+2],c=n[i+3],h=r[s],u=r[s+1],d=r[s+2],p=r[s+3];return t[e]=a*p+c*h+o*d-l*u,t[e+1]=o*p+c*u+l*h-a*d,t[e+2]=l*p+c*d+a*u-o*h,t[e+3]=c*p-a*h-o*u-l*d,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e){if(!t||!t.isEuler)throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");const n=t._x,i=t._y,r=t._z,s=t._order,a=Math.cos,o=Math.sin,l=a(n/2),c=a(i/2),h=a(r/2),u=o(n/2),d=o(i/2),p=o(r/2);switch(s){case"XYZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"YXZ":this._x=u*c*h+l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"ZXY":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h-u*d*p;break;case"ZYX":this._x=u*c*h-l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h+u*d*p;break;case"YZX":this._x=u*c*h+l*d*p,this._y=l*d*h+u*c*p,this._z=l*c*p-u*d*h,this._w=l*c*h-u*d*p;break;case"XZY":this._x=u*c*h-l*d*p,this._y=l*d*h-u*c*p,this._z=l*c*p+u*d*h,this._w=l*c*h+u*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+s)}return!1!==e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const n=e/2,i=Math.sin(n);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,n=e[0],i=e[4],r=e[8],s=e[1],a=e[5],o=e[9],l=e[2],c=e[6],h=e[10],u=n+a+h;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(c-o)*t,this._y=(r-l)*t,this._z=(s-i)*t}else if(n>a&&n>h){const t=2*Math.sqrt(1+n-a-h);this._w=(c-o)/t,this._x=.25*t,this._y=(i+s)/t,this._z=(r+l)/t}else if(a>h){const t=2*Math.sqrt(1+a-n-h);this._w=(r-l)/t,this._x=(i+s)/t,this._y=.25*t,this._z=(o+c)/t}else{const t=2*Math.sqrt(1+h-n-a);this._w=(s-i)/t,this._x=(r+l)/t,this._y=(o+c)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let n=t.dot(e)+1;return nMath.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=n):(this._x=0,this._y=-t.z,this._z=t.y,this._w=n)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=n),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(ht(this.dot(t),-1,1)))}rotateTowards(t,e){const n=this.angleTo(t);if(0===n)return this;const i=Math.min(1,e/n);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return 0===t?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t,e){return void 0!==e?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(t,e)):this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const n=t._x,i=t._y,r=t._z,s=t._w,a=e._x,o=e._y,l=e._z,c=e._w;return this._x=n*c+s*a+i*l-r*o,this._y=i*c+s*o+r*a-n*l,this._z=r*c+s*l+n*o-i*a,this._w=s*c-n*a-i*o-r*l,this._onChangeCallback(),this}slerp(t,e){if(0===e)return this;if(1===e)return this.copy(t);const n=this._x,i=this._y,r=this._z,s=this._w;let a=s*t._w+n*t._x+i*t._y+r*t._z;if(a<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,a=-a):this.copy(t),a>=1)return this._w=s,this._x=n,this._y=i,this._z=r,this;const o=1-a*a;if(o<=Number.EPSILON){const t=1-e;return this._w=t*s+e*this._w,this._x=t*n+e*this._x,this._y=t*i+e*this._y,this._z=t*r+e*this._z,this.normalize(),this._onChangeCallback(),this}const l=Math.sqrt(o),c=Math.atan2(l,a),h=Math.sin((1-e)*c)/l,u=Math.sin(e*c)/l;return this._w=s*h+this._w*u,this._x=n*h+this._x*u,this._y=i*h+this._y*u,this._z=r*h+this._z*u,this._onChangeCallback(),this}slerpQuaternions(t,e,n){this.copy(t).slerp(e,n)}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}}Lt.prototype.isQuaternion=!0;class Rt{constructor(t=0,e=0,n=0){this.x=t,this.y=e,this.z=n}set(t,e,n){return void 0===n&&(n=this.z),this.x=t,this.y=e,this.z=n,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t,e){return void 0!==e?(console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this.z+=t.z,this)}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t,e){return void 0!==e?(console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this.z-=t.z,this)}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t,e){return void 0!==e?(console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(t,e)):(this.x*=t.x,this.y*=t.y,this.z*=t.z,this)}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return t&&t.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."),this.applyQuaternion(Pt.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(Pt.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*n+r[6]*i,this.y=r[1]*e+r[4]*n+r[7]*i,this.z=r[2]*e+r[5]*n+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=t.elements,s=1/(r[3]*e+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*n+r[8]*i+r[12])*s,this.y=(r[1]*e+r[5]*n+r[9]*i+r[13])*s,this.z=(r[2]*e+r[6]*n+r[10]*i+r[14])*s,this}applyQuaternion(t){const e=this.x,n=this.y,i=this.z,r=t.x,s=t.y,a=t.z,o=t.w,l=o*e+s*i-a*n,c=o*n+a*e-r*i,h=o*i+r*n-s*e,u=-r*e-s*n-a*i;return this.x=l*o+u*-r+c*-a-h*-s,this.y=c*o+u*-s+h*-r-l*-a,this.z=h*o+u*-a+l*-s-c*-r,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*n+r[8]*i,this.y=r[1]*e+r[5]*n+r[9]*i,this.z=r[2]*e+r[6]*n+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this.z=Math.max(t,Math.min(e,this.z)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this}cross(t,e){return void 0!==e?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(t,e)):this.crossVectors(this,t)}crossVectors(t,e){const n=t.x,i=t.y,r=t.z,s=e.x,a=e.y,o=e.z;return this.x=i*o-r*a,this.y=r*s-n*o,this.z=n*a-i*s,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const n=t.dot(this)/e;return this.copy(t).multiplyScalar(n)}projectOnPlane(t){return Ct.copy(this).projectOnVector(t),this.sub(Ct)}reflect(t){return this.sub(Ct.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(ht(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return e*e+n*n+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,n){const i=Math.sin(e)*t;return this.x=i*Math.sin(n),this.y=Math.cos(e)*t,this.z=i*Math.cos(n),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,4*e)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,3*e)}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e,n){return void 0!==n&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."),this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}}Rt.prototype.isVector3=!0;const Ct=new Rt,Pt=new Lt;class It{constructor(t=new Rt(1/0,1/0,1/0),e=new Rt(-1/0,-1/0,-1/0)){this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){let e=1/0,n=1/0,i=1/0,r=-1/0,s=-1/0,a=-1/0;for(let o=0,l=t.length;or&&(r=l),c>s&&(s=c),h>a&&(a=h)}return this.min.set(e,n,i),this.max.set(r,s,a),this}setFromBufferAttribute(t){let e=1/0,n=1/0,i=1/0,r=-1/0,s=-1/0,a=-1/0;for(let o=0,l=t.count;or&&(r=l),c>s&&(s=c),h>a&&(a=h)}return this.min.set(e,n,i),this.max.set(r,s,a),this}setFromPoints(t){this.makeEmpty();for(let e=0,n=t.length;ethis.max.x||t.ythis.max.y||t.zthis.max.z)}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return!(t.max.xthis.max.x||t.max.ythis.max.y||t.max.zthis.max.z)}intersectsSphere(t){return this.clampPoint(t.center,Nt),Nt.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,n;return t.normal.x>0?(e=t.normal.x*this.min.x,n=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,n=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,n+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,n+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,n+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,n+=t.normal.z*this.min.z),e<=-t.constant&&n>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(kt),Vt.subVectors(this.max,kt),Bt.subVectors(t.a,kt),Ft.subVectors(t.b,kt),Ot.subVectors(t.c,kt),Ut.subVectors(Ft,Bt),Ht.subVectors(Ot,Ft),Gt.subVectors(Bt,Ot);let e=[0,-Ut.z,Ut.y,0,-Ht.z,Ht.y,0,-Gt.z,Gt.y,Ut.z,0,-Ut.x,Ht.z,0,-Ht.x,Gt.z,0,-Gt.x,-Ut.y,Ut.x,0,-Ht.y,Ht.x,0,-Gt.y,Gt.x,0];return!!qt(e,Bt,Ft,Ot,Vt)&&(e=[1,0,0,0,1,0,0,0,1],!!qt(e,Bt,Ft,Ot,Vt)&&(Wt.crossVectors(Ut,Ht),e=[Wt.x,Wt.y,Wt.z],qt(e,Bt,Ft,Ot,Vt)))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return Nt.copy(t).clamp(this.min,this.max).sub(t).length()}getBoundingSphere(t){return this.getCenter(t.center),t.radius=.5*this.getSize(Nt).length(),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()||(Dt[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Dt[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Dt[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Dt[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Dt[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Dt[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Dt[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Dt[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Dt)),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}It.prototype.isBox3=!0;const Dt=[new Rt,new Rt,new Rt,new Rt,new Rt,new Rt,new Rt,new Rt],Nt=new Rt,zt=new It,Bt=new Rt,Ft=new Rt,Ot=new Rt,Ut=new Rt,Ht=new Rt,Gt=new Rt,kt=new Rt,Vt=new Rt,Wt=new Rt,jt=new Rt;function qt(t,e,n,i,r){for(let s=0,a=t.length-3;s<=a;s+=3){jt.fromArray(t,s);const a=r.x*Math.abs(jt.x)+r.y*Math.abs(jt.y)+r.z*Math.abs(jt.z),o=e.dot(jt),l=n.dot(jt),c=i.dot(jt);if(Math.max(-Math.max(o,l,c),Math.min(o,l,c))>a)return!1}return!0}const Xt=new It,Yt=new Rt,Jt=new Rt,Zt=new Rt;class Qt{constructor(t=new Rt,e=-1){this.center=t,this.radius=e}set(t,e){return this.center.copy(t),this.radius=e,this}setFromPoints(t,e){const n=this.center;void 0!==e?n.copy(e):Xt.setFromPoints(t).getCenter(n);let i=0;for(let e=0,r=t.length;ethis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){Zt.subVectors(t,this.center);const e=Zt.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),n=.5*(t-this.radius);this.center.add(Zt.multiplyScalar(n/t)),this.radius+=n}return this}union(t){return Jt.subVectors(t.center,this.center).normalize().multiplyScalar(t.radius),this.expandByPoint(Yt.copy(t.center).add(Jt)),this.expandByPoint(Yt.copy(t.center).sub(Jt)),this}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const Kt=new Rt,$t=new Rt,te=new Rt,ee=new Rt,ne=new Rt,ie=new Rt,re=new Rt;class se{constructor(t=new Rt,e=new Rt(0,0,-1)){this.origin=t,this.direction=e}set(t,e){return this.origin.copy(t),this.direction.copy(e),this}copy(t){return this.origin.copy(t.origin),this.direction.copy(t.direction),this}at(t,e){return e.copy(this.direction).multiplyScalar(t).add(this.origin)}lookAt(t){return this.direction.copy(t).sub(this.origin).normalize(),this}recast(t){return this.origin.copy(this.at(t,Kt)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const n=e.dot(this.direction);return n<0?e.copy(this.origin):e.copy(this.direction).multiplyScalar(n).add(this.origin)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=Kt.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):(Kt.copy(this.direction).multiplyScalar(e).add(this.origin),Kt.distanceToSquared(t))}distanceSqToSegment(t,e,n,i){$t.copy(t).add(e).multiplyScalar(.5),te.copy(e).sub(t).normalize(),ee.copy(this.origin).sub($t);const r=.5*t.distanceTo(e),s=-this.direction.dot(te),a=ee.dot(this.direction),o=-ee.dot(te),l=ee.lengthSq(),c=Math.abs(1-s*s);let h,u,d,p;if(c>0)if(h=s*o-a,u=s*a-o,p=r*c,h>=0)if(u>=-p)if(u<=p){const t=1/c;h*=t,u*=t,d=h*(h+s*u+2*a)+u*(s*h+u+2*o)+l}else u=r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u=-r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;else u<=-p?(h=Math.max(0,-(-s*r+a)),u=h>0?-r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l):u<=p?(h=0,u=Math.min(Math.max(-r,-o),r),d=u*(u+2*o)+l):(h=Math.max(0,-(s*r+a)),u=h>0?r:Math.min(Math.max(-r,-o),r),d=-h*h+u*(u+2*o)+l);else u=s>0?-r:r,h=Math.max(0,-(s*u+a)),d=-h*h+u*(u+2*o)+l;return n&&n.copy(this.direction).multiplyScalar(h).add(this.origin),i&&i.copy(te).multiplyScalar(u).add($t),d}intersectSphere(t,e){Kt.subVectors(t.center,this.origin);const n=Kt.dot(this.direction),i=Kt.dot(Kt)-n*n,r=t.radius*t.radius;if(i>r)return null;const s=Math.sqrt(r-i),a=n-s,o=n+s;return a<0&&o<0?null:a<0?this.at(o,e):this.at(a,e)}intersectsSphere(t){return this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(0===e)return 0===t.distanceToPoint(this.origin)?0:null;const n=-(this.origin.dot(t.normal)+t.constant)/e;return n>=0?n:null}intersectPlane(t,e){const n=this.distanceToPlane(t);return null===n?null:this.at(n,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);if(0===e)return!0;return t.normal.dot(this.direction)*e<0}intersectBox(t,e){let n,i,r,s,a,o;const l=1/this.direction.x,c=1/this.direction.y,h=1/this.direction.z,u=this.origin;return l>=0?(n=(t.min.x-u.x)*l,i=(t.max.x-u.x)*l):(n=(t.max.x-u.x)*l,i=(t.min.x-u.x)*l),c>=0?(r=(t.min.y-u.y)*c,s=(t.max.y-u.y)*c):(r=(t.max.y-u.y)*c,s=(t.min.y-u.y)*c),n>s||r>i?null:((r>n||n!=n)&&(n=r),(s=0?(a=(t.min.z-u.z)*h,o=(t.max.z-u.z)*h):(a=(t.max.z-u.z)*h,o=(t.min.z-u.z)*h),n>o||a>i?null:((a>n||n!=n)&&(n=a),(o=0?n:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,Kt)}intersectTriangle(t,e,n,i,r){ne.subVectors(e,t),ie.subVectors(n,t),re.crossVectors(ne,ie);let s,a=this.direction.dot(re);if(a>0){if(i)return null;s=1}else{if(!(a<0))return null;s=-1,a=-a}ee.subVectors(this.origin,t);const o=s*this.direction.dot(ie.crossVectors(ee,ie));if(o<0)return null;const l=s*this.direction.dot(ne.cross(ee));if(l<0)return null;if(o+l>a)return null;const c=-s*ee.dot(re);return c<0?null:this.at(c/a,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class ae{constructor(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],arguments.length>0&&console.error("THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.")}set(t,e,n,i,r,s,a,o,l,c,h,u,d,p,m,f){const g=this.elements;return g[0]=t,g[4]=e,g[8]=n,g[12]=i,g[1]=r,g[5]=s,g[9]=a,g[13]=o,g[2]=l,g[6]=c,g[10]=h,g[14]=u,g[3]=d,g[7]=p,g[11]=m,g[15]=f,this}identity(){return this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1),this}clone(){return(new ae).fromArray(this.elements)}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],e[9]=n[9],e[10]=n[10],e[11]=n[11],e[12]=n[12],e[13]=n[13],e[14]=n[14],e[15]=n[15],this}copyPosition(t){const e=this.elements,n=t.elements;return e[12]=n[12],e[13]=n[13],e[14]=n[14],this}setFromMatrix3(t){const e=t.elements;return this.set(e[0],e[3],e[6],0,e[1],e[4],e[7],0,e[2],e[5],e[8],0,0,0,0,1),this}extractBasis(t,e,n){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),n.setFromMatrixColumn(this,2),this}makeBasis(t,e,n){return this.set(t.x,e.x,n.x,0,t.y,e.y,n.y,0,t.z,e.z,n.z,0,0,0,0,1),this}extractRotation(t){const e=this.elements,n=t.elements,i=1/oe.setFromMatrixColumn(t,0).length(),r=1/oe.setFromMatrixColumn(t,1).length(),s=1/oe.setFromMatrixColumn(t,2).length();return e[0]=n[0]*i,e[1]=n[1]*i,e[2]=n[2]*i,e[3]=0,e[4]=n[4]*r,e[5]=n[5]*r,e[6]=n[6]*r,e[7]=0,e[8]=n[8]*s,e[9]=n[9]*s,e[10]=n[10]*s,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromEuler(t){t&&t.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");const e=this.elements,n=t.x,i=t.y,r=t.z,s=Math.cos(n),a=Math.sin(n),o=Math.cos(i),l=Math.sin(i),c=Math.cos(r),h=Math.sin(r);if("XYZ"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=-o*h,e[8]=l,e[1]=n+i*l,e[5]=t-r*l,e[9]=-a*o,e[2]=r-t*l,e[6]=i+n*l,e[10]=s*o}else if("YXZ"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t+r*a,e[4]=i*a-n,e[8]=s*l,e[1]=s*h,e[5]=s*c,e[9]=-a,e[2]=n*a-i,e[6]=r+t*a,e[10]=s*o}else if("ZXY"===t.order){const t=o*c,n=o*h,i=l*c,r=l*h;e[0]=t-r*a,e[4]=-s*h,e[8]=i+n*a,e[1]=n+i*a,e[5]=s*c,e[9]=r-t*a,e[2]=-s*l,e[6]=a,e[10]=s*o}else if("ZYX"===t.order){const t=s*c,n=s*h,i=a*c,r=a*h;e[0]=o*c,e[4]=i*l-n,e[8]=t*l+r,e[1]=o*h,e[5]=r*l+t,e[9]=n*l-i,e[2]=-l,e[6]=a*o,e[10]=s*o}else if("YZX"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=r-t*h,e[8]=i*h+n,e[1]=h,e[5]=s*c,e[9]=-a*c,e[2]=-l*c,e[6]=n*h+i,e[10]=t-r*h}else if("XZY"===t.order){const t=s*o,n=s*l,i=a*o,r=a*l;e[0]=o*c,e[4]=-h,e[8]=l*c,e[1]=t*h+r,e[5]=s*c,e[9]=n*h-i,e[2]=i*h-n,e[6]=a*c,e[10]=r*h+t}return e[3]=0,e[7]=0,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromQuaternion(t){return this.compose(ce,t,he)}lookAt(t,e,n){const i=this.elements;return pe.subVectors(t,e),0===pe.lengthSq()&&(pe.z=1),pe.normalize(),ue.crossVectors(n,pe),0===ue.lengthSq()&&(1===Math.abs(n.z)?pe.x+=1e-4:pe.z+=1e-4,pe.normalize(),ue.crossVectors(n,pe)),ue.normalize(),de.crossVectors(pe,ue),i[0]=ue.x,i[4]=de.x,i[8]=pe.x,i[1]=ue.y,i[5]=de.y,i[9]=pe.y,i[2]=ue.z,i[6]=de.z,i[10]=pe.z,this}multiply(t,e){return void 0!==e?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."),this.multiplyMatrices(t,e)):this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[4],o=n[8],l=n[12],c=n[1],h=n[5],u=n[9],d=n[13],p=n[2],m=n[6],f=n[10],g=n[14],v=n[3],y=n[7],x=n[11],_=n[15],b=i[0],M=i[4],w=i[8],S=i[12],T=i[1],E=i[5],A=i[9],L=i[13],R=i[2],C=i[6],P=i[10],I=i[14],D=i[3],N=i[7],z=i[11],B=i[15];return r[0]=s*b+a*T+o*R+l*D,r[4]=s*M+a*E+o*C+l*N,r[8]=s*w+a*A+o*P+l*z,r[12]=s*S+a*L+o*I+l*B,r[1]=c*b+h*T+u*R+d*D,r[5]=c*M+h*E+u*C+d*N,r[9]=c*w+h*A+u*P+d*z,r[13]=c*S+h*L+u*I+d*B,r[2]=p*b+m*T+f*R+g*D,r[6]=p*M+m*E+f*C+g*N,r[10]=p*w+m*A+f*P+g*z,r[14]=p*S+m*L+f*I+g*B,r[3]=v*b+y*T+x*R+_*D,r[7]=v*M+y*E+x*C+_*N,r[11]=v*w+y*A+x*P+_*z,r[15]=v*S+y*L+x*I+_*B,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[4]*=t,e[8]*=t,e[12]*=t,e[1]*=t,e[5]*=t,e[9]*=t,e[13]*=t,e[2]*=t,e[6]*=t,e[10]*=t,e[14]*=t,e[3]*=t,e[7]*=t,e[11]*=t,e[15]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[4],i=t[8],r=t[12],s=t[1],a=t[5],o=t[9],l=t[13],c=t[2],h=t[6],u=t[10],d=t[14];return t[3]*(+r*o*h-i*l*h-r*a*u+n*l*u+i*a*d-n*o*d)+t[7]*(+e*o*d-e*l*u+r*s*u-i*s*d+i*l*c-r*o*c)+t[11]*(+e*l*h-e*a*d-r*s*h+n*s*d+r*a*c-n*l*c)+t[15]*(-i*a*c-e*o*h+e*a*u+i*s*h-n*s*u+n*o*c)}transpose(){const t=this.elements;let e;return e=t[1],t[1]=t[4],t[4]=e,e=t[2],t[2]=t[8],t[8]=e,e=t[6],t[6]=t[9],t[9]=e,e=t[3],t[3]=t[12],t[12]=e,e=t[7],t[7]=t[13],t[13]=e,e=t[11],t[11]=t[14],t[14]=e,this}setPosition(t,e,n){const i=this.elements;return t.isVector3?(i[12]=t.x,i[13]=t.y,i[14]=t.z):(i[12]=t,i[13]=e,i[14]=n),this}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=t[9],u=t[10],d=t[11],p=t[12],m=t[13],f=t[14],g=t[15],v=h*f*l-m*u*l+m*o*d-a*f*d-h*o*g+a*u*g,y=p*u*l-c*f*l-p*o*d+s*f*d+c*o*g-s*u*g,x=c*m*l-p*h*l+p*a*d-s*m*d-c*a*g+s*h*g,_=p*h*o-c*m*o-p*a*u+s*m*u+c*a*f-s*h*f,b=e*v+n*y+i*x+r*_;if(0===b)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const M=1/b;return t[0]=v*M,t[1]=(m*u*r-h*f*r-m*i*d+n*f*d+h*i*g-n*u*g)*M,t[2]=(a*f*r-m*o*r+m*i*l-n*f*l-a*i*g+n*o*g)*M,t[3]=(h*o*r-a*u*r-h*i*l+n*u*l+a*i*d-n*o*d)*M,t[4]=y*M,t[5]=(c*f*r-p*u*r+p*i*d-e*f*d-c*i*g+e*u*g)*M,t[6]=(p*o*r-s*f*r-p*i*l+e*f*l+s*i*g-e*o*g)*M,t[7]=(s*u*r-c*o*r+c*i*l-e*u*l-s*i*d+e*o*d)*M,t[8]=x*M,t[9]=(p*h*r-c*m*r-p*n*d+e*m*d+c*n*g-e*h*g)*M,t[10]=(s*m*r-p*a*r+p*n*l-e*m*l-s*n*g+e*a*g)*M,t[11]=(c*a*r-s*h*r-c*n*l+e*h*l+s*n*d-e*a*d)*M,t[12]=_*M,t[13]=(c*m*i-p*h*i+p*n*u-e*m*u-c*n*f+e*h*f)*M,t[14]=(p*a*i-s*m*i-p*n*o+e*m*o+s*n*f-e*a*f)*M,t[15]=(s*h*i-c*a*i+c*n*o-e*h*o-s*n*u+e*a*u)*M,this}scale(t){const e=this.elements,n=t.x,i=t.y,r=t.z;return e[0]*=n,e[4]*=i,e[8]*=r,e[1]*=n,e[5]*=i,e[9]*=r,e[2]*=n,e[6]*=i,e[10]*=r,e[3]*=n,e[7]*=i,e[11]*=r,this}getMaxScaleOnAxis(){const t=this.elements,e=t[0]*t[0]+t[1]*t[1]+t[2]*t[2],n=t[4]*t[4]+t[5]*t[5]+t[6]*t[6],i=t[8]*t[8]+t[9]*t[9]+t[10]*t[10];return Math.sqrt(Math.max(e,n,i))}makeTranslation(t,e,n){return this.set(1,0,0,t,0,1,0,e,0,0,1,n,0,0,0,1),this}makeRotationX(t){const e=Math.cos(t),n=Math.sin(t);return this.set(1,0,0,0,0,e,-n,0,0,n,e,0,0,0,0,1),this}makeRotationY(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,0,n,0,0,1,0,0,-n,0,e,0,0,0,0,1),this}makeRotationZ(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,0,n,e,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(t,e){const n=Math.cos(e),i=Math.sin(e),r=1-n,s=t.x,a=t.y,o=t.z,l=r*s,c=r*a;return this.set(l*s+n,l*a-i*o,l*o+i*a,0,l*a+i*o,c*a+n,c*o-i*s,0,l*o-i*a,c*o+i*s,r*o*o+n,0,0,0,0,1),this}makeScale(t,e,n){return this.set(t,0,0,0,0,e,0,0,0,0,n,0,0,0,0,1),this}makeShear(t,e,n,i,r,s){return this.set(1,n,r,0,t,1,s,0,e,i,1,0,0,0,0,1),this}compose(t,e,n){const i=this.elements,r=e._x,s=e._y,a=e._z,o=e._w,l=r+r,c=s+s,h=a+a,u=r*l,d=r*c,p=r*h,m=s*c,f=s*h,g=a*h,v=o*l,y=o*c,x=o*h,_=n.x,b=n.y,M=n.z;return i[0]=(1-(m+g))*_,i[1]=(d+x)*_,i[2]=(p-y)*_,i[3]=0,i[4]=(d-x)*b,i[5]=(1-(u+g))*b,i[6]=(f+v)*b,i[7]=0,i[8]=(p+y)*M,i[9]=(f-v)*M,i[10]=(1-(u+m))*M,i[11]=0,i[12]=t.x,i[13]=t.y,i[14]=t.z,i[15]=1,this}decompose(t,e,n){const i=this.elements;let r=oe.set(i[0],i[1],i[2]).length();const s=oe.set(i[4],i[5],i[6]).length(),a=oe.set(i[8],i[9],i[10]).length();this.determinant()<0&&(r=-r),t.x=i[12],t.y=i[13],t.z=i[14],le.copy(this);const o=1/r,l=1/s,c=1/a;return le.elements[0]*=o,le.elements[1]*=o,le.elements[2]*=o,le.elements[4]*=l,le.elements[5]*=l,le.elements[6]*=l,le.elements[8]*=c,le.elements[9]*=c,le.elements[10]*=c,e.setFromRotationMatrix(le),n.x=r,n.y=s,n.z=a,this}makePerspective(t,e,n,i,r,s){void 0===s&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.");const a=this.elements,o=2*r/(e-t),l=2*r/(n-i),c=(e+t)/(e-t),h=(n+i)/(n-i),u=-(s+r)/(s-r),d=-2*s*r/(s-r);return a[0]=o,a[4]=0,a[8]=c,a[12]=0,a[1]=0,a[5]=l,a[9]=h,a[13]=0,a[2]=0,a[6]=0,a[10]=u,a[14]=d,a[3]=0,a[7]=0,a[11]=-1,a[15]=0,this}makeOrthographic(t,e,n,i,r,s){const a=this.elements,o=1/(e-t),l=1/(n-i),c=1/(s-r),h=(e+t)*o,u=(n+i)*l,d=(s+r)*c;return a[0]=2*o,a[4]=0,a[8]=0,a[12]=-h,a[1]=0,a[5]=2*l,a[9]=0,a[13]=-u,a[2]=0,a[6]=0,a[10]=-2*c,a[14]=-d,a[3]=0,a[7]=0,a[11]=0,a[15]=1,this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<16;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<16;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t[e+9]=n[9],t[e+10]=n[10],t[e+11]=n[11],t[e+12]=n[12],t[e+13]=n[13],t[e+14]=n[14],t[e+15]=n[15],t}}ae.prototype.isMatrix4=!0;const oe=new Rt,le=new ae,ce=new Rt(0,0,0),he=new Rt(1,1,1),ue=new Rt,de=new Rt,pe=new Rt,me=new ae,fe=new Lt;class ge{constructor(t=0,e=0,n=0,i=ge.DefaultOrder){this._x=t,this._y=e,this._z=n,this._order=i}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get order(){return this._order}set order(t){this._order=t,this._onChangeCallback()}set(t,e,n,i=this._order){return this._x=t,this._y=e,this._z=n,this._order=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._order)}copy(t){return this._x=t._x,this._y=t._y,this._z=t._z,this._order=t._order,this._onChangeCallback(),this}setFromRotationMatrix(t,e=this._order,n=!0){const i=t.elements,r=i[0],s=i[4],a=i[8],o=i[1],l=i[5],c=i[9],h=i[2],u=i[6],d=i[10];switch(e){case"XYZ":this._y=Math.asin(ht(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-c,d),this._z=Math.atan2(-s,r)):(this._x=Math.atan2(u,l),this._z=0);break;case"YXZ":this._x=Math.asin(-ht(c,-1,1)),Math.abs(c)<.9999999?(this._y=Math.atan2(a,d),this._z=Math.atan2(o,l)):(this._y=Math.atan2(-h,r),this._z=0);break;case"ZXY":this._x=Math.asin(ht(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(-h,d),this._z=Math.atan2(-s,l)):(this._y=0,this._z=Math.atan2(o,r));break;case"ZYX":this._y=Math.asin(-ht(h,-1,1)),Math.abs(h)<.9999999?(this._x=Math.atan2(u,d),this._z=Math.atan2(o,r)):(this._x=0,this._z=Math.atan2(-s,l));break;case"YZX":this._z=Math.asin(ht(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-c,l),this._y=Math.atan2(-h,r)):(this._x=0,this._y=Math.atan2(a,d));break;case"XZY":this._z=Math.asin(-ht(s,-1,1)),Math.abs(s)<.9999999?(this._x=Math.atan2(u,l),this._y=Math.atan2(a,r)):(this._x=Math.atan2(-c,d),this._y=0);break;default:console.warn("THREE.Euler: .setFromRotationMatrix() encountered an unknown order: "+e)}return this._order=e,!0===n&&this._onChangeCallback(),this}setFromQuaternion(t,e,n){return me.makeRotationFromQuaternion(t),this.setFromRotationMatrix(me,e,n)}setFromVector3(t,e=this._order){return this.set(t.x,t.y,t.z,e)}reorder(t){return fe.setFromEuler(this),this.setFromQuaternion(fe,t)}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._order===this._order}fromArray(t){return this._x=t[0],this._y=t[1],this._z=t[2],void 0!==t[3]&&(this._order=t[3]),this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._order,t}toVector3(t){return t?t.set(this._x,this._y,this._z):new Rt(this._x,this._y,this._z)}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}}ge.prototype.isEuler=!0,ge.DefaultOrder="XYZ",ge.RotationOrders=["XYZ","YZX","ZXY","XZY","YXZ","ZYX"];class ve{constructor(){this.mask=1}set(t){this.mask=1<1){for(let t=0;t1){for(let t=0;t0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(n.geometries=e),i.length>0&&(n.materials=i),r.length>0&&(n.textures=r),a.length>0&&(n.images=a),o.length>0&&(n.shapes=o),l.length>0&&(n.skeletons=l),c.length>0&&(n.animations=c)}return n.object=i,n;function s(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}}clone(t){return(new this.constructor).copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.userData=JSON.parse(JSON.stringify(t.userData)),!0===e)for(let e=0;e0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,n,i,r){Ie.subVectors(i,e),De.subVectors(n,e),Ne.subVectors(t,e);const s=Ie.dot(Ie),a=Ie.dot(De),o=Ie.dot(Ne),l=De.dot(De),c=De.dot(Ne),h=s*l-a*a;if(0===h)return r.set(-2,-1,-1);const u=1/h,d=(l*o-a*c)*u,p=(s*c-a*o)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,n,i){return this.getBarycoord(t,e,n,i,ze),ze.x>=0&&ze.y>=0&&ze.x+ze.y<=1}static getUV(t,e,n,i,r,s,a,o){return this.getBarycoord(t,e,n,i,ze),o.set(0,0),o.addScaledVector(r,ze.x),o.addScaledVector(s,ze.y),o.addScaledVector(a,ze.z),o}static isFrontFacing(t,e,n,i){return Ie.subVectors(n,e),De.subVectors(t,e),Ie.cross(De).dot(i)<0}set(t,e,n){return this.a.copy(t),this.b.copy(e),this.c.copy(n),this}setFromPointsAndIndices(t,e,n,i){return this.a.copy(t[e]),this.b.copy(t[n]),this.c.copy(t[i]),this}clone(){return(new this.constructor).copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return Ie.subVectors(this.c,this.b),De.subVectors(this.a,this.b),.5*Ie.cross(De).length()}getMidpoint(t){return t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return ke.getNormal(this.a,this.b,this.c,t)}getPlane(t){return t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return ke.getBarycoord(t,this.a,this.b,this.c,e)}getUV(t,e,n,i,r){return ke.getUV(t,this.a,this.b,this.c,e,n,i,r)}containsPoint(t){return ke.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return ke.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){const n=this.a,i=this.b,r=this.c;let s,a;Be.subVectors(i,n),Fe.subVectors(r,n),Ue.subVectors(t,n);const o=Be.dot(Ue),l=Fe.dot(Ue);if(o<=0&&l<=0)return e.copy(n);He.subVectors(t,i);const c=Be.dot(He),h=Fe.dot(He);if(c>=0&&h<=c)return e.copy(i);const u=o*h-c*l;if(u<=0&&o>=0&&c<=0)return s=o/(o-c),e.copy(n).addScaledVector(Be,s);Ge.subVectors(t,r);const d=Be.dot(Ge),p=Fe.dot(Ge);if(p>=0&&d<=p)return e.copy(r);const m=d*l-o*p;if(m<=0&&l>=0&&p<=0)return a=l/(l-p),e.copy(n).addScaledVector(Fe,a);const f=c*p-d*h;if(f<=0&&h-c>=0&&d-p>=0)return Oe.subVectors(r,i),a=(h-c)/(h-c+(d-p)),e.copy(i).addScaledVector(Oe,a);const g=1/(f+m+u);return s=m*g,a=u*g,e.copy(n).addScaledVector(Be,s).addScaledVector(Fe,a)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}let Ve=0;class We extends rt{constructor(){super(),Object.defineProperty(this,"id",{value:Ve++}),this.uuid=ct(),this.name="",this.type="Material",this.fog=!0,this.blending=1,this.side=0,this.vertexColors=!1,this.opacity=1,this.format=E,this.transparent=!1,this.blendSrc=204,this.blendDst=205,this.blendEquation=n,this.blendSrcAlpha=null,this.blendDstAlpha=null,this.blendEquationAlpha=null,this.depthFunc=3,this.depthTest=!0,this.depthWrite=!0,this.stencilWriteMask=255,this.stencilFunc=519,this.stencilRef=0,this.stencilFuncMask=255,this.stencilFail=tt,this.stencilZFail=tt,this.stencilZPass=tt,this.stencilWrite=!1,this.clippingPlanes=null,this.clipIntersection=!1,this.clipShadows=!1,this.shadowSide=null,this.colorWrite=!0,this.precision=null,this.polygonOffset=!1,this.polygonOffsetFactor=0,this.polygonOffsetUnits=0,this.dithering=!1,this.alphaToCoverage=!1,this.premultipliedAlpha=!1,this.visible=!0,this.toneMapped=!0,this.userData={},this.version=0,this._alphaTest=0}get alphaTest(){return this._alphaTest}set alphaTest(t){this._alphaTest>0!=t>0&&this.version++,this._alphaTest=t}onBuild(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(t){if(void 0!==t)for(const e in t){const n=t[e];if(void 0===n){console.warn("THREE.Material: '"+e+"' parameter is undefined.");continue}if("shading"===e){console.warn("THREE."+this.type+": .shading has been removed. Use the boolean .flatShading instead."),this.flatShading=1===n;continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(n):i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[e]=n:console.warn("THREE."+this.type+": '"+e+"' is not a property of this material.")}}toJSON(t){const e=void 0===t||"string"==typeof t;e&&(t={textures:{},images:{}});const n={metadata:{version:4.5,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const n in t){const i=t[n];delete i.metadata,e.push(i)}return e}if(n.uuid=this.uuid,n.type=this.type,""!==this.name&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),void 0!==this.roughness&&(n.roughness=this.roughness),void 0!==this.metalness&&(n.metalness=this.metalness),this.sheenTint&&this.sheenTint.isColor&&(n.sheenTint=this.sheenTint.getHex()),void 0!==this.sheenRoughness&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity&&1!==this.emissiveIntensity&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(n.specularIntensity=this.specularIntensity),this.specularTint&&this.specularTint.isColor&&(n.specularTint=this.specularTint.getHex()),void 0!==this.shininess&&(n.shininess=this.shininess),void 0!==this.clearcoat&&(n.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(t).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularTintMap&&this.specularTintMap.isTexture&&(n.specularTintMap=this.specularTintMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,void 0!==this.combine&&(n.combine=this.combine)),void 0!==this.envMapIntensity&&(n.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(n.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),void 0!==this.transmission&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(t).uuid),void 0!==this.thickness&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(t).uuid),void 0!==this.attenuationDistance&&(n.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationTint&&(n.attenuationTint=this.attenuationTint.getHex()),void 0!==this.size&&(n.size=this.size),null!==this.shadowSide&&(n.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(n.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(n.blending=this.blending),0!==this.side&&(n.side=this.side),this.vertexColors&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.format!==E&&(n.format=this.format),!0===this.transparent&&(n.transparent=this.transparent),n.depthFunc=this.depthFunc,n.depthTest=this.depthTest,n.depthWrite=this.depthWrite,n.colorWrite=this.colorWrite,n.stencilWrite=this.stencilWrite,n.stencilWriteMask=this.stencilWriteMask,n.stencilFunc=this.stencilFunc,n.stencilRef=this.stencilRef,n.stencilFuncMask=this.stencilFuncMask,n.stencilFail=this.stencilFail,n.stencilZFail=this.stencilZFail,n.stencilZPass=this.stencilZPass,this.rotation&&0!==this.rotation&&(n.rotation=this.rotation),!0===this.polygonOffset&&(n.polygonOffset=!0),0!==this.polygonOffsetFactor&&(n.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth&&1!==this.linewidth&&(n.linewidth=this.linewidth),void 0!==this.dashSize&&(n.dashSize=this.dashSize),void 0!==this.gapSize&&(n.gapSize=this.gapSize),void 0!==this.scale&&(n.scale=this.scale),!0===this.dithering&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),!0===this.alphaToCoverage&&(n.alphaToCoverage=this.alphaToCoverage),!0===this.premultipliedAlpha&&(n.premultipliedAlpha=this.premultipliedAlpha),!0===this.wireframe&&(n.wireframe=this.wireframe),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(n.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(n.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(n.flatShading=this.flatShading),!1===this.visible&&(n.visible=!1),!1===this.toneMapped&&(n.toneMapped=!1),"{}"!==JSON.stringify(this.userData)&&(n.userData=this.userData),e){const e=i(t.textures),r=i(t.images);e.length>0&&(n.textures=e),r.length>0&&(n.images=r)}return n}clone(){return(new this.constructor).copy(this)}copy(t){this.name=t.name,this.fog=t.fog,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.format=t.format,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let n=null;if(null!==e){const t=e.length;n=new Array(t);for(let i=0;i!==t;++i)n[i]=e[i].clone()}return this.clippingPlanes=n,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(t){!0===t&&this.version++}}We.prototype.isMaterial=!0;const je={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},qe={h:0,s:0,l:0},Xe={h:0,s:0,l:0};function Ye(t,e,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?t+6*(e-t)*n:n<.5?e:n<2/3?t+6*(e-t)*(2/3-n):t}function Je(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function Ze(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}class Qe{constructor(t,e,n){return void 0===e&&void 0===n?this.set(t):this.setRGB(t,e,n)}set(t){return t&&t.isColor?this.copy(t):"number"==typeof t?this.setHex(t):"string"==typeof t&&this.setStyle(t),this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,this}setRGB(t,e,n){return this.r=t,this.g=e,this.b=n,this}setHSL(t,e,n){if(t=ut(t,1),e=ht(e,0,1),n=ht(n,0,1),0===e)this.r=this.g=this.b=n;else{const i=n<=.5?n*(1+e):n+e-n*e,r=2*n-i;this.r=Ye(r,i,t+1/3),this.g=Ye(r,i,t),this.b=Ye(r,i,t-1/3)}return this}setStyle(t){function e(e){void 0!==e&&parseFloat(e)<1&&console.warn("THREE.Color: Alpha component of "+t+" will be ignored.")}let n;if(n=/^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec(t)){let t;const i=n[1],r=n[2];switch(i){case"rgb":case"rgba":if(t=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(r))return this.r=Math.min(255,parseInt(t[1],10))/255,this.g=Math.min(255,parseInt(t[2],10))/255,this.b=Math.min(255,parseInt(t[3],10))/255,e(t[4]),this;if(t=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(r))return this.r=Math.min(100,parseInt(t[1],10))/100,this.g=Math.min(100,parseInt(t[2],10))/100,this.b=Math.min(100,parseInt(t[3],10))/100,e(t[4]),this;break;case"hsl":case"hsla":if(t=/^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(r)){const n=parseFloat(t[1])/360,i=parseInt(t[2],10)/100,r=parseInt(t[3],10)/100;return e(t[4]),this.setHSL(n,i,r)}}}else if(n=/^\#([A-Fa-f\d]+)$/.exec(t)){const t=n[1],e=t.length;if(3===e)return this.r=parseInt(t.charAt(0)+t.charAt(0),16)/255,this.g=parseInt(t.charAt(1)+t.charAt(1),16)/255,this.b=parseInt(t.charAt(2)+t.charAt(2),16)/255,this;if(6===e)return this.r=parseInt(t.charAt(0)+t.charAt(1),16)/255,this.g=parseInt(t.charAt(2)+t.charAt(3),16)/255,this.b=parseInt(t.charAt(4)+t.charAt(5),16)/255,this}return t&&t.length>0?this.setColorName(t):this}setColorName(t){const e=je[t.toLowerCase()];return void 0!==e?this.setHex(e):console.warn("THREE.Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copyGammaToLinear(t,e=2){return this.r=Math.pow(t.r,e),this.g=Math.pow(t.g,e),this.b=Math.pow(t.b,e),this}copyLinearToGamma(t,e=2){const n=e>0?1/e:1;return this.r=Math.pow(t.r,n),this.g=Math.pow(t.g,n),this.b=Math.pow(t.b,n),this}convertGammaToLinear(t){return this.copyGammaToLinear(this,t),this}convertLinearToGamma(t){return this.copyLinearToGamma(this,t),this}copySRGBToLinear(t){return this.r=Je(t.r),this.g=Je(t.g),this.b=Je(t.b),this}copyLinearToSRGB(t){return this.r=Ze(t.r),this.g=Ze(t.g),this.b=Ze(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(){return 255*this.r<<16^255*this.g<<8^255*this.b<<0}getHexString(){return("000000"+this.getHex().toString(16)).slice(-6)}getHSL(t){const e=this.r,n=this.g,i=this.b,r=Math.max(e,n,i),s=Math.min(e,n,i);let a,o;const l=(s+r)/2;if(s===r)a=0,o=0;else{const t=r-s;switch(o=l<=.5?t/(r+s):t/(2-r-s),r){case e:a=(n-i)/t+(ne&&(e=t[n]);return e}const mn={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function fn(t,e){return new mn[t](e)}let gn=0;const vn=new ae,yn=new Pe,xn=new Rt,_n=new It,bn=new It,Mn=new Rt;class wn extends rt{constructor(){super(),Object.defineProperty(this,"id",{value:gn++}),this.uuid=ct(),this.name="",this.type="BufferGeometry",this.index=null,this.attributes={},this.morphAttributes={},this.morphTargetsRelative=!1,this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.drawRange={start:0,count:1/0},this.userData={}}getIndex(){return this.index}setIndex(t){return Array.isArray(t)?this.index=new(pn(t)>65535?cn:on)(t,1):this.index=t,this}getAttribute(t){return this.attributes[t]}setAttribute(t,e){return this.attributes[t]=e,this}deleteAttribute(t){return delete this.attributes[t],this}hasAttribute(t){return void 0!==this.attributes[t]}addGroup(t,e,n=0){this.groups.push({start:t,count:e,materialIndex:n})}clearGroups(){this.groups=[]}setDrawRange(t,e){this.drawRange.start=t,this.drawRange.count=e}applyMatrix4(t){const e=this.attributes.position;void 0!==e&&(e.applyMatrix4(t),e.needsUpdate=!0);const n=this.attributes.normal;if(void 0!==n){const e=(new yt).getNormalMatrix(t);n.applyNormalMatrix(e),n.needsUpdate=!0}const i=this.attributes.tangent;return void 0!==i&&(i.transformDirection(t),i.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this}applyQuaternion(t){return vn.makeRotationFromQuaternion(t),this.applyMatrix4(vn),this}rotateX(t){return vn.makeRotationX(t),this.applyMatrix4(vn),this}rotateY(t){return vn.makeRotationY(t),this.applyMatrix4(vn),this}rotateZ(t){return vn.makeRotationZ(t),this.applyMatrix4(vn),this}translate(t,e,n){return vn.makeTranslation(t,e,n),this.applyMatrix4(vn),this}scale(t,e,n){return vn.makeScale(t,e,n),this.applyMatrix4(vn),this}lookAt(t){return yn.lookAt(t),yn.updateMatrix(),this.applyMatrix4(yn.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(xn).negate(),this.translate(xn.x,xn.y,xn.z),this}setFromPoints(t){const e=[];for(let n=0,i=t.length;n0&&(t.userData=this.userData),void 0!==this.parameters){const e=this.parameters;for(const n in e)void 0!==e[n]&&(t[n]=e[n]);return t}t.data={attributes:{}};const e=this.index;null!==e&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const n=this.attributes;for(const e in n){const i=n[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const n=this.morphAttributes[e],s=[];for(let e=0,i=n.length;e0&&(i[e]=s,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const s=this.groups;s.length>0&&(t.data.groups=JSON.parse(JSON.stringify(s)));const a=this.boundingSphere;return null!==a&&(t.data.boundingSphere={center:a.center.toArray(),radius:a.radius}),t}clone(){return(new wn).copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const n=t.index;null!==n&&this.setIndex(n.clone(e));const i=t.attributes;for(const t in i){const n=i[t];this.setAttribute(t,n.clone(e))}const r=t.morphAttributes;for(const t in r){const n=[],i=r[t];for(let t=0,r=i.length;t0){const t=e[n[0]];if(void 0!==t){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,n=t.length;e0&&console.error("THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.")}}raycast(t,e){const n=this.geometry,i=this.material,r=this.matrixWorld;if(void 0===i)return;if(null===n.boundingSphere&&n.computeBoundingSphere(),En.copy(n.boundingSphere),En.applyMatrix4(r),!1===t.ray.intersectsSphere(En))return;if(Sn.copy(r).invert(),Tn.copy(t.ray).applyMatrix4(Sn),null!==n.boundingBox&&!1===Tn.intersectsBox(n.boundingBox))return;let s;if(n.isBufferGeometry){const r=n.index,a=n.attributes.position,o=n.morphAttributes.position,l=n.morphTargetsRelative,c=n.attributes.uv,h=n.attributes.uv2,u=n.groups,d=n.drawRange;if(null!==r)if(Array.isArray(i))for(let n=0,p=u.length;nn.far?null:{distance:c,point:Hn.clone(),object:t}}(t,e,n,i,An,Ln,Rn,Un);if(p){o&&(Bn.fromBufferAttribute(o,c),Fn.fromBufferAttribute(o,h),On.fromBufferAttribute(o,u),p.uv=ke.getUV(Un,An,Ln,Rn,Bn,Fn,On,new vt)),l&&(Bn.fromBufferAttribute(l,c),Fn.fromBufferAttribute(l,h),On.fromBufferAttribute(l,u),p.uv2=ke.getUV(Un,An,Ln,Rn,Bn,Fn,On,new vt));const t={a:c,b:h,c:u,normal:new Rt,materialIndex:0};ke.getNormal(An,Ln,Rn,t.normal),p.face=t}return p}Gn.prototype.isMesh=!0;class Vn extends wn{constructor(t=1,e=1,n=1,i=1,r=1,s=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:n,widthSegments:i,heightSegments:r,depthSegments:s};const a=this;i=Math.floor(i),r=Math.floor(r),s=Math.floor(s);const o=[],l=[],c=[],h=[];let u=0,d=0;function p(t,e,n,i,r,s,p,m,f,g,v){const y=s/f,x=p/g,_=s/2,b=p/2,M=m/2,w=f+1,S=g+1;let T=0,E=0;const A=new Rt;for(let s=0;s0?1:-1,c.push(A.x,A.y,A.z),h.push(o/f),h.push(1-s/g),T+=1}}for(let t=0;t0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader;const n={};for(const t in this.extensions)!0===this.extensions[t]&&(n[t]=!0);return Object.keys(n).length>0&&(e.extensions=n),e}}Xn.prototype.isShaderMaterial=!0;class Yn extends Pe{constructor(){super(),this.type="Camera",this.matrixWorldInverse=new ae,this.projectionMatrix=new ae,this.projectionMatrixInverse=new ae}copy(t,e){return super.copy(t,e),this.matrixWorldInverse.copy(t.matrixWorldInverse),this.projectionMatrix.copy(t.projectionMatrix),this.projectionMatrixInverse.copy(t.projectionMatrixInverse),this}getWorldDirection(t){this.updateWorldMatrix(!0,!1);const e=this.matrixWorld.elements;return t.set(-e[8],-e[9],-e[10]).normalize()}updateMatrixWorld(t){super.updateMatrixWorld(t),this.matrixWorldInverse.copy(this.matrixWorld).invert()}updateWorldMatrix(t,e){super.updateWorldMatrix(t,e),this.matrixWorldInverse.copy(this.matrixWorld).invert()}clone(){return(new this.constructor).copy(this)}}Yn.prototype.isCamera=!0;class Jn extends Yn{constructor(t=50,e=1,n=.1,i=2e3){super(),this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=e,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.fov=t.fov,this.zoom=t.zoom,this.near=t.near,this.far=t.far,this.focus=t.focus,this.aspect=t.aspect,this.view=null===t.view?null:Object.assign({},t.view),this.filmGauge=t.filmGauge,this.filmOffset=t.filmOffset,this}setFocalLength(t){const e=.5*this.getFilmHeight()/t;this.fov=2*lt*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(.5*ot*this.fov);return.5*this.getFilmHeight()/t}getEffectiveFOV(){return 2*lt*Math.atan(Math.tan(.5*ot*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}setViewOffset(t,e,n,i,r,s){this.aspect=t/e,null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=this.near;let e=t*Math.tan(.5*ot*this.fov)/this.zoom,n=2*e,i=this.aspect*n,r=-.5*i;const s=this.view;if(null!==this.view&&this.view.enabled){const t=s.fullWidth,a=s.fullHeight;r+=s.offsetX*i/t,e-=s.offsetY*n/a,i*=s.width/t,n*=s.height/a}const a=this.filmOffset;0!==a&&(r+=t*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-n,t,this.far),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.fov=this.fov,e.object.zoom=this.zoom,e.object.near=this.near,e.object.far=this.far,e.object.focus=this.focus,e.object.aspect=this.aspect,null!==this.view&&(e.object.view=Object.assign({},this.view)),e.object.filmGauge=this.filmGauge,e.object.filmOffset=this.filmOffset,e}}Jn.prototype.isPerspectiveCamera=!0;const Zn=90;class Qn extends Pe{constructor(t,e,n){if(super(),this.type="CubeCamera",!0!==n.isWebGLCubeRenderTarget)return void console.error("THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.");this.renderTarget=n;const i=new Jn(Zn,1,t,e);i.layers=this.layers,i.up.set(0,-1,0),i.lookAt(new Rt(1,0,0)),this.add(i);const r=new Jn(Zn,1,t,e);r.layers=this.layers,r.up.set(0,-1,0),r.lookAt(new Rt(-1,0,0)),this.add(r);const s=new Jn(Zn,1,t,e);s.layers=this.layers,s.up.set(0,0,1),s.lookAt(new Rt(0,1,0)),this.add(s);const a=new Jn(Zn,1,t,e);a.layers=this.layers,a.up.set(0,0,-1),a.lookAt(new Rt(0,-1,0)),this.add(a);const o=new Jn(Zn,1,t,e);o.layers=this.layers,o.up.set(0,-1,0),o.lookAt(new Rt(0,0,1)),this.add(o);const l=new Jn(Zn,1,t,e);l.layers=this.layers,l.up.set(0,-1,0),l.lookAt(new Rt(0,0,-1)),this.add(l)}update(t,e){null===this.parent&&this.updateMatrixWorld();const n=this.renderTarget,[i,r,s,a,o,l]=this.children,c=t.xr.enabled,h=t.getRenderTarget();t.xr.enabled=!1;const u=n.texture.generateMipmaps;n.texture.generateMipmaps=!1,t.setRenderTarget(n,0),t.render(e,i),t.setRenderTarget(n,1),t.render(e,r),t.setRenderTarget(n,2),t.render(e,s),t.setRenderTarget(n,3),t.render(e,a),t.setRenderTarget(n,4),t.render(e,o),n.texture.generateMipmaps=u,t.setRenderTarget(n,5),t.render(e,l),t.setRenderTarget(h),t.xr.enabled=c}}class Kn extends Mt{constructor(t,e,n,i,s,a,o,l,c,h){super(t=void 0!==t?t:[],e=void 0!==e?e:r,n,i,s,a,o=void 0!==o?o:T,l,c,h),this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}Kn.prototype.isCubeTexture=!0;class $n extends Tt{constructor(t,e,n){Number.isInteger(e)&&(console.warn("THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )"),e=n),super(t,t,e),e=e||{},this.texture=new Kn(void 0,e.mapping,e.wrapS,e.wrapT,e.magFilter,e.minFilter,e.format,e.type,e.anisotropy,e.encoding),this.texture.isRenderTargetTexture=!0,this.texture.generateMipmaps=void 0!==e.generateMipmaps&&e.generateMipmaps,this.texture.minFilter=void 0!==e.minFilter?e.minFilter:g,this.texture._needsFlipEnvMap=!1}fromEquirectangularTexture(t,e){this.texture.type=e.type,this.texture.format=E,this.texture.encoding=e.encoding,this.texture.generateMipmaps=e.generateMipmaps,this.texture.minFilter=e.minFilter,this.texture.magFilter=e.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:"\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\tvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\n\t\t\t\t\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvWorldDirection = transformDirection( position, modelMatrix );\n\n\t\t\t\t\t#include \n\t\t\t\t\t#include \n\n\t\t\t\t}\n\t\t\t",fragmentShader:"\n\n\t\t\t\tuniform sampler2D tEquirect;\n\n\t\t\t\tvarying vec3 vWorldDirection;\n\n\t\t\t\t#include \n\n\t\t\t\tvoid main() {\n\n\t\t\t\t\tvec3 direction = normalize( vWorldDirection );\n\n\t\t\t\t\tvec2 sampleUV = equirectUv( direction );\n\n\t\t\t\t\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\n\t\t\t\t}\n\t\t\t"},i=new Vn(5,5,5),r=new Xn({name:"CubemapFromEquirect",uniforms:Wn(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:1,blending:0});r.uniforms.tEquirect.value=e;const s=new Gn(i,r),a=e.minFilter;e.minFilter===y&&(e.minFilter=g);return new Qn(1,10,this).update(t,s),e.minFilter=a,s.geometry.dispose(),s.material.dispose(),this}clear(t,e,n,i){const r=t.getRenderTarget();for(let r=0;r<6;r++)t.setRenderTarget(this,r),t.clear(e,n,i);t.setRenderTarget(r)}}$n.prototype.isWebGLCubeRenderTarget=!0;const ti=new Rt,ei=new Rt,ni=new yt;class ii{constructor(t=new Rt(1,0,0),e=0){this.normal=t,this.constant=e}set(t,e){return this.normal.copy(t),this.constant=e,this}setComponents(t,e,n,i){return this.normal.set(t,e,n),this.constant=i,this}setFromNormalAndCoplanarPoint(t,e){return this.normal.copy(t),this.constant=-e.dot(this.normal),this}setFromCoplanarPoints(t,e,n){const i=ti.subVectors(n,e).cross(ei.subVectors(t,e)).normalize();return this.setFromNormalAndCoplanarPoint(i,t),this}copy(t){return this.normal.copy(t.normal),this.constant=t.constant,this}normalize(){const t=1/this.normal.length();return this.normal.multiplyScalar(t),this.constant*=t,this}negate(){return this.constant*=-1,this.normal.negate(),this}distanceToPoint(t){return this.normal.dot(t)+this.constant}distanceToSphere(t){return this.distanceToPoint(t.center)-t.radius}projectPoint(t,e){return e.copy(this.normal).multiplyScalar(-this.distanceToPoint(t)).add(t)}intersectLine(t,e){const n=t.delta(ti),i=this.normal.dot(n);if(0===i)return 0===this.distanceToPoint(t.start)?e.copy(t.start):null;const r=-(t.start.dot(this.normal)+this.constant)/i;return r<0||r>1?null:e.copy(n).multiplyScalar(r).add(t.start)}intersectsLine(t){const e=this.distanceToPoint(t.start),n=this.distanceToPoint(t.end);return e<0&&n>0||n<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const n=e||ni.getNormalMatrix(t),i=this.coplanarPoint(ti).applyMatrix4(t),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return(new this.constructor).copy(this)}}ii.prototype.isPlane=!0;const ri=new Qt,si=new Rt;class ai{constructor(t=new ii,e=new ii,n=new ii,i=new ii,r=new ii,s=new ii){this.planes=[t,e,n,i,r,s]}set(t,e,n,i,r,s){const a=this.planes;return a[0].copy(t),a[1].copy(e),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(s),this}copy(t){const e=this.planes;for(let n=0;n<6;n++)e[n].copy(t.planes[n]);return this}setFromProjectionMatrix(t){const e=this.planes,n=t.elements,i=n[0],r=n[1],s=n[2],a=n[3],o=n[4],l=n[5],c=n[6],h=n[7],u=n[8],d=n[9],p=n[10],m=n[11],f=n[12],g=n[13],v=n[14],y=n[15];return e[0].setComponents(a-i,h-o,m-u,y-f).normalize(),e[1].setComponents(a+i,h+o,m+u,y+f).normalize(),e[2].setComponents(a+r,h+l,m+d,y+g).normalize(),e[3].setComponents(a-r,h-l,m-d,y-g).normalize(),e[4].setComponents(a-s,h-c,m-p,y-v).normalize(),e[5].setComponents(a+s,h+c,m+p,y+v).normalize(),this}intersectsObject(t){const e=t.geometry;return null===e.boundingSphere&&e.computeBoundingSphere(),ri.copy(e.boundingSphere).applyMatrix4(t.matrixWorld),this.intersectsSphere(ri)}intersectsSprite(t){return ri.center.set(0,0,0),ri.radius=.7071067811865476,ri.applyMatrix4(t.matrixWorld),this.intersectsSphere(ri)}intersectsSphere(t){const e=this.planes,n=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(n)0?t.max.x:t.min.x,si.y=i.normal.y>0?t.max.y:t.min.y,si.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(si)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let n=0;n<6;n++)if(e[n].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function oi(){let t=null,e=!1,n=null,i=null;function r(e,s){n(e,s),i=t.requestAnimationFrame(r)}return{start:function(){!0!==e&&null!==n&&(i=t.requestAnimationFrame(r),e=!0)},stop:function(){t.cancelAnimationFrame(i),e=!1},setAnimationLoop:function(t){n=t},setContext:function(e){t=e}}}function li(t,e){const n=e.isWebGL2,i=new WeakMap;return{get:function(t){return t.isInterleavedBufferAttribute&&(t=t.data),i.get(t)},remove:function(e){e.isInterleavedBufferAttribute&&(e=e.data);const n=i.get(e);n&&(t.deleteBuffer(n.buffer),i.delete(e))},update:function(e,r){if(e.isGLBufferAttribute){const t=i.get(e);return void((!t||t.version 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotVH = saturate( dot( geometry.viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenTint, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenTint * ( D * V );\n}\n#endif",bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif",clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif",color_fragment:"#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif",color_vertex:"#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif",common:"#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_maxMipLevel 8.0\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_maxTileSize 256.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tfloat texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 1.0 );\n\t\tvec2 f = fract( uv );\n\t\tuv += 0.5 - f;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tif ( mipInt < cubeUV_maxMipLevel ) {\n\t\t\tuv.y += 2.0 * cubeUV_maxTileSize;\n\t\t}\n\t\tuv.y += filterInt * 2.0 * cubeUV_minTileSize;\n\t\tuv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize );\n\t\tuv *= texelSize;\n\t\tvec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x += texelSize;\n\t\tvec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.y += texelSize;\n\t\tvec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x -= texelSize;\n\t\tvec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tvec3 tm = mix( tl, tr, f.x );\n\t\tvec3 bm = mix( bl, br, f.x );\n\t\treturn mix( tm, bm, f.y );\n\t}\n\t#define r0 1.0\n\t#define v0 0.339\n\t#define m0 - 2.0\n\t#define r1 0.8\n\t#define v1 0.276\n\t#define m1 - 1.0\n\t#define r4 0.4\n\t#define v4 0.046\n\t#define m4 2.0\n\t#define r5 0.305\n\t#define v5 0.016\n\t#define m5 3.0\n\t#define r6 0.21\n\t#define v6 0.0038\n\t#define m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= r1 ) {\n\t\t\tmip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0;\n\t\t} else if ( roughness >= r4 ) {\n\t\t\tmip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1;\n\t\t} else if ( roughness >= r5 ) {\n\t\t\tmip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4;\n\t\t} else if ( roughness >= r6 ) {\n\t\t\tmip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), m0, cubeUV_maxMipLevel );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",encodings_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",encodings_pars_fragment:"\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = clamp( floor( D ) / 255.0, 0.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = cLogLuvM * value.rgb;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif",envmap_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) ||defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#if defined( USE_ENVMAP )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\n\tvec3 getIBLIrradiance( const in GeometricContext geometry ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec;\n\t\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\t\treflectVec = reflect( - viewDir, normal );\n\t\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\t#else\n\t\t\t\treflectVec = refract( - viewDir, normal, refractionRatio );\n\t\t\t#endif\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif",fog_vertex:"#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif",gradientmap_pars_fragment:"#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tlightMapIrradiance *= PI;\n\t#endif\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\nvIndirectFront += getAmbientLightIrradiance( ambientLightColor );\nvIndirectFront += getLightProbeIrradiance( lightProbe, geometry );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointLightInfo( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotLightInfo( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalLightInfo( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( - dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n\t#pragma unroll_loop_end\n#endif",lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif",lights_toon_fragment:"ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;",lights_toon_pars_fragment:"varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularTintFactor = specularTint;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARTINTMAP\n\t\t\tspecularTintFactor *= specularTintMapTexelToLinear( texture2D( specularTintMap, vUv ) ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularTintFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( ior - 1.0 ) / ( ior + 1.0 ) ) * specularTintFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenTint = sheenTint;\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenTint;\n\t\tfloat sheenRoughness;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\tvec3 FssEss = specularColor * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3(\t\t0, 1,\t\t0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenTint, material.sheenRoughness );\n\t#else\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}",lights_fragment_begin:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif",map_particle_pars_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\t\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\t\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif",normal_fragment_begin:"float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;",normal_fragment_maps:"#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif",normal_pars_fragment:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_pars_vertex:"#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif",normal_vertex:"#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif",clearcoat_normal_fragment_begin:"#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif",clearcoat_pars_fragment:"#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif",output_fragment:"#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t\tf.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t\tf.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif",shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}",skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform highp sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3(\t1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108,\t1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605,\t1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }",transmission_fragment:"#ifdef USE_TRANSMISSION\n\tfloat transmissionAlpha = 1.0;\n\tfloat transmissionFactor = transmission;\n\tfloat thicknessFactor = thickness;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\ttransmissionFactor *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tthicknessFactor *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, roughnessFactor, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, ior, thicknessFactor,\n\t\tattenuationTint, attenuationDistance );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, transmissionFactor );\n\ttransmissionAlpha = transmission.a;\n#endif",transmission_pars_fragment:"#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationTint;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( float roughness, float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( vec2 fragCoord, float roughness, float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( vec3 radiance, float transmissionDistance, vec3 attenuationColor, float attenuationDistance ) {\n\t\tif ( attenuationDistance == 0.0 ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 specularColor, float specularF90,\n\t\tvec3 position, mat4 modelMatrix, mat4 viewMatrix, mat4 projMatrix, float ior, float thickness,\n\t\tvec3 attenuationColor, float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif",uv_pars_fragment:"#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif",uv_vertex:"#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif",uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION )\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif",background_frag:"uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",cube_frag:"#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}",distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}",distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}",meshnormal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}",meshnormal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}",meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphong_vert:"#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularTint;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARTINTMAP\n\t\tuniform sampler2D specularTintMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenTint;\n\tuniform float sheenRoughness;\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - clearcoat * Fcc ) + clearcoatSpecular * clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}",meshtoon_frag:"#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshtoon_vert:"#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}",points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",points_vert:"uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}",shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}",shadow_vert:"#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}",sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"},ui={common:{diffuse:{value:new Qe(16777215)},opacity:{value:1},map:{value:null},uvTransform:{value:new yt},uv2Transform:{value:new yt},alphaMap:{value:null},alphaTest:{value:0}},specularmap:{specularMap:{value:null}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98},maxMipLevel:{value:0}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalScale:{value:new vt(1,1)}},displacementmap:{displacementMap:{value:null},displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Qe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null}},points:{diffuse:{value:new Qe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaTest:{value:0},uvTransform:{value:new yt}},sprite:{diffuse:{value:new Qe(16777215)},opacity:{value:1},center:{value:new vt(.5,.5)},rotation:{value:0},map:{value:null},alphaMap:{value:null},alphaTest:{value:0},uvTransform:{value:new yt}}},di={basic:{uniforms:jn([ui.common,ui.specularmap,ui.envmap,ui.aomap,ui.lightmap,ui.fog]),vertexShader:hi.meshbasic_vert,fragmentShader:hi.meshbasic_frag},lambert:{uniforms:jn([ui.common,ui.specularmap,ui.envmap,ui.aomap,ui.lightmap,ui.emissivemap,ui.fog,ui.lights,{emissive:{value:new Qe(0)}}]),vertexShader:hi.meshlambert_vert,fragmentShader:hi.meshlambert_frag},phong:{uniforms:jn([ui.common,ui.specularmap,ui.envmap,ui.aomap,ui.lightmap,ui.emissivemap,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.fog,ui.lights,{emissive:{value:new Qe(0)},specular:{value:new Qe(1118481)},shininess:{value:30}}]),vertexShader:hi.meshphong_vert,fragmentShader:hi.meshphong_frag},standard:{uniforms:jn([ui.common,ui.envmap,ui.aomap,ui.lightmap,ui.emissivemap,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.roughnessmap,ui.metalnessmap,ui.fog,ui.lights,{emissive:{value:new Qe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:hi.meshphysical_vert,fragmentShader:hi.meshphysical_frag},toon:{uniforms:jn([ui.common,ui.aomap,ui.lightmap,ui.emissivemap,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.gradientmap,ui.fog,ui.lights,{emissive:{value:new Qe(0)}}]),vertexShader:hi.meshtoon_vert,fragmentShader:hi.meshtoon_frag},matcap:{uniforms:jn([ui.common,ui.bumpmap,ui.normalmap,ui.displacementmap,ui.fog,{matcap:{value:null}}]),vertexShader:hi.meshmatcap_vert,fragmentShader:hi.meshmatcap_frag},points:{uniforms:jn([ui.points,ui.fog]),vertexShader:hi.points_vert,fragmentShader:hi.points_frag},dashed:{uniforms:jn([ui.common,ui.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:hi.linedashed_vert,fragmentShader:hi.linedashed_frag},depth:{uniforms:jn([ui.common,ui.displacementmap]),vertexShader:hi.depth_vert,fragmentShader:hi.depth_frag},normal:{uniforms:jn([ui.common,ui.bumpmap,ui.normalmap,ui.displacementmap,{opacity:{value:1}}]),vertexShader:hi.meshnormal_vert,fragmentShader:hi.meshnormal_frag},sprite:{uniforms:jn([ui.sprite,ui.fog]),vertexShader:hi.sprite_vert,fragmentShader:hi.sprite_frag},background:{uniforms:{uvTransform:{value:new yt},t2D:{value:null}},vertexShader:hi.background_vert,fragmentShader:hi.background_frag},cube:{uniforms:jn([ui.envmap,{opacity:{value:1}}]),vertexShader:hi.cube_vert,fragmentShader:hi.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:hi.equirect_vert,fragmentShader:hi.equirect_frag},distanceRGBA:{uniforms:jn([ui.common,ui.displacementmap,{referencePosition:{value:new Rt},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:hi.distanceRGBA_vert,fragmentShader:hi.distanceRGBA_frag},shadow:{uniforms:jn([ui.lights,ui.fog,{color:{value:new Qe(0)},opacity:{value:1}}]),vertexShader:hi.shadow_vert,fragmentShader:hi.shadow_frag}};function pi(t,e,n,i,r){const s=new Qe(0);let a,o,c=0,h=null,u=0,d=null;function p(t,e){n.buffers.color.setClear(t.r,t.g,t.b,e,r)}return{getClearColor:function(){return s},setClearColor:function(t,e=1){s.set(t),c=e,p(s,c)},getClearAlpha:function(){return c},setClearAlpha:function(t){c=t,p(s,c)},render:function(n,r){let m=!1,f=!0===r.isScene?r.background:null;f&&f.isTexture&&(f=e.get(f));const g=t.xr,v=g.getSession&&g.getSession();v&&"additive"===v.environmentBlendMode&&(f=null),null===f?p(s,c):f&&f.isColor&&(p(f,1),m=!0),(t.autoClear||m)&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),f&&(f.isCubeTexture||f.mapping===l)?(void 0===o&&(o=new Gn(new Vn(1,1,1),new Xn({name:"BackgroundCubeMaterial",uniforms:Wn(di.cube.uniforms),vertexShader:di.cube.vertexShader,fragmentShader:di.cube.fragmentShader,side:1,depthTest:!1,depthWrite:!1,fog:!1})),o.geometry.deleteAttribute("normal"),o.geometry.deleteAttribute("uv"),o.onBeforeRender=function(t,e,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(o.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),i.update(o)),o.material.uniforms.envMap.value=f,o.material.uniforms.flipEnvMap.value=f.isCubeTexture&&!1===f.isRenderTargetTexture?-1:1,h===f&&u===f.version&&d===t.toneMapping||(o.material.needsUpdate=!0,h=f,u=f.version,d=t.toneMapping),n.unshift(o,o.geometry,o.material,0,0,null)):f&&f.isTexture&&(void 0===a&&(a=new Gn(new ci(2,2),new Xn({name:"BackgroundMaterial",uniforms:Wn(di.background.uniforms),vertexShader:di.background.vertexShader,fragmentShader:di.background.fragmentShader,side:0,depthTest:!1,depthWrite:!1,fog:!1})),a.geometry.deleteAttribute("normal"),Object.defineProperty(a.material,"map",{get:function(){return this.uniforms.t2D.value}}),i.update(a)),a.material.uniforms.t2D.value=f,!0===f.matrixAutoUpdate&&f.updateMatrix(),a.material.uniforms.uvTransform.value.copy(f.matrix),h===f&&u===f.version&&d===t.toneMapping||(a.material.needsUpdate=!0,h=f,u=f.version,d=t.toneMapping),n.unshift(a,a.geometry,a.material,0,0,null))}}}function mi(t,e,n,i){const r=t.getParameter(34921),s=i.isWebGL2?null:e.get("OES_vertex_array_object"),a=i.isWebGL2||null!==s,o={},l=d(null);let c=l;function h(e){return i.isWebGL2?t.bindVertexArray(e):s.bindVertexArrayOES(e)}function u(e){return i.isWebGL2?t.deleteVertexArray(e):s.deleteVertexArrayOES(e)}function d(t){const e=[],n=[],i=[];for(let t=0;t=0){let s=l[e];if(void 0===s&&("instanceMatrix"===e&&r.instanceMatrix&&(s=r.instanceMatrix),"instanceColor"===e&&r.instanceColor&&(s=r.instanceColor)),void 0!==s){const e=s.normalized,a=s.itemSize,l=n.get(s);if(void 0===l)continue;const c=l.buffer,h=l.type,u=l.bytesPerElement;if(s.isInterleavedBufferAttribute){const n=s.data,l=n.stride,d=s.offset;if(n&&n.isInstancedInterleavedBuffer){for(let t=0;t0&&t.getShaderPrecisionFormat(35632,36338).precision>0)return"highp";e="mediump"}return"mediump"===e&&t.getShaderPrecisionFormat(35633,36337).precision>0&&t.getShaderPrecisionFormat(35632,36337).precision>0?"mediump":"lowp"}const s="undefined"!=typeof WebGL2RenderingContext&&t instanceof WebGL2RenderingContext||"undefined"!=typeof WebGL2ComputeRenderingContext&&t instanceof WebGL2ComputeRenderingContext;let a=void 0!==n.precision?n.precision:"highp";const o=r(a);o!==a&&(console.warn("THREE.WebGLRenderer:",a,"not supported, using",o,"instead."),a=o);const l=s||e.has("WEBGL_draw_buffers"),c=!0===n.logarithmicDepthBuffer,h=t.getParameter(34930),u=t.getParameter(35660),d=t.getParameter(3379),p=t.getParameter(34076),m=t.getParameter(34921),f=t.getParameter(36347),g=t.getParameter(36348),v=t.getParameter(36349),y=u>0,x=s||e.has("OES_texture_float");return{isWebGL2:s,drawBuffers:l,getMaxAnisotropy:function(){if(void 0!==i)return i;if(!0===e.has("EXT_texture_filter_anisotropic")){const n=e.get("EXT_texture_filter_anisotropic");i=t.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else i=0;return i},getMaxPrecision:r,precision:a,logarithmicDepthBuffer:c,maxTextures:h,maxVertexTextures:u,maxTextureSize:d,maxCubemapSize:p,maxAttributes:m,maxVertexUniforms:f,maxVaryings:g,maxFragmentUniforms:v,vertexTextures:y,floatFragmentTextures:x,floatVertexTextures:y&&x,maxSamples:s?t.getParameter(36183):0}}function vi(t){const e=this;let n=null,i=0,r=!1,s=!1;const a=new ii,o=new yt,l={value:null,needsUpdate:!1};function c(){l.value!==n&&(l.value=n,l.needsUpdate=i>0),e.numPlanes=i,e.numIntersection=0}function h(t,n,i,r){const s=null!==t?t.length:0;let c=null;if(0!==s){if(c=l.value,!0!==r||null===c){const e=i+4*s,r=n.matrixWorldInverse;o.getNormalMatrix(r),(null===c||c.length0){const a=t.getRenderTarget(),o=new $n(s.height/2);return o.fromEquirectangularTexture(t,r),e.set(r,o),t.setRenderTarget(a),r.addEventListener("dispose",i),n(o.texture,r.mapping)}return null}}}return r},dispose:function(){e=new WeakMap}}}di.physical={uniforms:jn([di.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatNormalScale:{value:new vt(1,1)},clearcoatNormalMap:{value:null},sheenTint:{value:new Qe(0)},sheenRoughness:{value:0},transmission:{value:0},transmissionMap:{value:null},transmissionSamplerSize:{value:new vt},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},attenuationDistance:{value:0},attenuationTint:{value:new Qe(0)},specularIntensity:{value:0},specularIntensityMap:{value:null},specularTint:{value:new Qe(1,1,1)},specularTintMap:{value:null}}]),vertexShader:hi.meshphysical_vert,fragmentShader:hi.meshphysical_frag};class xi extends Yn{constructor(t=-1,e=1,n=1,i=-1,r=.1,s=2e3){super(),this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=t,this.right=e,this.top=n,this.bottom=i,this.near=r,this.far=s,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.left=t.left,this.right=t.right,this.top=t.top,this.bottom=t.bottom,this.near=t.near,this.far=t.far,this.zoom=t.zoom,this.view=null===t.view?null:Object.assign({},t.view),this}setViewOffset(t,e,n,i,r,s){null===this.view&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=s,this.updateProjectionMatrix()}clearViewOffset(){null!==this.view&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=(this.right-this.left)/(2*this.zoom),e=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-t,s=n+t,a=i+e,o=i-e;if(null!==this.view&&this.view.enabled){const t=(this.right-this.left)/this.view.fullWidth/this.zoom,e=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=t*this.view.offsetX,s=r+t*this.view.width,a-=e*this.view.offsetY,o=a-e*this.view.height}this.projectionMatrix.makeOrthographic(r,s,a,o,this.near,this.far),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.zoom=this.zoom,e.object.left=this.left,e.object.right=this.right,e.object.top=this.top,e.object.bottom=this.bottom,e.object.near=this.near,e.object.far=this.far,null!==this.view&&(e.object.view=Object.assign({},this.view)),e}}xi.prototype.isOrthographicCamera=!0;class _i extends Xn{constructor(t){super(t),this.type="RawShaderMaterial"}}_i.prototype.isRawShaderMaterial=!0;const bi=Math.pow(2,8),Mi=[.125,.215,.35,.446,.526,.582],wi=5+Mi.length,Si=20,Ti={[X]:0,[Y]:1,[Z]:2,[Q]:3,[K]:4,[$]:5,[J]:6},Ei=new xi,{_lodPlanes:Ai,_sizeLods:Li,_sigmas:Ri}=Fi(),Ci=new Qe;let Pi=null;const Ii=(1+Math.sqrt(5))/2,Di=1/Ii,Ni=[new Rt(1,1,1),new Rt(-1,1,1),new Rt(1,1,-1),new Rt(-1,1,-1),new Rt(0,Ii,Di),new Rt(0,Ii,-Di),new Rt(Di,0,Ii),new Rt(-Di,0,Ii),new Rt(Ii,Di,0),new Rt(-Ii,Di,0)];class zi{constructor(t){this._renderer=t,this._pingPongRenderTarget=null,this._blurMaterial=function(t){const e=new Float32Array(t),n=new Rt(0,1,0);return new _i({name:"SphericalGaussianBlur",defines:{n:t},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:e},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:n},inputEncoding:{value:Ti[3e3]},outputEncoding:{value:Ti[3e3]}},vertexShader:ki(),fragmentShader:`\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform int samples;\n\t\t\tuniform float weights[ n ];\n\t\t\tuniform bool latitudinal;\n\t\t\tuniform float dTheta;\n\t\t\tuniform float mipInt;\n\t\t\tuniform vec3 poleAxis;\n\n\t\t\t${Vi()}\n\n\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\t\t\t#include \n\n\t\t\tvec3 getSample( float theta, vec3 axis ) {\n\n\t\t\t\tfloat cosTheta = cos( theta );\n\t\t\t\t// Rodrigues' axis-angle rotation\n\t\t\t\tvec3 sampleDirection = vOutputDirection * cosTheta\n\t\t\t\t\t+ cross( axis, vOutputDirection ) * sin( theta )\n\t\t\t\t\t+ axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );\n\n\t\t\t\treturn bilinearCubeUV( envMap, sampleDirection, mipInt );\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tvec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );\n\n\t\t\t\tif ( all( equal( axis, vec3( 0.0 ) ) ) ) {\n\n\t\t\t\t\taxis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );\n\n\t\t\t\t}\n\n\t\t\t\taxis = normalize( axis );\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );\n\n\t\t\t\tfor ( int i = 1; i < n; i++ ) {\n\n\t\t\t\t\tif ( i >= samples ) {\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfloat theta = dTheta * float( i );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );\n\t\t\t\t\tgl_FragColor.rgb += weights[ i ] * getSample( theta, axis );\n\n\t\t\t\t}\n\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t`,blending:0,depthTest:!1,depthWrite:!1})}(Si),this._equirectShader=null,this._cubemapShader=null,this._compileMaterial(this._blurMaterial)}fromScene(t,e=0,n=.1,i=100){Pi=this._renderer.getRenderTarget();const r=this._allocateTargets();return this._sceneToCubeUV(t,n,i,r),e>0&&this._blur(r,0,0,e),this._applyPMREM(r),this._cleanup(r),r}fromEquirectangular(t){return this._fromTexture(t)}fromCubemap(t){return this._fromTexture(t)}compileCubemapShader(){null===this._cubemapShader&&(this._cubemapShader=Gi(),this._compileMaterial(this._cubemapShader))}compileEquirectangularShader(){null===this._equirectShader&&(this._equirectShader=Hi(),this._compileMaterial(this._equirectShader))}dispose(){this._blurMaterial.dispose(),null!==this._cubemapShader&&this._cubemapShader.dispose(),null!==this._equirectShader&&this._equirectShader.dispose();for(let t=0;t2?bi:0,bi,bi),o.setRenderTarget(i),p&&o.render(d,r),o.render(t,r)}d.geometry.dispose(),d.material.dispose(),o.toneMapping=h,o.outputEncoding=c,o.autoClear=l,t.background=m}_textureToCubeUV(t,e){const n=this._renderer;t.isCubeTexture?null==this._cubemapShader&&(this._cubemapShader=Gi()):null==this._equirectShader&&(this._equirectShader=Hi());const i=t.isCubeTexture?this._cubemapShader:this._equirectShader,r=new Gn(Ai[0],i),s=i.uniforms;s.envMap.value=t,t.isCubeTexture||s.texelSize.value.set(1/t.image.width,1/t.image.height),s.inputEncoding.value=Ti[t.encoding],s.outputEncoding.value=Ti[e.texture.encoding],Ui(e,0,0,3*bi,2*bi),n.setRenderTarget(e),n.render(r,Ei)}_applyPMREM(t){const e=this._renderer,n=e.autoClear;e.autoClear=!1;for(let e=1;eSi&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to 20`);const f=[];let g=0;for(let t=0;t4?i-8+4:0),3*v,2*v),o.setRenderTarget(e),o.render(c,Ei)}}function Bi(t){return void 0!==t&&t.type===x&&(t.encoding===X||t.encoding===Y||t.encoding===J)}function Fi(){const t=[],e=[],n=[];let i=8;for(let r=0;r4?a=Mi[r-8+4-1]:0==r&&(a=0),n.push(a);const o=1/(s-1),l=-o/2,c=1+o/2,h=[l,l,c,l,c,c,l,l,c,c,l,c],u=6,d=6,p=3,m=2,f=1,g=new Float32Array(p*d*u),v=new Float32Array(m*d*u),y=new Float32Array(f*d*u);for(let t=0;t2?0:-1,i=[e,n,0,e+2/3,n,0,e+2/3,n+1,0,e,n,0,e+2/3,n+1,0,e,n+1,0];g.set(i,p*d*t),v.set(h,m*d*t);const r=[t,t,t,t,t,t];y.set(r,f*d*t)}const x=new wn;x.setAttribute("position",new en(g,p)),x.setAttribute("uv",new en(v,m)),x.setAttribute("faceIndex",new en(y,f)),t.push(x),i>4&&i--}return{_lodPlanes:t,_sizeLods:e,_sigmas:n}}function Oi(t){const e=new Tt(3*bi,3*bi,t);return e.texture.mapping=l,e.texture.name="PMREM.cubeUv",e.scissorTest=!0,e}function Ui(t,e,n,i,r){t.viewport.set(e,n,i,r),t.scissor.set(e,n,i,r)}function Hi(){const t=new vt(1,1);return new _i({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null},texelSize:{value:t},inputEncoding:{value:Ti[3e3]},outputEncoding:{value:Ti[3e3]}},vertexShader:ki(),fragmentShader:`\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform sampler2D envMap;\n\t\t\tuniform vec2 texelSize;\n\n\t\t\t${Vi()}\n\n\t\t\t#include \n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\n\t\t\t\tvec3 outputDirection = normalize( vOutputDirection );\n\t\t\t\tvec2 uv = equirectUv( outputDirection );\n\n\t\t\t\tvec2 f = fract( uv / texelSize - 0.5 );\n\t\t\t\tuv -= f * texelSize;\n\t\t\t\tvec3 tl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.x += texelSize.x;\n\t\t\t\tvec3 tr = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.y += texelSize.y;\n\t\t\t\tvec3 br = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\t\t\t\tuv.x -= texelSize.x;\n\t\t\t\tvec3 bl = envMapTexelToLinear( texture2D ( envMap, uv ) ).rgb;\n\n\t\t\t\tvec3 tm = mix( tl, tr, f.x );\n\t\t\t\tvec3 bm = mix( bl, br, f.x );\n\t\t\t\tgl_FragColor.rgb = mix( tm, bm, f.y );\n\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t`,blending:0,depthTest:!1,depthWrite:!1})}function Gi(){return new _i({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},inputEncoding:{value:Ti[3e3]},outputEncoding:{value:Ti[3e3]}},vertexShader:ki(),fragmentShader:`\n\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec3 vOutputDirection;\n\n\t\t\tuniform samplerCube envMap;\n\n\t\t\t${Vi()}\n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t\t\t\tgl_FragColor.rgb = envMapTexelToLinear( textureCube( envMap, vec3( - vOutputDirection.x, vOutputDirection.yz ) ) ).rgb;\n\t\t\t\tgl_FragColor = linearToOutputTexel( gl_FragColor );\n\n\t\t\t}\n\t\t`,blending:0,depthTest:!1,depthWrite:!1})}function ki(){return"\n\n\t\tprecision mediump float;\n\t\tprecision mediump int;\n\n\t\tattribute vec3 position;\n\t\tattribute vec2 uv;\n\t\tattribute float faceIndex;\n\n\t\tvarying vec3 vOutputDirection;\n\n\t\t// RH coordinate system; PMREM face-indexing convention\n\t\tvec3 getDirection( vec2 uv, float face ) {\n\n\t\t\tuv = 2.0 * uv - 1.0;\n\n\t\t\tvec3 direction = vec3( uv, 1.0 );\n\n\t\t\tif ( face == 0.0 ) {\n\n\t\t\t\tdirection = direction.zyx; // ( 1, v, u ) pos x\n\n\t\t\t} else if ( face == 1.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xz *= -1.0; // ( -u, 1, -v ) pos y\n\n\t\t\t} else if ( face == 2.0 ) {\n\n\t\t\t\tdirection.x *= -1.0; // ( -u, v, 1 ) pos z\n\n\t\t\t} else if ( face == 3.0 ) {\n\n\t\t\t\tdirection = direction.zyx;\n\t\t\t\tdirection.xz *= -1.0; // ( -1, v, -u ) neg x\n\n\t\t\t} else if ( face == 4.0 ) {\n\n\t\t\t\tdirection = direction.xzy;\n\t\t\t\tdirection.xy *= -1.0; // ( -u, -1, v ) neg y\n\n\t\t\t} else if ( face == 5.0 ) {\n\n\t\t\t\tdirection.z *= -1.0; // ( u, v, -1 ) neg z\n\n\t\t\t}\n\n\t\t\treturn direction;\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvOutputDirection = getDirection( uv, faceIndex );\n\t\t\tgl_Position = vec4( position, 1.0 );\n\n\t\t}\n\t"}function Vi(){return"\n\n\t\tuniform int inputEncoding;\n\t\tuniform int outputEncoding;\n\n\t\t#include \n\n\t\tvec4 inputTexelToLinear( vec4 value ) {\n\n\t\t\tif ( inputEncoding == 0 ) {\n\n\t\t\t\treturn value;\n\n\t\t\t} else if ( inputEncoding == 1 ) {\n\n\t\t\t\treturn sRGBToLinear( value );\n\n\t\t\t} else if ( inputEncoding == 2 ) {\n\n\t\t\t\treturn RGBEToLinear( value );\n\n\t\t\t} else if ( inputEncoding == 3 ) {\n\n\t\t\t\treturn RGBMToLinear( value, 7.0 );\n\n\t\t\t} else if ( inputEncoding == 4 ) {\n\n\t\t\t\treturn RGBMToLinear( value, 16.0 );\n\n\t\t\t} else if ( inputEncoding == 5 ) {\n\n\t\t\t\treturn RGBDToLinear( value, 256.0 );\n\n\t\t\t} else {\n\n\t\t\t\treturn GammaToLinear( value, 2.2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvec4 linearToOutputTexel( vec4 value ) {\n\n\t\t\tif ( outputEncoding == 0 ) {\n\n\t\t\t\treturn value;\n\n\t\t\t} else if ( outputEncoding == 1 ) {\n\n\t\t\t\treturn LinearTosRGB( value );\n\n\t\t\t} else if ( outputEncoding == 2 ) {\n\n\t\t\t\treturn LinearToRGBE( value );\n\n\t\t\t} else if ( outputEncoding == 3 ) {\n\n\t\t\t\treturn LinearToRGBM( value, 7.0 );\n\n\t\t\t} else if ( outputEncoding == 4 ) {\n\n\t\t\t\treturn LinearToRGBM( value, 16.0 );\n\n\t\t\t} else if ( outputEncoding == 5 ) {\n\n\t\t\t\treturn LinearToRGBD( value, 256.0 );\n\n\t\t\t} else {\n\n\t\t\t\treturn LinearToGamma( value, 2.2 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tvec4 envMapTexelToLinear( vec4 color ) {\n\n\t\t\treturn inputTexelToLinear( color );\n\n\t\t}\n\t"}function Wi(t){let e=new WeakMap,n=null;function i(t){const n=t.target;n.removeEventListener("dispose",i);const r=e.get(n);void 0!==r&&(e.delete(n),r.dispose())}return{get:function(l){if(l&&l.isTexture&&!1===l.isRenderTargetTexture){const c=l.mapping,h=c===a||c===o,u=c===r||c===s;if(h||u){if(e.has(l))return e.get(l).texture;{const r=l.image;if(h&&r&&r.height>0||u&&r&&function(t){let e=0;const n=6;for(let i=0;i65535?cn:on)(n,1);o.version=a;const l=s.get(t);l&&e.remove(l),s.set(t,o)}return{get:function(t,e){return!0===r[e.id]||(e.addEventListener("dispose",a),r[e.id]=!0,n.memory.geometries++),e},update:function(t){const n=t.attributes;for(const t in n)e.update(n[t],34962);const i=t.morphAttributes;for(const t in i){const n=i[t];for(let t=0,i=n.length;t0)return t;const r=e*n;let s=sr[r];if(void 0===s&&(s=new Float32Array(r),sr[r]=s),0!==e){i.toArray(s,0);for(let i=1,r=0;i!==e;++i)r+=n,t[i].toArray(s,r)}return s}function ur(t,e){if(t.length!==e.length)return!1;for(let n=0,i=t.length;n/gm;function ms(t){return t.replace(ps,fs)}function fs(t,e){const n=hi[e];if(void 0===n)throw new Error("Can not resolve #include <"+e+">");return ms(n)}const gs=/#pragma unroll_loop[\s]+?for \( int i \= (\d+)\; i < (\d+)\; i \+\+ \) \{([\s\S]+?)(?=\})\}/g,vs=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function ys(t){return t.replace(vs,_s).replace(gs,xs)}function xs(t,e,n,i){return console.warn("WebGLProgram: #pragma unroll_loop shader syntax is deprecated. Please use #pragma unroll_loop_start syntax instead."),_s(t,e,n,i)}function _s(t,e,n,i){let r="";for(let t=parseInt(e);t0?t.gammaFactor:1,v=n.isWebGL2?"":function(t){return[t.extensionDerivatives||t.envMapCubeUV||t.bumpMap||t.tangentSpaceNormalMap||t.clearcoatNormalMap||t.flatShading||"physical"===t.shaderID?"#extension GL_OES_standard_derivatives : enable":"",(t.extensionFragDepth||t.logarithmicDepthBuffer)&&t.rendererExtensionFragDepth?"#extension GL_EXT_frag_depth : enable":"",t.extensionDrawBuffers&&t.rendererExtensionDrawBuffers?"#extension GL_EXT_draw_buffers : require":"",(t.extensionShaderTextureLOD||t.envMap||t.transmission)&&t.rendererExtensionShaderTextureLod?"#extension GL_EXT_shader_texture_lod : enable":""].filter(hs).join("\n")}(n),y=function(t){const e=[];for(const n in t){const i=t[n];!1!==i&&e.push("#define "+n+" "+i)}return e.join("\n")}(o),x=a.createProgram();let _,b,M=n.glslVersion?"#version "+n.glslVersion+"\n":"";n.isRawShaderMaterial?(_=[y].filter(hs).join("\n"),_.length>0&&(_+="\n"),b=[v,y].filter(hs).join("\n"),b.length>0&&(b+="\n")):(_=[bs(n),"#define SHADER_NAME "+n.shaderName,y,n.instancing?"#define USE_INSTANCING":"",n.instancingColor?"#define USE_INSTANCING_COLOR":"",n.supportsVertexTextures?"#define VERTEX_TEXTURES":"","#define GAMMA_FACTOR "+g,"#define MAX_BONES "+n.maxBones,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+m:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.displacementMap&&n.supportsVertexTextures?"#define USE_DISPLACEMENTMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularIntensityMap?"#define USE_SPECULARINTENSITYMAP":"",n.specularTintMap?"#define USE_SPECULARTINTMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.flatShading?"#define FLAT_SHADED":"",n.skinning?"#define USE_SKINNING":"",n.useVertexTexture?"#define BONE_TEXTURE":"",n.morphTargets?"#define USE_MORPHTARGETS":"",n.morphNormals&&!1===n.flatShading?"#define USE_MORPHNORMALS":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+d:"",n.sizeAttenuation?"#define USE_SIZEATTENUATION":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING","\tattribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR","\tattribute vec3 instanceColor;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_TANGENT","\tattribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )","\tattribute vec4 color;","#elif defined( USE_COLOR )","\tattribute vec3 color;","#endif","#ifdef USE_MORPHTARGETS","\tattribute vec3 morphTarget0;","\tattribute vec3 morphTarget1;","\tattribute vec3 morphTarget2;","\tattribute vec3 morphTarget3;","\t#ifdef USE_MORPHNORMALS","\t\tattribute vec3 morphNormal0;","\t\tattribute vec3 morphNormal1;","\t\tattribute vec3 morphNormal2;","\t\tattribute vec3 morphNormal3;","\t#else","\t\tattribute vec3 morphTarget4;","\t\tattribute vec3 morphTarget5;","\t\tattribute vec3 morphTarget6;","\t\tattribute vec3 morphTarget7;","\t#endif","#endif","#ifdef USE_SKINNING","\tattribute vec4 skinIndex;","\tattribute vec4 skinWeight;","#endif","\n"].filter(hs).join("\n"),b=[v,bs(n),"#define SHADER_NAME "+n.shaderName,y,"#define GAMMA_FACTOR "+g,n.useFog&&n.fog?"#define USE_FOG":"",n.useFog&&n.fogExp2?"#define FOG_EXP2":"",n.map?"#define USE_MAP":"",n.matcap?"#define USE_MATCAP":"",n.envMap?"#define USE_ENVMAP":"",n.envMap?"#define "+p:"",n.envMap?"#define "+m:"",n.envMap?"#define "+f:"",n.lightMap?"#define USE_LIGHTMAP":"",n.aoMap?"#define USE_AOMAP":"",n.emissiveMap?"#define USE_EMISSIVEMAP":"",n.bumpMap?"#define USE_BUMPMAP":"",n.normalMap?"#define USE_NORMALMAP":"",n.normalMap&&n.objectSpaceNormalMap?"#define OBJECTSPACE_NORMALMAP":"",n.normalMap&&n.tangentSpaceNormalMap?"#define TANGENTSPACE_NORMALMAP":"",n.clearcoat?"#define USE_CLEARCOAT":"",n.clearcoatMap?"#define USE_CLEARCOATMAP":"",n.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",n.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",n.specularMap?"#define USE_SPECULARMAP":"",n.specularIntensityMap?"#define USE_SPECULARINTENSITYMAP":"",n.specularTintMap?"#define USE_SPECULARTINTMAP":"",n.roughnessMap?"#define USE_ROUGHNESSMAP":"",n.metalnessMap?"#define USE_METALNESSMAP":"",n.alphaMap?"#define USE_ALPHAMAP":"",n.alphaTest?"#define USE_ALPHATEST":"",n.sheenTint?"#define USE_SHEEN":"",n.transmission?"#define USE_TRANSMISSION":"",n.transmissionMap?"#define USE_TRANSMISSIONMAP":"",n.thicknessMap?"#define USE_THICKNESSMAP":"",n.vertexTangents?"#define USE_TANGENT":"",n.vertexColors||n.instancingColor?"#define USE_COLOR":"",n.vertexAlphas?"#define USE_COLOR_ALPHA":"",n.vertexUvs?"#define USE_UV":"",n.uvsVertexOnly?"#define UVS_VERTEX_ONLY":"",n.gradientMap?"#define USE_GRADIENTMAP":"",n.flatShading?"#define FLAT_SHADED":"",n.doubleSided?"#define DOUBLE_SIDED":"",n.flipSided?"#define FLIP_SIDED":"",n.shadowMapEnabled?"#define USE_SHADOWMAP":"",n.shadowMapEnabled?"#define "+d:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.physicallyCorrectLights?"#define PHYSICALLY_CORRECT_LIGHTS":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.logarithmicDepthBuffer&&n.rendererExtensionFragDepth?"#define USE_LOGDEPTHBUF_EXT":"",(n.extensionShaderTextureLOD||n.envMap)&&n.rendererExtensionShaderTextureLod?"#define TEXTURE_LOD_EXT":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",0!==n.toneMapping?"#define TONE_MAPPING":"",0!==n.toneMapping?hi.tonemapping_pars_fragment:"",0!==n.toneMapping?cs("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.format===T?"#define OPAQUE":"",hi.encodings_pars_fragment,n.map?os("mapTexelToLinear",n.mapEncoding):"",n.matcap?os("matcapTexelToLinear",n.matcapEncoding):"",n.envMap?os("envMapTexelToLinear",n.envMapEncoding):"",n.emissiveMap?os("emissiveMapTexelToLinear",n.emissiveMapEncoding):"",n.specularTintMap?os("specularTintMapTexelToLinear",n.specularTintMapEncoding):"",n.lightMap?os("lightMapTexelToLinear",n.lightMapEncoding):"",ls("linearToOutputTexel",n.outputEncoding),n.depthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(hs).join("\n")),h=ms(h),h=us(h,n),h=ds(h,n),u=ms(u),u=us(u,n),u=ds(u,n),h=ys(h),u=ys(u),n.isWebGL2&&!0!==n.isRawShaderMaterial&&(M="#version 300 es\n",_=["#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+_,b=["#define varying in",n.glslVersion===it?"":"out highp vec4 pc_fragColor;",n.glslVersion===it?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join("\n")+"\n"+b);const w=M+b+u,S=is(a,35633,M+_+h),E=is(a,35632,w);if(a.attachShader(x,S),a.attachShader(x,E),void 0!==n.index0AttributeName?a.bindAttribLocation(x,0,n.index0AttributeName):!0===n.morphTargets&&a.bindAttribLocation(x,0,"position"),a.linkProgram(x),t.debug.checkShaderErrors){const t=a.getProgramInfoLog(x).trim(),e=a.getShaderInfoLog(S).trim(),n=a.getShaderInfoLog(E).trim();let i=!0,r=!0;if(!1===a.getProgramParameter(x,35714)){i=!1;const e=as(a,S,"vertex"),n=as(a,E,"fragment");console.error("THREE.WebGLProgram: Shader Error "+a.getError()+" - VALIDATE_STATUS "+a.getProgramParameter(x,35715)+"\n\nProgram Info Log: "+t+"\n"+e+"\n"+n)}else""!==t?console.warn("THREE.WebGLProgram: Program Info Log:",t):""!==e&&""!==n||(r=!1);r&&(this.diagnostics={runnable:i,programLog:t,vertexShader:{log:e,prefix:_},fragmentShader:{log:n,prefix:b}})}let A,L;return a.deleteShader(S),a.deleteShader(E),this.getUniforms=function(){return void 0===A&&(A=new ns(a,x)),A},this.getAttributes=function(){return void 0===L&&(L=function(t,e){const n={},i=t.getProgramParameter(e,35721);for(let r=0;r0,C=s.clearcoat>0;return{isWebGL2:h,shaderID:S,shaderName:s.type,vertexShader:E,fragmentShader:A,defines:s.defines,isRawShaderMaterial:!0===s.isRawShaderMaterial,glslVersion:s.glslVersion,precision:f,instancing:!0===_.isInstancedMesh,instancingColor:!0===_.isInstancedMesh&&null!==_.instanceColor,supportsVertexTextures:m,outputEncoding:null!==L?y(L.texture):t.outputEncoding,map:!!s.map,mapEncoding:y(s.map),matcap:!!s.matcap,matcapEncoding:y(s.matcap),envMap:!!w,envMapMode:w&&w.mapping,envMapEncoding:y(w),envMapCubeUV:!!w&&(w.mapping===l||w.mapping===c),lightMap:!!s.lightMap,lightMapEncoding:y(s.lightMap),aoMap:!!s.aoMap,emissiveMap:!!s.emissiveMap,emissiveMapEncoding:y(s.emissiveMap),bumpMap:!!s.bumpMap,normalMap:!!s.normalMap,objectSpaceNormalMap:1===s.normalMapType,tangentSpaceNormalMap:0===s.normalMapType,clearcoat:C,clearcoatMap:C&&!!s.clearcoatMap,clearcoatRoughnessMap:C&&!!s.clearcoatRoughnessMap,clearcoatNormalMap:C&&!!s.clearcoatNormalMap,displacementMap:!!s.displacementMap,roughnessMap:!!s.roughnessMap,metalnessMap:!!s.metalnessMap,specularMap:!!s.specularMap,specularIntensityMap:!!s.specularIntensityMap,specularTintMap:!!s.specularTintMap,specularTintMapEncoding:y(s.specularTintMap),alphaMap:!!s.alphaMap,alphaTest:R,gradientMap:!!s.gradientMap,sheenTint:!!s.sheenTint&&(s.sheenTint.r>0||s.sheenTint.g>0||s.sheenTint.b>0),transmission:s.transmission>0,transmissionMap:!!s.transmissionMap,thicknessMap:!!s.thicknessMap,combine:s.combine,vertexTangents:!!s.normalMap&&!!_.geometry&&!!_.geometry.attributes.tangent,vertexColors:s.vertexColors,vertexAlphas:!0===s.vertexColors&&!!_.geometry&&!!_.geometry.attributes.color&&4===_.geometry.attributes.color.itemSize,vertexUvs:!!(s.map||s.bumpMap||s.normalMap||s.specularMap||s.alphaMap||s.emissiveMap||s.roughnessMap||s.metalnessMap||s.clearcoatMap||s.clearcoatRoughnessMap||s.clearcoatNormalMap||s.displacementMap||s.transmissionMap||s.thicknessMap||s.specularIntensityMap||s.specularTintMap),uvsVertexOnly:!(s.map||s.bumpMap||s.normalMap||s.specularMap||s.alphaMap||s.emissiveMap||s.roughnessMap||s.metalnessMap||s.clearcoatNormalMap||s.transmission>0||s.transmissionMap||s.thicknessMap||s.specularIntensityMap||s.specularTintMap||!s.displacementMap),fog:!!b,useFog:s.fog,fogExp2:b&&b.isFogExp2,flatShading:!!s.flatShading,sizeAttenuation:s.sizeAttenuation,logarithmicDepthBuffer:u,skinning:!0===_.isSkinnedMesh&&T>0,maxBones:T,useVertexTexture:d,morphTargets:!!_.geometry&&!!_.geometry.morphAttributes.position,morphNormals:!!_.geometry&&!!_.geometry.morphAttributes.normal,numDirLights:o.directional.length,numPointLights:o.point.length,numSpotLights:o.spot.length,numRectAreaLights:o.rectArea.length,numHemiLights:o.hemi.length,numDirLightShadows:o.directionalShadowMap.length,numPointLightShadows:o.pointShadowMap.length,numSpotLightShadows:o.spotShadowMap.length,numClippingPlanes:a.numPlanes,numClipIntersection:a.numIntersection,format:s.format,dithering:s.dithering,shadowMapEnabled:t.shadowMap.enabled&&v.length>0,shadowMapType:t.shadowMap.type,toneMapping:s.toneMapped?t.toneMapping:0,physicallyCorrectLights:t.physicallyCorrectLights,premultipliedAlpha:s.premultipliedAlpha,doubleSided:2===s.side,flipSided:1===s.side,depthPacking:void 0!==s.depthPacking&&s.depthPacking,index0AttributeName:s.index0AttributeName,extensionDerivatives:s.extensions&&s.extensions.derivatives,extensionFragDepth:s.extensions&&s.extensions.fragDepth,extensionDrawBuffers:s.extensions&&s.extensions.drawBuffers,extensionShaderTextureLOD:s.extensions&&s.extensions.shaderTextureLOD,rendererExtensionFragDepth:h||i.has("EXT_frag_depth"),rendererExtensionDrawBuffers:h||i.has("WEBGL_draw_buffers"),rendererExtensionShaderTextureLod:h||i.has("EXT_shader_texture_lod"),customProgramCacheKey:s.customProgramCacheKey()}},getProgramCacheKey:function(e){const n=[];if(e.shaderID?n.push(e.shaderID):(n.push(e.fragmentShader),n.push(e.vertexShader)),void 0!==e.defines)for(const t in e.defines)n.push(t),n.push(e.defines[t]);if(!1===e.isRawShaderMaterial){for(let t=0;t0?r.push(h):!0===n.transparent?s.push(h):i.push(h)},unshift:function(t,e,n,a,l,c){const h=o(t,e,n,a,l,c);n.transmission>0?r.unshift(h):!0===n.transparent?s.unshift(h):i.unshift(h)},finish:function(){for(let t=n,i=e.length;t1&&i.sort(t||Ts),r.length>1&&r.sort(e||Es),s.length>1&&s.sort(e||Es)}}}function Ls(t){let e=new WeakMap;return{get:function(n,i){let r;return!1===e.has(n)?(r=new As(t),e.set(n,[r])):i>=e.get(n).length?(r=new As(t),e.get(n).push(r)):r=e.get(n)[i],r},dispose:function(){e=new WeakMap}}}function Rs(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":n={direction:new Rt,color:new Qe};break;case"SpotLight":n={position:new Rt,direction:new Rt,color:new Qe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":n={position:new Rt,color:new Qe,distance:0,decay:0};break;case"HemisphereLight":n={direction:new Rt,skyColor:new Qe,groundColor:new Qe};break;case"RectAreaLight":n={color:new Qe,position:new Rt,halfWidth:new Rt,halfHeight:new Rt}}return t[e.id]=n,n}}}let Cs=0;function Ps(t,e){return(e.castShadow?1:0)-(t.castShadow?1:0)}function Is(t,e){const n=new Rs,i=function(){const t={};return{get:function(e){if(void 0!==t[e.id])return t[e.id];let n;switch(e.type){case"DirectionalLight":case"SpotLight":n={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new vt};break;case"PointLight":n={shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new vt,shadowCameraNear:1,shadowCameraFar:1e3}}return t[e.id]=n,n}}}(),r={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotShadow:[],spotShadowMap:[],spotShadowMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[]};for(let t=0;t<9;t++)r.probe.push(new Rt);const s=new Rt,a=new ae,o=new ae;return{setup:function(s,a){let o=0,l=0,c=0;for(let t=0;t<9;t++)r.probe[t].set(0,0,0);let h=0,u=0,d=0,p=0,m=0,f=0,g=0,v=0;s.sort(Ps);const y=!0!==a?Math.PI:1;for(let t=0,e=s.length;t0&&(e.isWebGL2||!0===t.has("OES_texture_float_linear")?(r.rectAreaLTC1=ui.LTC_FLOAT_1,r.rectAreaLTC2=ui.LTC_FLOAT_2):!0===t.has("OES_texture_half_float_linear")?(r.rectAreaLTC1=ui.LTC_HALF_1,r.rectAreaLTC2=ui.LTC_HALF_2):console.error("THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.")),r.ambient[0]=o,r.ambient[1]=l,r.ambient[2]=c;const x=r.hash;x.directionalLength===h&&x.pointLength===u&&x.spotLength===d&&x.rectAreaLength===p&&x.hemiLength===m&&x.numDirectionalShadows===f&&x.numPointShadows===g&&x.numSpotShadows===v||(r.directional.length=h,r.spot.length=d,r.rectArea.length=p,r.point.length=u,r.hemi.length=m,r.directionalShadow.length=f,r.directionalShadowMap.length=f,r.pointShadow.length=g,r.pointShadowMap.length=g,r.spotShadow.length=v,r.spotShadowMap.length=v,r.directionalShadowMatrix.length=f,r.pointShadowMatrix.length=g,r.spotShadowMatrix.length=v,x.directionalLength=h,x.pointLength=u,x.spotLength=d,x.rectAreaLength=p,x.hemiLength=m,x.numDirectionalShadows=f,x.numPointShadows=g,x.numSpotShadows=v,r.version=Cs++)},setupView:function(t,e){let n=0,i=0,l=0,c=0,h=0;const u=e.matrixWorldInverse;for(let e=0,d=t.length;e=n.get(i).length?(s=new Ds(t,e),n.get(i).push(s)):s=n.get(i)[r],s},dispose:function(){n=new WeakMap}}}class zs extends We{constructor(t){super(),this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}zs.prototype.isMeshDepthMaterial=!0;class Bs extends We{constructor(t){super(),this.type="MeshDistanceMaterial",this.referencePosition=new Rt,this.nearDistance=1,this.farDistance=1e3,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.fog=!1,this.setValues(t)}copy(t){return super.copy(t),this.referencePosition.copy(t.referencePosition),this.nearDistance=t.nearDistance,this.farDistance=t.farDistance,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}Bs.prototype.isMeshDistanceMaterial=!0;function Fs(t,e,n){let i=new ai;const r=new vt,s=new vt,a=new St,o=new zs({depthPacking:3201}),l=new Bs,c={},h=n.maxTextureSize,u={0:1,1:0,2:2},d=new Xn({uniforms:{shadow_pass:{value:null},resolution:{value:new vt},radius:{value:4},samples:{value:8}},vertexShader:"void main() {\n\tgl_Position = vec4( position, 1.0 );\n}",fragmentShader:"uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\nuniform float samples;\n#include \nvoid main() {\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"}),m=d.clone();m.defines.HORIZONTAL_PASS=1;const f=new wn;f.setAttribute("position",new en(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const v=new Gn(f,d),y=this;function x(n,i){const r=e.update(v);d.uniforms.shadow_pass.value=n.map.texture,d.uniforms.resolution.value=n.mapSize,d.uniforms.radius.value=n.radius,d.uniforms.samples.value=n.blurSamples,t.setRenderTarget(n.mapPass),t.clear(),t.renderBufferDirect(i,null,r,d,v,null),m.uniforms.shadow_pass.value=n.mapPass.texture,m.uniforms.resolution.value=n.mapSize,m.uniforms.radius.value=n.radius,m.uniforms.samples.value=n.blurSamples,t.setRenderTarget(n.map),t.clear(),t.renderBufferDirect(i,null,r,m,v,null)}function _(e,n,i,r,s,a,h){let d=null;const p=!0===r.isPointLight?e.customDistanceMaterial:e.customDepthMaterial;if(d=void 0!==p?p:!0===r.isPointLight?l:o,t.localClippingEnabled&&!0===i.clipShadows&&0!==i.clippingPlanes.length||i.displacementMap&&0!==i.displacementScale||i.alphaMap&&i.alphaTest>0){const t=d.uuid,e=i.uuid;let n=c[t];void 0===n&&(n={},c[t]=n);let r=n[e];void 0===r&&(r=d.clone(),n[e]=r),d=r}return d.visible=i.visible,d.wireframe=i.wireframe,d.side=3===h?null!==i.shadowSide?i.shadowSide:i.side:null!==i.shadowSide?i.shadowSide:u[i.side],d.alphaMap=i.alphaMap,d.alphaTest=i.alphaTest,d.clipShadows=i.clipShadows,d.clippingPlanes=i.clippingPlanes,d.clipIntersection=i.clipIntersection,d.displacementMap=i.displacementMap,d.displacementScale=i.displacementScale,d.displacementBias=i.displacementBias,d.wireframeLinewidth=i.wireframeLinewidth,d.linewidth=i.linewidth,!0===r.isPointLight&&!0===d.isMeshDistanceMaterial&&(d.referencePosition.setFromMatrixPosition(r.matrixWorld),d.nearDistance=s,d.farDistance=a),d}function b(n,r,s,a,o){if(!1===n.visible)return;if(n.layers.test(r.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&3===o)&&(!n.frustumCulled||i.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(s.matrixWorldInverse,n.matrixWorld);const i=e.update(n),r=n.material;if(Array.isArray(r)){const e=i.groups;for(let l=0,c=e.length;lh||r.y>h)&&(r.x>h&&(s.x=Math.floor(h/m.x),r.x=s.x*m.x,u.mapSize.x=s.x),r.y>h&&(s.y=Math.floor(h/m.y),r.y=s.y*m.y,u.mapSize.y=s.y)),null===u.map&&!u.isPointLightShadow&&3===this.type){const t={minFilter:g,magFilter:g,format:E};u.map=new Tt(r.x,r.y,t),u.map.texture.name=c.name+".shadowMap",u.mapPass=new Tt(r.x,r.y,t),u.camera.updateProjectionMatrix()}if(null===u.map){const t={minFilter:p,magFilter:p,format:E};u.map=new Tt(r.x,r.y,t),u.map.texture.name=c.name+".shadowMap",u.camera.updateProjectionMatrix()}t.setRenderTarget(u.map),t.clear();const f=u.getViewportCount();for(let t=0;t=1):-1!==R.indexOf("OpenGL ES")&&(L=parseFloat(/^OpenGL ES (\d)/.exec(R)[1]),A=L>=2);let C=null,P={};const I=t.getParameter(3088),D=t.getParameter(2978),N=(new St).fromArray(I),z=(new St).fromArray(D);function B(e,n,i){const r=new Uint8Array(4),s=t.createTexture();t.bindTexture(e,s),t.texParameteri(e,10241,9728),t.texParameteri(e,10240,9728);for(let e=0;ei||t.height>i)&&(r=i/Math.max(t.width,t.height)),r<1||!0===e){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const i=e?ft:Math.floor,s=i(r*t.width),a=i(r*t.height);void 0===P&&(P=D(s,a));const o=n?D(s,a):P;o.width=s,o.height=a;return o.getContext("2d").drawImage(t,0,0,s,a),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+t.width+"x"+t.height+") to ("+s+"x"+a+")."),o}return"data"in t&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+t.width+"x"+t.height+")."),t}return t}function z(t){return pt(t.width)&&pt(t.height)}function B(t,e){return t.generateMipmaps&&e&&t.minFilter!==p&&t.minFilter!==g}function F(e,n,r,s,a=1){t.generateMipmap(e);i.get(n).__maxMipLevel=Math.log2(Math.max(r,s,a))}function O(n,i,r){if(!1===o)return i;if(null!==n){if(void 0!==t[n])return t[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}let s=i;return 6403===i&&(5126===r&&(s=33326),5131===r&&(s=33325),5121===r&&(s=33321)),6407===i&&(5126===r&&(s=34837),5131===r&&(s=34843),5121===r&&(s=32849)),6408===i&&(5126===r&&(s=34836),5131===r&&(s=34842),5121===r&&(s=32856)),33325!==s&&33326!==s&&34842!==s&&34836!==s||e.get("EXT_color_buffer_float"),s}function U(t){return t===p||t===m||t===f?9728:9729}function H(e){const n=e.target;n.removeEventListener("dispose",H),function(e){const n=i.get(e);if(void 0===n.__webglInit)return;t.deleteTexture(n.__webglTexture),i.remove(e)}(n),n.isVideoTexture&&C.delete(n),a.memory.textures--}function G(e){const n=e.target;n.removeEventListener("dispose",G),function(e){const n=e.texture,r=i.get(e),s=i.get(n);if(!e)return;void 0!==s.__webglTexture&&(t.deleteTexture(s.__webglTexture),a.memory.textures--);e.depthTexture&&e.depthTexture.dispose();if(e.isWebGLCubeRenderTarget)for(let e=0;e<6;e++)t.deleteFramebuffer(r.__webglFramebuffer[e]),r.__webglDepthbuffer&&t.deleteRenderbuffer(r.__webglDepthbuffer[e]);else t.deleteFramebuffer(r.__webglFramebuffer),r.__webglDepthbuffer&&t.deleteRenderbuffer(r.__webglDepthbuffer),r.__webglMultisampledFramebuffer&&t.deleteFramebuffer(r.__webglMultisampledFramebuffer),r.__webglColorRenderbuffer&&t.deleteRenderbuffer(r.__webglColorRenderbuffer),r.__webglDepthRenderbuffer&&t.deleteRenderbuffer(r.__webglDepthRenderbuffer);if(e.isWebGLMultipleRenderTargets)for(let e=0,r=n.length;e0&&r.__version!==t.version){const n=t.image;if(void 0===n)console.warn("THREE.WebGLRenderer: Texture marked for update but image is undefined");else{if(!1!==n.complete)return void J(r,t,e);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}n.activeTexture(33984+e),n.bindTexture(3553,r.__webglTexture)}function W(e,r){const a=i.get(e);e.version>0&&a.__version!==e.version?function(e,i,r){if(6!==i.image.length)return;Y(e,i),n.activeTexture(33984+r),n.bindTexture(34067,e.__webglTexture),t.pixelStorei(37440,i.flipY),t.pixelStorei(37441,i.premultiplyAlpha),t.pixelStorei(3317,i.unpackAlignment),t.pixelStorei(37443,0);const a=i&&(i.isCompressedTexture||i.image[0].isCompressedTexture),l=i.image[0]&&i.image[0].isDataTexture,h=[];for(let t=0;t<6;t++)h[t]=a||l?l?i.image[t].image:i.image[t]:N(i.image[t],!1,!0,c);const u=h[0],d=z(u)||o,p=s.convert(i.format),m=s.convert(i.type),f=O(i.internalFormat,p,m);let g;if(X(34067,i,d),a){for(let t=0;t<6;t++){g=h[t].mipmaps;for(let e=0;e1||i.get(s).__currentAnisotropy)&&(t.texParameterf(n,a.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(s.anisotropy,r.getMaxAnisotropy())),i.get(s).__currentAnisotropy=s.anisotropy)}}function Y(e,n){void 0===e.__webglInit&&(e.__webglInit=!0,n.addEventListener("dispose",H),e.__webglTexture=t.createTexture(),a.memory.textures++)}function J(e,i,r){let a=3553;i.isDataTexture2DArray&&(a=35866),i.isDataTexture3D&&(a=32879),Y(e,i),n.activeTexture(33984+r),n.bindTexture(a,e.__webglTexture),t.pixelStorei(37440,i.flipY),t.pixelStorei(37441,i.premultiplyAlpha),t.pixelStorei(3317,i.unpackAlignment),t.pixelStorei(37443,0);const l=function(t){return!o&&(t.wrapS!==u||t.wrapT!==u||t.minFilter!==p&&t.minFilter!==g)}(i)&&!1===z(i.image),c=N(i.image,l,!1,x),h=z(c)||o,d=s.convert(i.format);let m,f=s.convert(i.type),v=O(i.internalFormat,d,f);X(a,i,h);const y=i.mipmaps;if(i.isDepthTexture)v=6402,o?v=i.type===M?36012:i.type===b?33190:i.type===S?35056:33189:i.type===M&&console.error("WebGLRenderer: Floating point depth texture requires WebGL2."),i.format===A&&6402===v&&i.type!==_&&i.type!==b&&(console.warn("THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture."),i.type=_,f=s.convert(i.type)),i.format===L&&6402===v&&(v=34041,i.type!==S&&(console.warn("THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture."),i.type=S,f=s.convert(i.type))),n.texImage2D(3553,0,v,c.width,c.height,0,d,f,null);else if(i.isDataTexture)if(y.length>0&&h){for(let t=0,e=y.length;t0&&h){for(let t=0,e=y.length;t=l&&console.warn("THREE.WebGLTextures: Trying to use "+t+" texture units while this GPU supports only "+l),k+=1,t},this.resetTextureUnits=function(){k=0},this.setTexture2D=V,this.setTexture2DArray=function(t,e){const r=i.get(t);t.version>0&&r.__version!==t.version?J(r,t,e):(n.activeTexture(33984+e),n.bindTexture(35866,r.__webglTexture))},this.setTexture3D=function(t,e){const r=i.get(t);t.version>0&&r.__version!==t.version?J(r,t,e):(n.activeTexture(33984+e),n.bindTexture(32879,r.__webglTexture))},this.setTextureCube=W,this.setupRenderTarget=function(e){const l=e.texture,c=i.get(e),h=i.get(l);e.addEventListener("dispose",G),!0!==e.isWebGLMultipleRenderTargets&&(h.__webglTexture=t.createTexture(),h.__version=l.version,a.memory.textures++);const u=!0===e.isWebGLCubeRenderTarget,d=!0===e.isWebGLMultipleRenderTargets,p=!0===e.isWebGLMultisampleRenderTarget,m=l.isDataTexture3D||l.isDataTexture2DArray,f=z(e)||o;if(!o||l.format!==T||l.type!==M&&l.type!==w||(l.format=E,console.warn("THREE.WebGLRenderer: Rendering to textures with RGB format is not supported. Using RGBA format instead.")),u){c.__webglFramebuffer=[];for(let e=0;e<6;e++)c.__webglFramebuffer[e]=t.createFramebuffer()}else if(c.__webglFramebuffer=t.createFramebuffer(),d)if(r.drawBuffers){const n=e.texture;for(let e=0,r=n.length;eo+c?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!l.inputState.pinching&&a<=o-c&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else null!==o&&t.gripSpace&&(r=e.getPose(t.gripSpace,n),null!==r&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1));return null!==a&&(a.visible=null!==i),null!==o&&(o.visible=null!==r),null!==l&&(l.visible=null!==s),this}}class js extends rt{constructor(t,e){super();const n=this,i=t.state;let r=null,s=1,a=null,o="local-floor",l=null,c=null,h=null,u=null,d=null,p=!1,m=null,f=null,g=null,v=null,y=null,x=null;const _=[],b=new Map,M=new Jn;M.layers.enable(1),M.viewport=new St;const w=new Jn;w.layers.enable(2),w.viewport=new St;const S=[M,w],T=new Gs;T.layers.enable(1),T.layers.enable(2);let E=null,A=null;function L(t){const e=b.get(t.inputSource);e&&e.dispatchEvent({type:t.type,data:t.inputSource})}function R(){b.forEach((function(t,e){t.disconnect(e)})),b.clear(),E=null,A=null,i.bindXRFramebuffer(null),t.setRenderTarget(t.getRenderTarget()),h&&e.deleteFramebuffer(h),m&&e.deleteFramebuffer(m),f&&e.deleteRenderbuffer(f),g&&e.deleteRenderbuffer(g),h=null,m=null,f=null,g=null,d=null,u=null,c=null,r=null,z.stop(),n.isPresenting=!1,n.dispatchEvent({type:"sessionend"})}function C(t){const e=r.inputSources;for(let t=0;t<_.length;t++)b.set(e[t],_[t]);for(let e=0;e0&&(e.alphaTest.value=n.alphaTest);const i=t.get(n).envMap;if(i){e.envMap.value=i,e.flipEnvMap.value=i.isCubeTexture&&!1===i.isRenderTargetTexture?-1:1,e.reflectivity.value=n.reflectivity,e.ior.value=n.ior,e.refractionRatio.value=n.refractionRatio;const r=t.get(i).__maxMipLevel;void 0!==r&&(e.maxMipLevel.value=r)}let r,s;n.lightMap&&(e.lightMap.value=n.lightMap,e.lightMapIntensity.value=n.lightMapIntensity),n.aoMap&&(e.aoMap.value=n.aoMap,e.aoMapIntensity.value=n.aoMapIntensity),n.map?r=n.map:n.specularMap?r=n.specularMap:n.displacementMap?r=n.displacementMap:n.normalMap?r=n.normalMap:n.bumpMap?r=n.bumpMap:n.roughnessMap?r=n.roughnessMap:n.metalnessMap?r=n.metalnessMap:n.alphaMap?r=n.alphaMap:n.emissiveMap?r=n.emissiveMap:n.clearcoatMap?r=n.clearcoatMap:n.clearcoatNormalMap?r=n.clearcoatNormalMap:n.clearcoatRoughnessMap?r=n.clearcoatRoughnessMap:n.specularIntensityMap?r=n.specularIntensityMap:n.specularTintMap?r=n.specularTintMap:n.transmissionMap?r=n.transmissionMap:n.thicknessMap&&(r=n.thicknessMap),void 0!==r&&(r.isWebGLRenderTarget&&(r=r.texture),!0===r.matrixAutoUpdate&&r.updateMatrix(),e.uvTransform.value.copy(r.matrix)),n.aoMap?s=n.aoMap:n.lightMap&&(s=n.lightMap),void 0!==s&&(s.isWebGLRenderTarget&&(s=s.texture),!0===s.matrixAutoUpdate&&s.updateMatrix(),e.uv2Transform.value.copy(s.matrix))}function n(e,n){e.roughness.value=n.roughness,e.metalness.value=n.metalness,n.roughnessMap&&(e.roughnessMap.value=n.roughnessMap),n.metalnessMap&&(e.metalnessMap.value=n.metalnessMap),n.emissiveMap&&(e.emissiveMap.value=n.emissiveMap),n.bumpMap&&(e.bumpMap.value=n.bumpMap,e.bumpScale.value=n.bumpScale,1===n.side&&(e.bumpScale.value*=-1)),n.normalMap&&(e.normalMap.value=n.normalMap,e.normalScale.value.copy(n.normalScale),1===n.side&&e.normalScale.value.negate()),n.displacementMap&&(e.displacementMap.value=n.displacementMap,e.displacementScale.value=n.displacementScale,e.displacementBias.value=n.displacementBias);t.get(n).envMap&&(e.envMapIntensity.value=n.envMapIntensity)}return{refreshFogUniforms:function(t,e){t.fogColor.value.copy(e.color),e.isFog?(t.fogNear.value=e.near,t.fogFar.value=e.far):e.isFogExp2&&(t.fogDensity.value=e.density)},refreshMaterialUniforms:function(t,i,r,s,a){i.isMeshBasicMaterial?e(t,i):i.isMeshLambertMaterial?(e(t,i),function(t,e){e.emissiveMap&&(t.emissiveMap.value=e.emissiveMap)}(t,i)):i.isMeshToonMaterial?(e(t,i),function(t,e){e.gradientMap&&(t.gradientMap.value=e.gradientMap);e.emissiveMap&&(t.emissiveMap.value=e.emissiveMap);e.bumpMap&&(t.bumpMap.value=e.bumpMap,t.bumpScale.value=e.bumpScale,1===e.side&&(t.bumpScale.value*=-1));e.normalMap&&(t.normalMap.value=e.normalMap,t.normalScale.value.copy(e.normalScale),1===e.side&&t.normalScale.value.negate());e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias)}(t,i)):i.isMeshPhongMaterial?(e(t,i),function(t,e){t.specular.value.copy(e.specular),t.shininess.value=Math.max(e.shininess,1e-4),e.emissiveMap&&(t.emissiveMap.value=e.emissiveMap);e.bumpMap&&(t.bumpMap.value=e.bumpMap,t.bumpScale.value=e.bumpScale,1===e.side&&(t.bumpScale.value*=-1));e.normalMap&&(t.normalMap.value=e.normalMap,t.normalScale.value.copy(e.normalScale),1===e.side&&t.normalScale.value.negate());e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias)}(t,i)):i.isMeshStandardMaterial?(e(t,i),i.isMeshPhysicalMaterial?function(t,e,i){n(t,e),t.ior.value=e.ior,e.sheenTint&&(e.sheenTint.r>0||e.sheenTint.g>0||e.sheenTint.b>0)&&(t.sheenTint.value.copy(e.sheenTint),t.sheenRoughness.value=e.sheenRoughness);e.clearcoat>0&&(t.clearcoat.value=e.clearcoat,t.clearcoatRoughness.value=e.clearcoatRoughness,e.clearcoatMap&&(t.clearcoatMap.value=e.clearcoatMap),e.clearcoatRoughnessMap&&(t.clearcoatRoughnessMap.value=e.clearcoatRoughnessMap),e.clearcoatNormalMap&&(t.clearcoatNormalScale.value.copy(e.clearcoatNormalScale),t.clearcoatNormalMap.value=e.clearcoatNormalMap,1===e.side&&t.clearcoatNormalScale.value.negate()));e.transmission>0&&(t.transmission.value=e.transmission,t.transmissionSamplerMap.value=i.texture,t.transmissionSamplerSize.value.set(i.width,i.height),e.transmissionMap&&(t.transmissionMap.value=e.transmissionMap),t.thickness.value=e.thickness,e.thicknessMap&&(t.thicknessMap.value=e.thicknessMap),t.attenuationDistance.value=e.attenuationDistance,t.attenuationTint.value.copy(e.attenuationTint));t.specularIntensity.value=e.specularIntensity,t.specularTint.value.copy(e.specularTint),e.specularIntensityMap&&(t.specularIntensityMap.value=e.specularIntensityMap);e.specularTintMap&&(t.specularTintMap.value=e.specularTintMap)}(t,i,a):n(t,i)):i.isMeshMatcapMaterial?(e(t,i),function(t,e){e.matcap&&(t.matcap.value=e.matcap);e.bumpMap&&(t.bumpMap.value=e.bumpMap,t.bumpScale.value=e.bumpScale,1===e.side&&(t.bumpScale.value*=-1));e.normalMap&&(t.normalMap.value=e.normalMap,t.normalScale.value.copy(e.normalScale),1===e.side&&t.normalScale.value.negate());e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias)}(t,i)):i.isMeshDepthMaterial?(e(t,i),function(t,e){e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias)}(t,i)):i.isMeshDistanceMaterial?(e(t,i),function(t,e){e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias);t.referencePosition.value.copy(e.referencePosition),t.nearDistance.value=e.nearDistance,t.farDistance.value=e.farDistance}(t,i)):i.isMeshNormalMaterial?(e(t,i),function(t,e){e.bumpMap&&(t.bumpMap.value=e.bumpMap,t.bumpScale.value=e.bumpScale,1===e.side&&(t.bumpScale.value*=-1));e.normalMap&&(t.normalMap.value=e.normalMap,t.normalScale.value.copy(e.normalScale),1===e.side&&t.normalScale.value.negate());e.displacementMap&&(t.displacementMap.value=e.displacementMap,t.displacementScale.value=e.displacementScale,t.displacementBias.value=e.displacementBias)}(t,i)):i.isLineBasicMaterial?(function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity}(t,i),i.isLineDashedMaterial&&function(t,e){t.dashSize.value=e.dashSize,t.totalSize.value=e.dashSize+e.gapSize,t.scale.value=e.scale}(t,i)):i.isPointsMaterial?function(t,e,n,i){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.size.value=e.size*n,t.scale.value=.5*i,e.map&&(t.map.value=e.map);e.alphaMap&&(t.alphaMap.value=e.alphaMap);e.alphaTest>0&&(t.alphaTest.value=e.alphaTest);let r;e.map?r=e.map:e.alphaMap&&(r=e.alphaMap);void 0!==r&&(!0===r.matrixAutoUpdate&&r.updateMatrix(),t.uvTransform.value.copy(r.matrix))}(t,i,r,s):i.isSpriteMaterial?function(t,e){t.diffuse.value.copy(e.color),t.opacity.value=e.opacity,t.rotation.value=e.rotation,e.map&&(t.map.value=e.map);e.alphaMap&&(t.alphaMap.value=e.alphaMap);e.alphaTest>0&&(t.alphaTest.value=e.alphaTest);let n;e.map?n=e.map:e.alphaMap&&(n=e.alphaMap);void 0!==n&&(!0===n.matrixAutoUpdate&&n.updateMatrix(),t.uvTransform.value.copy(n.matrix))}(t,i):i.isShadowMaterial?(t.color.value.copy(i.color),t.opacity.value=i.opacity):i.isShaderMaterial&&(i.uniformsNeedUpdate=!1)}}}function Xs(t={}){const e=void 0!==t.canvas?t.canvas:function(){const t=document.createElementNS("http://www.w3.org/1999/xhtml","canvas");return t.style.display="block",t}(),n=void 0!==t.context?t.context:null,i=void 0!==t.alpha&&t.alpha,r=void 0===t.depth||t.depth,s=void 0===t.stencil||t.stencil,a=void 0!==t.antialias&&t.antialias,o=void 0===t.premultipliedAlpha||t.premultipliedAlpha,l=void 0!==t.preserveDrawingBuffer&&t.preserveDrawingBuffer,c=void 0!==t.powerPreference?t.powerPreference:"default",h=void 0!==t.failIfMajorPerformanceCaveat&&t.failIfMajorPerformanceCaveat;let d=null,m=null;const f=[],g=[];this.domElement=e,this.debug={checkShaderErrors:!0},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.gammaFactor=2,this.outputEncoding=X,this.physicallyCorrectLights=!1,this.toneMapping=0,this.toneMappingExposure=1;const v=this;let _=!1,b=0,S=0,T=null,A=-1,L=null;const R=new St,C=new St;let P=null,I=e.width,D=e.height,N=1,z=null,B=null;const F=new St(0,0,I,D),O=new St(0,0,I,D);let U=!1;const H=[],G=new ai;let k=!1,V=!1,W=null;const j=new ae,q=new Rt,Y={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};function J(){return null===T?N:1}let Z,Q,K,$,tt,et,nt,it,rt,st,at,ot,lt,ct,ht,ut,dt,pt,mt,ft,gt,vt,yt,xt=n;function _t(t,n){for(let i=0;i0&&function(t,e,n){if(null===W){const t=!0===a&&!0===Q.isWebGL2;W=new(t?At:Tt)(1024,1024,{generateMipmaps:!0,type:null!==vt.convert(w)?w:x,minFilter:y,magFilter:p,wrapS:u,wrapT:u})}const i=v.getRenderTarget();v.setRenderTarget(W),v.clear();const r=v.toneMapping;v.toneMapping=0,Bt(t,e,n),v.toneMapping=r,et.updateMultisampleRenderTarget(W),et.updateRenderTargetMipmap(W),v.setRenderTarget(i)}(r,e,n),i&&K.viewport(R.copy(i)),r.length>0&&Bt(r,e,n),s.length>0&&Bt(s,e,n),o.length>0&&Bt(o,e,n)}function Bt(t,e,n){const i=!0===e.isScene?e.overrideMaterial:null;for(let r=0,s=t.length;r0?g[g.length-1]:null,f.pop(),d=f.length>0?f[f.length-1]:null},this.getActiveCubeFace=function(){return b},this.getActiveMipmapLevel=function(){return S},this.getRenderTarget=function(){return T},this.setRenderTarget=function(t,e=0,n=0){T=t,b=e,S=n,t&&void 0===tt.get(t).__webglFramebuffer&&et.setupRenderTarget(t);let i=null,r=!1,s=!1;if(t){const n=t.texture;(n.isDataTexture3D||n.isDataTexture2DArray)&&(s=!0);const a=tt.get(t).__webglFramebuffer;t.isWebGLCubeRenderTarget?(i=a[e],r=!0):i=t.isWebGLMultisampleRenderTarget?tt.get(t).__webglMultisampledFramebuffer:a,R.copy(t.viewport),C.copy(t.scissor),P=t.scissorTest}else R.copy(F).multiplyScalar(N).floor(),C.copy(O).multiplyScalar(N).floor(),P=U;if(K.bindFramebuffer(36160,i)&&Q.drawBuffers){let e=!1;if(t)if(t.isWebGLMultipleRenderTargets){const n=t.texture;if(H.length!==n.length||36064!==H[0]){for(let t=0,e=n.length;t=0&&e<=t.width-i&&n>=0&&n<=t.height-r&&xt.readPixels(e,n,i,r,vt.convert(o),vt.convert(l),s):console.error("THREE.WebGLRenderer.readRenderTargetPixels: readPixels from renderTarget failed. Framebuffer not complete.")}finally{const t=null!==T?tt.get(T).__webglFramebuffer:null;K.bindFramebuffer(36160,t)}}},this.copyFramebufferToTexture=function(t,e,n=0){const i=Math.pow(2,-n),r=Math.floor(e.image.width*i),s=Math.floor(e.image.height*i);let a=vt.convert(e.format);Q.isWebGL2&&(6407===a&&(a=32849),6408===a&&(a=32856)),et.setTexture2D(e,0),xt.copyTexImage2D(3553,n,a,t.x,t.y,r,s,0),K.unbindTexture()},this.copyTextureToTexture=function(t,e,n,i=0){const r=e.image.width,s=e.image.height,a=vt.convert(n.format),o=vt.convert(n.type);et.setTexture2D(n,0),xt.pixelStorei(37440,n.flipY),xt.pixelStorei(37441,n.premultiplyAlpha),xt.pixelStorei(3317,n.unpackAlignment),e.isDataTexture?xt.texSubImage2D(3553,i,t.x,t.y,r,s,a,o,e.image.data):e.isCompressedTexture?xt.compressedTexSubImage2D(3553,i,t.x,t.y,e.mipmaps[0].width,e.mipmaps[0].height,a,e.mipmaps[0].data):xt.texSubImage2D(3553,i,t.x,t.y,a,o,e.image),0===i&&n.generateMipmaps&&xt.generateMipmap(3553),K.unbindTexture()},this.copyTextureToTexture3D=function(t,e,n,i,r=0){if(v.isWebGL1Renderer)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.");const s=t.max.x-t.min.x+1,a=t.max.y-t.min.y+1,o=t.max.z-t.min.z+1,l=vt.convert(i.format),c=vt.convert(i.type);let h;if(i.isDataTexture3D)et.setTexture3D(i,0),h=32879;else{if(!i.isDataTexture2DArray)return void console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");et.setTexture2DArray(i,0),h=35866}xt.pixelStorei(37440,i.flipY),xt.pixelStorei(37441,i.premultiplyAlpha),xt.pixelStorei(3317,i.unpackAlignment);const u=xt.getParameter(3314),d=xt.getParameter(32878),p=xt.getParameter(3316),m=xt.getParameter(3315),f=xt.getParameter(32877),g=n.isCompressedTexture?n.mipmaps[0]:n.image;xt.pixelStorei(3314,g.width),xt.pixelStorei(32878,g.height),xt.pixelStorei(3316,t.min.x),xt.pixelStorei(3315,t.min.y),xt.pixelStorei(32877,t.min.z),n.isDataTexture||n.isDataTexture3D?xt.texSubImage3D(h,r,e.x,e.y,e.z,s,a,o,l,c,g.data):n.isCompressedTexture?(console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture."),xt.compressedTexSubImage3D(h,r,e.x,e.y,e.z,s,a,o,l,g.data)):xt.texSubImage3D(h,r,e.x,e.y,e.z,s,a,o,l,c,g),xt.pixelStorei(3314,u),xt.pixelStorei(32878,d),xt.pixelStorei(3316,p),xt.pixelStorei(3315,m),xt.pixelStorei(32877,f),0===r&&i.generateMipmaps&&xt.generateMipmap(h),K.unbindTexture()},this.initTexture=function(t){et.setTexture2D(t,0),K.unbindTexture()},this.resetState=function(){b=0,S=0,T=null,K.reset(),yt.reset()},"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}class Ys extends Xs{}Ys.prototype.isWebGL1Renderer=!0;class Js{constructor(t,e=25e-5){this.name="",this.color=new Qe(t),this.density=e}clone(){return new Js(this.color,this.density)}toJSON(){return{type:"FogExp2",color:this.color.getHex(),density:this.density}}}Js.prototype.isFogExp2=!0;class Zs{constructor(t,e=1,n=1e3){this.name="",this.color=new Qe(t),this.near=e,this.far=n}clone(){return new Zs(this.color,this.near,this.far)}toJSON(){return{type:"Fog",color:this.color.getHex(),near:this.near,far:this.far}}}Zs.prototype.isFog=!0;class Qs extends Pe{constructor(){super(),this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.overrideMaterial=null,this.autoUpdate=!0,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(t,e){return super.copy(t,e),null!==t.background&&(this.background=t.background.clone()),null!==t.environment&&(this.environment=t.environment.clone()),null!==t.fog&&(this.fog=t.fog.clone()),null!==t.overrideMaterial&&(this.overrideMaterial=t.overrideMaterial.clone()),this.autoUpdate=t.autoUpdate,this.matrixAutoUpdate=t.matrixAutoUpdate,this}toJSON(t){const e=super.toJSON(t);return null!==this.fog&&(e.object.fog=this.fog.toJSON()),e}}Qs.prototype.isScene=!0;class Ks{constructor(t,e){this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.usage=et,this.updateRange={offset:0,count:-1},this.version=0,this.uuid=ct()}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}setUsage(t){return this.usage=t,this}copy(t){return this.array=new t.array.constructor(t.array),this.count=t.count,this.stride=t.stride,this.usage=t.usage,this}copyAt(t,e,n){t*=this.stride,n*=e.stride;for(let i=0,r=this.stride;it.far||e.push({distance:o,point:ia.clone(),uv:ke.getUV(ia,ca,ha,ua,da,pa,ma,new vt),face:null,object:this})}copy(t){return super.copy(t),void 0!==t.center&&this.center.copy(t.center),this.material=t.material,this}}function ga(t,e,n,i,r,s){aa.subVectors(t,n).addScalar(.5).multiply(i),void 0!==r?(oa.x=s*aa.x-r*aa.y,oa.y=r*aa.x+s*aa.y):oa.copy(aa),t.copy(e),t.x+=oa.x,t.y+=oa.y,t.applyMatrix4(la)}fa.prototype.isSprite=!0;const va=new Rt,ya=new Rt;class xa extends Pe{constructor(){super(),this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]},isLOD:{value:!0}}),this.autoUpdate=!0}copy(t){super.copy(t,!1);const e=t.levels;for(let t=0,n=e.length;t0){let n,i;for(n=1,i=e.length;n0){va.setFromMatrixPosition(this.matrixWorld);const n=t.ray.origin.distanceTo(va);this.getObjectForDistance(n).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){va.setFromMatrixPosition(t.matrixWorld),ya.setFromMatrixPosition(this.matrixWorld);const n=va.distanceTo(ya)/t.zoom;let i,r;for(e[0].object.visible=!0,i=1,r=e.length;i=e[i].distance;i++)e[i-1].object.visible=!1,e[i].object.visible=!0;for(this._currentLevel=i-1;io)continue;u.applyMatrix4(this.matrixWorld);const d=t.ray.origin.distanceTo(u);dt.far||e.push({distance:d,point:h.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this})}}else{for(let n=Math.max(0,s.start),i=Math.min(r.count,s.start+s.count)-1;no)continue;u.applyMatrix4(this.matrixWorld);const i=t.ray.origin.distanceTo(u);it.far||e.push({distance:i,point:h.clone().applyMatrix4(this.matrixWorld),index:n,face:null,faceIndex:null,object:this})}}}else n.isGeometry&&console.error("THREE.Line.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.")}updateMorphTargets(){const t=this.geometry;if(t.isBufferGeometry){const e=t.morphAttributes,n=Object.keys(e);if(n.length>0){const t=e[n[0]];if(void 0!==t){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,n=t.length;e0&&console.error("THREE.Line.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.")}}}Va.prototype.isLine=!0;const Wa=new Rt,ja=new Rt;class qa extends Va{constructor(t,e){super(t,e),this.type="LineSegments"}computeLineDistances(){const t=this.geometry;if(t.isBufferGeometry)if(null===t.index){const e=t.attributes.position,n=[];for(let t=0,i=e.count;t0){const t=e[n[0]];if(void 0!==t){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let e=0,n=t.length;e0&&console.error("THREE.Points.updateMorphTargets() does not support THREE.Geometry. Use THREE.BufferGeometry instead.")}}}function to(t,e,n,i,r,s,a){const o=Za.distanceSqToPoint(t);if(or.far)return;s.push({distance:l,distanceToRay:Math.sqrt(o),point:n,index:e,face:null,object:a})}}$a.prototype.isPoints=!0;class eo extends Mt{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.format=void 0!==a?a:T,this.minFilter=void 0!==s?s:g,this.magFilter=void 0!==r?r:g,this.generateMipmaps=!1;const c=this;"requestVideoFrameCallback"in t&&t.requestVideoFrameCallback((function e(){c.needsUpdate=!0,t.requestVideoFrameCallback(e)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const t=this.image;!1==="requestVideoFrameCallback"in t&&t.readyState>=t.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}}eo.prototype.isVideoTexture=!0;class no extends Mt{constructor(t,e,n,i,r,s,a,o,l,c,h,u){super(null,s,a,o,l,c,i,r,h,u),this.image={width:e,height:n},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}no.prototype.isCompressedTexture=!0;class io extends Mt{constructor(t,e,n,i,r,s,a,o,l){super(t,e,n,i,r,s,a,o,l),this.needsUpdate=!0}}io.prototype.isCanvasTexture=!0;class ro extends Mt{constructor(t,e,n,i,r,s,a,o,l,c){if((c=void 0!==c?c:A)!==A&&c!==L)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===n&&c===A&&(n=_),void 0===n&&c===L&&(n=S),super(null,i,r,s,a,o,c,n,l),this.image={width:t,height:e},this.magFilter=void 0!==a?a:p,this.minFilter=void 0!==o?o:p,this.flipY=!1,this.generateMipmaps=!1}}ro.prototype.isDepthTexture=!0;class so extends wn{constructor(t=1,e=8,n=0,i=2*Math.PI){super(),this.type="CircleGeometry",this.parameters={radius:t,segments:e,thetaStart:n,thetaLength:i},e=Math.max(3,e);const r=[],s=[],a=[],o=[],l=new Rt,c=new vt;s.push(0,0,0),a.push(0,0,1),o.push(.5,.5);for(let r=0,h=3;r<=e;r++,h+=3){const u=n+r/e*i;l.x=t*Math.cos(u),l.y=t*Math.sin(u),s.push(l.x,l.y,l.z),a.push(0,0,1),c.x=(s[h]/t+1)/2,c.y=(s[h+1]/t+1)/2,o.push(c.x,c.y)}for(let t=1;t<=e;t++)r.push(t,t+1,0);this.setIndex(r),this.setAttribute("position",new un(s,3)),this.setAttribute("normal",new un(a,3)),this.setAttribute("uv",new un(o,2))}static fromJSON(t){return new so(t.radius,t.segments,t.thetaStart,t.thetaLength)}}class ao extends wn{constructor(t=1,e=1,n=1,i=8,r=1,s=!1,a=0,o=2*Math.PI){super(),this.type="CylinderGeometry",this.parameters={radiusTop:t,radiusBottom:e,height:n,radialSegments:i,heightSegments:r,openEnded:s,thetaStart:a,thetaLength:o};const l=this;i=Math.floor(i),r=Math.floor(r);const c=[],h=[],u=[],d=[];let p=0;const m=[],f=n/2;let g=0;function v(n){const r=p,s=new vt,m=new Rt;let v=0;const y=!0===n?t:e,x=!0===n?1:-1;for(let t=1;t<=i;t++)h.push(0,f*x,0),u.push(0,x,0),d.push(.5,.5),p++;const _=p;for(let t=0;t<=i;t++){const e=t/i*o+a,n=Math.cos(e),r=Math.sin(e);m.x=y*r,m.y=f*x,m.z=y*n,h.push(m.x,m.y,m.z),u.push(0,x,0),s.x=.5*n+.5,s.y=.5*r*x+.5,d.push(s.x,s.y),p++}for(let t=0;t0&&v(!0),e>0&&v(!1)),this.setIndex(c),this.setAttribute("position",new un(h,3)),this.setAttribute("normal",new un(u,3)),this.setAttribute("uv",new un(d,2))}static fromJSON(t){return new ao(t.radiusTop,t.radiusBottom,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class oo extends ao{constructor(t=1,e=1,n=8,i=1,r=!1,s=0,a=2*Math.PI){super(0,t,e,n,i,r,s,a),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:n,heightSegments:i,openEnded:r,thetaStart:s,thetaLength:a}}static fromJSON(t){return new oo(t.radius,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class lo extends wn{constructor(t,e,n=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:n,detail:i};const r=[],s=[];function a(t,e,n,i){const r=i+1,s=[];for(let i=0;i<=r;i++){s[i]=[];const a=t.clone().lerp(n,i/r),o=e.clone().lerp(n,i/r),l=r-i;for(let t=0;t<=l;t++)s[i][t]=0===t&&i===r?a:a.clone().lerp(o,t/l)}for(let t=0;t.9&&a<.1&&(e<.2&&(s[t+0]+=1),n<.2&&(s[t+2]+=1),i<.2&&(s[t+4]+=1))}}()}(),this.setAttribute("position",new un(r,3)),this.setAttribute("normal",new un(r.slice(),3)),this.setAttribute("uv",new un(s,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}static fromJSON(t){return new lo(t.vertices,t.indices,t.radius,t.details)}}class co extends lo{constructor(t=1,e=0){const n=(1+Math.sqrt(5))/2,i=1/n;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-n,0,-i,n,0,i,-n,0,i,n,-i,-n,0,-i,n,0,i,-n,0,i,n,0,-n,0,-i,n,0,-i,-n,0,i,n,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}static fromJSON(t){return new co(t.radius,t.detail)}}const ho=new Rt,uo=new Rt,po=new Rt,mo=new ke;class fo extends wn{constructor(t,e){if(super(),this.type="EdgesGeometry",this.parameters={thresholdAngle:e},e=void 0!==e?e:1,!0===t.isGeometry)return void console.error("THREE.EdgesGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.");const n=Math.pow(10,4),i=Math.cos(ot*e),r=t.getIndex(),s=t.getAttribute("position"),a=r?r.count:s.count,o=[0,0,0],l=["a","b","c"],c=new Array(3),h={},u=[];for(let t=0;t0)){l=i;break}l=i-1}if(i=l,n[i]===s)return i/(r-1);const c=n[i];return(i+(s-c)/(n[i+1]-c))/(r-1)}getTangent(t,e){const n=1e-4;let i=t-n,r=t+n;i<0&&(i=0),r>1&&(r=1);const s=this.getPoint(i),a=this.getPoint(r),o=e||(s.isVector2?new vt:new Rt);return o.copy(a).sub(s).normalize(),o}getTangentAt(t,e){const n=this.getUtoTmapping(t);return this.getTangent(n,e)}computeFrenetFrames(t,e){const n=new Rt,i=[],r=[],s=[],a=new Rt,o=new ae;for(let e=0;e<=t;e++){const n=e/t;i[e]=this.getTangentAt(n,new Rt),i[e].normalize()}r[0]=new Rt,s[0]=new Rt;let l=Number.MAX_VALUE;const c=Math.abs(i[0].x),h=Math.abs(i[0].y),u=Math.abs(i[0].z);c<=l&&(l=c,n.set(1,0,0)),h<=l&&(l=h,n.set(0,1,0)),u<=l&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),s[0].crossVectors(i[0],r[0]);for(let e=1;e<=t;e++){if(r[e]=r[e-1].clone(),s[e]=s[e-1].clone(),a.crossVectors(i[e-1],i[e]),a.length()>Number.EPSILON){a.normalize();const t=Math.acos(ht(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(o.makeRotationAxis(a,t))}s[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(ht(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(a.crossVectors(r[0],r[t]))>0&&(e=-e);for(let n=1;n<=t;n++)r[n].applyMatrix4(o.makeRotationAxis(i[n],e*n)),s[n].crossVectors(i[n],r[n])}return{tangents:i,normals:r,binormals:s}}clone(){return(new this.constructor).copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.5,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class vo extends go{constructor(t=0,e=0,n=1,i=1,r=0,s=2*Math.PI,a=!1,o=0){super(),this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=s,this.aClockwise=a,this.aRotation=o}getPoint(t,e){const n=e||new vt,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const s=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(l)/r)+1)*r:0===c&&l===r-1&&(l=r-2,c=1),this.closed||l>0?a=i[(l-1)%r]:(_o.subVectors(i[0],i[1]).add(i[0]),a=_o);const h=i[l%r],u=i[(l+1)%r];if(this.closed||l+2i.length-2?i.length-1:s+1],h=i[s>i.length-3?i.length-1:s+2];return n.set(To(a,o.x,l.x,c.x,h.x),To(a,o.y,l.y,c.y,h.y)),n}copy(t){super.copy(t),this.points=[];for(let e=0,n=t.points.length;e80*n){o=c=t[0],l=h=t[1];for(let e=n;ec&&(c=u),d>h&&(h=d);p=Math.max(c-o,h-l),p=0!==p?1/p:0}return Uo(s,a,n,o,l,p),a};function Fo(t,e,n,i,r){let s,a;if(r===function(t,e,n,i){let r=0;for(let s=e,a=n-i;s0)for(s=e;s=e;s-=i)a=rl(s,t[s],t[s+1],a);return a&&Ko(a,a.next)&&(sl(a),a=a.next),a}function Oo(t,e){if(!t)return t;e||(e=t);let n,i=t;do{if(n=!1,i.steiner||!Ko(i,i.next)&&0!==Qo(i.prev,i,i.next))i=i.next;else{if(sl(i),i=e=i.prev,i===i.next)break;n=!0}}while(n||i!==e);return e}function Uo(t,e,n,i,r,s,a){if(!t)return;!a&&s&&function(t,e,n,i){let r=t;do{null===r.z&&(r.z=Xo(r.x,r.y,e,n,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==t);r.prevZ.nextZ=null,r.prevZ=null,function(t){let e,n,i,r,s,a,o,l,c=1;do{for(n=t,t=null,s=null,a=0;n;){for(a++,i=n,o=0,e=0;e0||l>0&&i;)0!==o&&(0===l||!i||n.z<=i.z)?(r=n,n=n.nextZ,o--):(r=i,i=i.nextZ,l--),s?s.nextZ=r:t=r,r.prevZ=s,s=r;n=i}s.nextZ=null,c*=2}while(a>1)}(r)}(t,i,r,s);let o,l,c=t;for(;t.prev!==t.next;)if(o=t.prev,l=t.next,s?Go(t,i,r,s):Ho(t))e.push(o.i/n),e.push(t.i/n),e.push(l.i/n),sl(t),t=l.next,c=l.next;else if((t=l)===c){a?1===a?Uo(t=ko(Oo(t),e,n),e,n,i,r,s,2):2===a&&Vo(t,e,n,i,r,s):Uo(Oo(t),e,n,i,r,s,1);break}}function Ho(t){const e=t.prev,n=t,i=t.next;if(Qo(e,n,i)>=0)return!1;let r=t.next.next;for(;r!==t.prev;){if(Jo(e.x,e.y,n.x,n.y,i.x,i.y,r.x,r.y)&&Qo(r.prev,r,r.next)>=0)return!1;r=r.next}return!0}function Go(t,e,n,i){const r=t.prev,s=t,a=t.next;if(Qo(r,s,a)>=0)return!1;const o=r.xs.x?r.x>a.x?r.x:a.x:s.x>a.x?s.x:a.x,h=r.y>s.y?r.y>a.y?r.y:a.y:s.y>a.y?s.y:a.y,u=Xo(o,l,e,n,i),d=Xo(c,h,e,n,i);let p=t.prevZ,m=t.nextZ;for(;p&&p.z>=u&&m&&m.z<=d;){if(p!==t.prev&&p!==t.next&&Jo(r.x,r.y,s.x,s.y,a.x,a.y,p.x,p.y)&&Qo(p.prev,p,p.next)>=0)return!1;if(p=p.prevZ,m!==t.prev&&m!==t.next&&Jo(r.x,r.y,s.x,s.y,a.x,a.y,m.x,m.y)&&Qo(m.prev,m,m.next)>=0)return!1;m=m.nextZ}for(;p&&p.z>=u;){if(p!==t.prev&&p!==t.next&&Jo(r.x,r.y,s.x,s.y,a.x,a.y,p.x,p.y)&&Qo(p.prev,p,p.next)>=0)return!1;p=p.prevZ}for(;m&&m.z<=d;){if(m!==t.prev&&m!==t.next&&Jo(r.x,r.y,s.x,s.y,a.x,a.y,m.x,m.y)&&Qo(m.prev,m,m.next)>=0)return!1;m=m.nextZ}return!0}function ko(t,e,n){let i=t;do{const r=i.prev,s=i.next.next;!Ko(r,s)&&$o(r,i,i.next,s)&&nl(r,s)&&nl(s,r)&&(e.push(r.i/n),e.push(i.i/n),e.push(s.i/n),sl(i),sl(i.next),i=t=s),i=i.next}while(i!==t);return Oo(i)}function Vo(t,e,n,i,r,s){let a=t;do{let t=a.next.next;for(;t!==a.prev;){if(a.i!==t.i&&Zo(a,t)){let o=il(a,t);return a=Oo(a,a.next),o=Oo(o,o.next),Uo(a,e,n,i,r,s),void Uo(o,e,n,i,r,s)}t=t.next}a=a.next}while(a!==t)}function Wo(t,e){return t.x-e.x}function jo(t,e){if(e=function(t,e){let n=e;const i=t.x,r=t.y;let s,a=-1/0;do{if(r<=n.y&&r>=n.next.y&&n.next.y!==n.y){const t=n.x+(r-n.y)*(n.next.x-n.x)/(n.next.y-n.y);if(t<=i&&t>a){if(a=t,t===i){if(r===n.y)return n;if(r===n.next.y)return n.next}s=n.x=n.x&&n.x>=l&&i!==n.x&&Jo(rs.x||n.x===s.x&&qo(s,n)))&&(s=n,u=h)),n=n.next}while(n!==o);return s}(t,e)){const n=il(e,t);Oo(e,e.next),Oo(n,n.next)}}function qo(t,e){return Qo(t.prev,t,e.prev)<0&&Qo(e.next,t,t.next)<0}function Xo(t,e,n,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=32767*(t-n)*r)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=32767*(e-i)*r)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function Yo(t){let e=t,n=t;do{(e.x=0&&(t-a)*(i-o)-(n-a)*(e-o)>=0&&(n-a)*(s-o)-(r-a)*(i-o)>=0}function Zo(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let n=t;do{if(n.i!==t.i&&n.next.i!==t.i&&n.i!==e.i&&n.next.i!==e.i&&$o(n,n.next,t,e))return!0;n=n.next}while(n!==t);return!1}(t,e)&&(nl(t,e)&&nl(e,t)&&function(t,e){let n=t,i=!1;const r=(t.x+e.x)/2,s=(t.y+e.y)/2;do{n.y>s!=n.next.y>s&&n.next.y!==n.y&&r<(n.next.x-n.x)*(s-n.y)/(n.next.y-n.y)+n.x&&(i=!i),n=n.next}while(n!==t);return i}(t,e)&&(Qo(t.prev,t,e.prev)||Qo(t,e.prev,e))||Ko(t,e)&&Qo(t.prev,t,t.next)>0&&Qo(e.prev,e,e.next)>0)}function Qo(t,e,n){return(e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y)}function Ko(t,e){return t.x===e.x&&t.y===e.y}function $o(t,e,n,i){const r=el(Qo(t,e,n)),s=el(Qo(t,e,i)),a=el(Qo(n,i,t)),o=el(Qo(n,i,e));return r!==s&&a!==o||(!(0!==r||!tl(t,n,e))||(!(0!==s||!tl(t,i,e))||(!(0!==a||!tl(n,t,i))||!(0!==o||!tl(n,e,i)))))}function tl(t,e,n){return e.x<=Math.max(t.x,n.x)&&e.x>=Math.min(t.x,n.x)&&e.y<=Math.max(t.y,n.y)&&e.y>=Math.min(t.y,n.y)}function el(t){return t>0?1:t<0?-1:0}function nl(t,e){return Qo(t.prev,t,t.next)<0?Qo(t,e,t.next)>=0&&Qo(t,t.prev,e)>=0:Qo(t,e,t.prev)<0||Qo(t,t.next,e)<0}function il(t,e){const n=new al(t.i,t.x,t.y),i=new al(e.i,e.x,e.y),r=t.next,s=e.prev;return t.next=e,e.prev=t,n.next=r,r.prev=n,i.next=n,n.prev=i,s.next=i,i.prev=s,i}function rl(t,e,n,i){const r=new al(t,e,n);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function sl(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function al(t,e,n){this.i=t,this.x=e,this.y=n,this.prev=null,this.next=null,this.z=null,this.prevZ=null,this.nextZ=null,this.steiner=!1}class ol{static area(t){const e=t.length;let n=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function cl(t,e){for(let n=0;nNumber.EPSILON){const u=Math.sqrt(h),d=Math.sqrt(l*l+c*c),p=e.x-o/u,m=e.y+a/u,f=((n.x-c/d-p)*c-(n.y+l/d-m)*l)/(a*c-o*l);i=p+a*f-t.x,r=m+o*f-t.y;const g=i*i+r*r;if(g<=2)return new vt(i,r);s=Math.sqrt(g/2)}else{let t=!1;a>Number.EPSILON?l>Number.EPSILON&&(t=!0):a<-Number.EPSILON?l<-Number.EPSILON&&(t=!0):Math.sign(o)===Math.sign(c)&&(t=!0),t?(i=-o,r=a,s=Math.sqrt(h)):(i=a,r=o,s=Math.sqrt(h/2))}return new vt(i/s,r/s)}const P=[];for(let t=0,e=E.length,n=e-1,i=t+1;t=0;t--){const e=t/p,n=h*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=E.length;t=0;){const i=n;let r=n-1;r<0&&(r=t.length-1);for(let t=0,n=o+2*p;t=0?(t(i-o,p,h),u.subVectors(c,h)):(t(i+o,p,h),u.subVectors(h,c)),p-o>=0?(t(i,p-o,h),d.subVectors(c,h)):(t(i,p+o,h),d.subVectors(h,c)),l.crossVectors(u,d).normalize(),s.push(l.x,l.y,l.z),a.push(i,p)}}for(let t=0;t0)&&d.push(e,r,l),(t!==n-1||o0!=t>0&&this.version++,this._clearcoat=t}get transmission(){return this._transmission}set transmission(t){this._transmission>0!=t>0&&this.version++,this._transmission=t}copy(t){return super.copy(t),this.defines={STANDARD:"",PHYSICAL:""},this.clearcoat=t.clearcoat,this.clearcoatMap=t.clearcoatMap,this.clearcoatRoughness=t.clearcoatRoughness,this.clearcoatRoughnessMap=t.clearcoatRoughnessMap,this.clearcoatNormalMap=t.clearcoatNormalMap,this.clearcoatNormalScale.copy(t.clearcoatNormalScale),this.ior=t.ior,this.sheenTint.copy(t.sheenTint),this.sheenRoughness=t.sheenRoughness,this.transmission=t.transmission,this.transmissionMap=t.transmissionMap,this.thickness=t.thickness,this.thicknessMap=t.thicknessMap,this.attenuationDistance=t.attenuationDistance,this.attenuationTint.copy(t.attenuationTint),this.specularIntensity=t.specularIntensity,this.specularIntensityMap=t.specularIntensityMap,this.specularTint.copy(t.specularTint),this.specularTintMap=t.specularTintMap,this}}Rl.prototype.isMeshPhysicalMaterial=!0;class Cl extends We{constructor(t){super(),this.type="MeshPhongMaterial",this.color=new Qe(16777215),this.specular=new Qe(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Qe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new vt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.specular.copy(t.specular),this.shininess=t.shininess,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this}}Cl.prototype.isMeshPhongMaterial=!0;class Pl extends We{constructor(t){super(),this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Qe(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Qe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new vt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.gradientMap=t.gradientMap,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this}}Pl.prototype.isMeshToonMaterial=!0;class Il extends We{constructor(t){super(),this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new vt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.fog=!1,this.flatShading=!1,this.setValues(t)}copy(t){return super.copy(t),this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.flatShading=t.flatShading,this}}Il.prototype.isMeshNormalMaterial=!0;class Dl extends We{constructor(t){super(),this.type="MeshLambertMaterial",this.color=new Qe(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Qe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this}}Dl.prototype.isMeshLambertMaterial=!0;class Nl extends We{constructor(t){super(),this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Qe(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new vt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.flatShading=!1,this.setValues(t)}copy(t){return super.copy(t),this.defines={MATCAP:""},this.color.copy(t.color),this.matcap=t.matcap,this.map=t.map,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.flatShading=t.flatShading,this}}Nl.prototype.isMeshMatcapMaterial=!0;class zl extends Fa{constructor(t){super(),this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(t)}copy(t){return super.copy(t),this.scale=t.scale,this.dashSize=t.dashSize,this.gapSize=t.gapSize,this}}zl.prototype.isLineDashedMaterial=!0;var Bl=Object.freeze({__proto__:null,ShadowMaterial:Al,SpriteMaterial:ea,RawShaderMaterial:_i,ShaderMaterial:Xn,PointsMaterial:Ya,MeshPhysicalMaterial:Rl,MeshStandardMaterial:Ll,MeshPhongMaterial:Cl,MeshToonMaterial:Pl,MeshNormalMaterial:Il,MeshLambertMaterial:Dl,MeshDepthMaterial:zs,MeshDistanceMaterial:Bs,MeshBasicMaterial:Ke,MeshMatcapMaterial:Nl,LineDashedMaterial:zl,LineBasicMaterial:Fa,Material:We});const Fl={arraySlice:function(t,e,n){return Fl.isTypedArray(t)?new t.constructor(t.subarray(e,void 0!==n?n:t.length)):t.slice(e,n)},convertArray:function(t,e,n){return!t||!n&&t.constructor===e?t:"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t)},isTypedArray:function(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)},getKeyframeOrder:function(t){const e=t.length,n=new Array(e);for(let t=0;t!==e;++t)n[t]=t;return n.sort((function(e,n){return t[e]-t[n]})),n},sortedArray:function(t,e,n){const i=t.length,r=new t.constructor(i);for(let s=0,a=0;a!==i;++s){const i=n[s]*e;for(let n=0;n!==e;++n)r[a++]=t[i+n]}return r},flattenJSON:function(t,e,n,i){let r=1,s=t[0];for(;void 0!==s&&void 0===s[i];)s=t[r++];if(void 0===s)return;let a=s[i];if(void 0!==a)if(Array.isArray(a))do{a=s[i],void 0!==a&&(e.push(s.time),n.push.apply(n,a)),s=t[r++]}while(void 0!==s);else if(void 0!==a.toArray)do{a=s[i],void 0!==a&&(e.push(s.time),a.toArray(n,n.length)),s=t[r++]}while(void 0!==s);else do{a=s[i],void 0!==a&&(e.push(s.time),n.push(a)),s=t[r++]}while(void 0!==s)},subclip:function(t,e,n,i,r=30){const s=t.clone();s.name=e;const a=[];for(let t=0;t=i)){l.push(e.times[t]);for(let n=0;ns.tracks[t].times[0]&&(o=s.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*l+o,e=t+l-o;d=Fl.arraySlice(i.values,t,e)}else{const t=i.createInterpolant(),e=o,n=l-o;t.evaluate(s),d=Fl.arraySlice(t.resultBuffer,e,n)}if("quaternion"===r){(new Lt).fromArray(d).normalize().conjugate().toArray(d)}const p=a.times.length;for(let t=0;t=r)break t;{const a=e[1];t=r)break e}s=n,n=0}}for(;n>>1;te;)--s;if(++s,0!==r||s!==i){r>=s&&(s=Math.max(s,1),r=s-1);const t=this.getValueSize();this.times=Fl.arraySlice(n,r,s),this.values=Fl.arraySlice(this.values,r*t,s*t)}return this}validate(){let t=!0;const e=this.getValueSize();e-Math.floor(e)!=0&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),t=!1);const n=this.times,i=this.values,r=n.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),t=!1);let s=null;for(let e=0;e!==r;e++){const i=n[e];if("number"==typeof i&&isNaN(i)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,e,i),t=!1;break}if(null!==s&&s>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,e,i,s),t=!1;break}s=i}if(void 0!==i&&Fl.isTypedArray(i))for(let e=0,n=i.length;e!==n;++e){const n=i[e];if(isNaN(n)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,e,n),t=!1;break}}return t}optimize(){const t=Fl.arraySlice(this.times),e=Fl.arraySlice(this.values),n=this.getValueSize(),i=this.getInterpolation()===G,r=t.length-1;let s=1;for(let a=1;a0){t[s]=t[r];for(let t=r*n,i=s*n,a=0;a!==n;++a)e[i+a]=e[t+a];++s}return s!==t.length?(this.times=Fl.arraySlice(t,0,s),this.values=Fl.arraySlice(e,0,s*n)):(this.times=t,this.values=e),this}clone(){const t=Fl.arraySlice(this.times,0),e=Fl.arraySlice(this.values,0),n=new(0,this.constructor)(this.name,t,e);return n.createInterpolant=this.createInterpolant,n}}kl.prototype.TimeBufferType=Float32Array,kl.prototype.ValueBufferType=Float32Array,kl.prototype.DefaultInterpolation=H;class Vl extends kl{}Vl.prototype.ValueTypeName="bool",Vl.prototype.ValueBufferType=Array,Vl.prototype.DefaultInterpolation=U,Vl.prototype.InterpolantFactoryMethodLinear=void 0,Vl.prototype.InterpolantFactoryMethodSmooth=void 0;class Wl extends kl{}Wl.prototype.ValueTypeName="color";class jl extends kl{}jl.prototype.ValueTypeName="number";class ql extends Ol{constructor(t,e,n,i){super(t,e,n,i)}interpolate_(t,e,n,i){const r=this.resultBuffer,s=this.sampleValues,a=this.valueSize,o=(n-e)/(i-e);let l=t*a;for(let t=l+a;l!==t;l+=4)Lt.slerpFlat(r,0,s,l-a,s,l,o);return r}}class Xl extends kl{InterpolantFactoryMethodLinear(t){return new ql(this.times,this.values,this.getValueSize(),t)}}Xl.prototype.ValueTypeName="quaternion",Xl.prototype.DefaultInterpolation=H,Xl.prototype.InterpolantFactoryMethodSmooth=void 0;class Yl extends kl{}Yl.prototype.ValueTypeName="string",Yl.prototype.ValueBufferType=Array,Yl.prototype.DefaultInterpolation=U,Yl.prototype.InterpolantFactoryMethodLinear=void 0,Yl.prototype.InterpolantFactoryMethodSmooth=void 0;class Jl extends kl{}Jl.prototype.ValueTypeName="vector";class Zl{constructor(t,e=-1,n,i=2500){this.name=t,this.tracks=n,this.duration=e,this.blendMode=i,this.uuid=ct(),this.duration<0&&this.resetDuration()}static parse(t){const e=[],n=t.tracks,i=1/(t.fps||1);for(let t=0,r=n.length;t!==r;++t)e.push(Ql(n[t]).scale(i));const r=new this(t.name,t.duration,e,t.blendMode);return r.uuid=t.uuid,r}static toJSON(t){const e=[],n=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode};for(let t=0,i=n.length;t!==i;++t)e.push(kl.toJSON(n[t]));return i}static CreateFromMorphTargetSequence(t,e,n,i){const r=e.length,s=[];for(let t=0;t1){const t=s[1];let e=i[t];e||(i[t]=e=[]),e.push(n)}}const s=[];for(const t in i)s.push(this.CreateFromMorphTargetSequence(t,i[t],e,n));return s}static parseAnimation(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const n=function(t,e,n,i,r){if(0!==n.length){const s=[],a=[];Fl.flattenJSON(n,s,a,i),0!==s.length&&r.push(new t(e,s,a))}},i=[],r=t.name||"default",s=t.fps||30,a=t.blendMode;let o=t.length||-1;const l=t.hierarchy||[];for(let t=0;t0||0===t.search(/^data\:image\/jpeg/);r.format=i?T:E,r.needsUpdate=!0,void 0!==e&&e(r)}),n,i),r}}class lc extends go{constructor(){super(),this.type="CurvePath",this.curves=[],this.autoClose=!1}add(t){this.curves.push(t)}closePath(){const t=this.curves[0].getPoint(0),e=this.curves[this.curves.length-1].getPoint(1);t.equals(e)||this.curves.push(new Co(e,t))}getPoint(t){const e=t*this.getLength(),n=this.getCurveLengths();let i=0;for(;i=e){const t=n[i]-e,r=this.curves[i],s=r.getLength(),a=0===s?0:1-t/s;return r.getPointAt(a)}i++}return null}getLength(){const t=this.getCurveLengths();return t[t.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const t=[];let e=0;for(let n=0,i=this.curves.length;n1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,n=t.curves.length;e0){const t=l.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(l);const c=l.getPoint(1);return this.currentPoint.copy(c),this}copy(t){return super.copy(t),this.currentPoint.copy(t.currentPoint),this}toJSON(){const t=super.toJSON();return t.currentPoint=this.currentPoint.toArray(),t}fromJSON(t){return super.fromJSON(t),this.currentPoint.fromArray(t.currentPoint),this}}class hc extends cc{constructor(t){super(t),this.uuid=ct(),this.type="Shape",this.holes=[]}getPointsHoles(t){const e=[];for(let n=0,i=this.holes.length;n0:i.vertexColors=t.vertexColors),void 0!==t.uniforms)for(const e in t.uniforms){const r=t.uniforms[e];switch(i.uniforms[e]={},r.type){case"t":i.uniforms[e].value=n(r.value);break;case"c":i.uniforms[e].value=(new Qe).setHex(r.value);break;case"v2":i.uniforms[e].value=(new vt).fromArray(r.value);break;case"v3":i.uniforms[e].value=(new Rt).fromArray(r.value);break;case"v4":i.uniforms[e].value=(new St).fromArray(r.value);break;case"m3":i.uniforms[e].value=(new yt).fromArray(r.value);break;case"m4":i.uniforms[e].value=(new ae).fromArray(r.value);break;default:i.uniforms[e].value=r.value}}if(void 0!==t.defines&&(i.defines=t.defines),void 0!==t.vertexShader&&(i.vertexShader=t.vertexShader),void 0!==t.fragmentShader&&(i.fragmentShader=t.fragmentShader),void 0!==t.extensions)for(const e in t.extensions)i.extensions[e]=t.extensions[e];if(void 0!==t.shading&&(i.flatShading=1===t.shading),void 0!==t.size&&(i.size=t.size),void 0!==t.sizeAttenuation&&(i.sizeAttenuation=t.sizeAttenuation),void 0!==t.map&&(i.map=n(t.map)),void 0!==t.matcap&&(i.matcap=n(t.matcap)),void 0!==t.alphaMap&&(i.alphaMap=n(t.alphaMap)),void 0!==t.bumpMap&&(i.bumpMap=n(t.bumpMap)),void 0!==t.bumpScale&&(i.bumpScale=t.bumpScale),void 0!==t.normalMap&&(i.normalMap=n(t.normalMap)),void 0!==t.normalMapType&&(i.normalMapType=t.normalMapType),void 0!==t.normalScale){let e=t.normalScale;!1===Array.isArray(e)&&(e=[e,e]),i.normalScale=(new vt).fromArray(e)}return void 0!==t.displacementMap&&(i.displacementMap=n(t.displacementMap)),void 0!==t.displacementScale&&(i.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(i.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(i.roughnessMap=n(t.roughnessMap)),void 0!==t.metalnessMap&&(i.metalnessMap=n(t.metalnessMap)),void 0!==t.emissiveMap&&(i.emissiveMap=n(t.emissiveMap)),void 0!==t.emissiveIntensity&&(i.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(i.specularMap=n(t.specularMap)),void 0!==t.specularIntensityMap&&(i.specularIntensityMap=n(t.specularIntensityMap)),void 0!==t.specularTintMap&&(i.specularTintMap=n(t.specularTintMap)),void 0!==t.envMap&&(i.envMap=n(t.envMap)),void 0!==t.envMapIntensity&&(i.envMapIntensity=t.envMapIntensity),void 0!==t.reflectivity&&(i.reflectivity=t.reflectivity),void 0!==t.refractionRatio&&(i.refractionRatio=t.refractionRatio),void 0!==t.lightMap&&(i.lightMap=n(t.lightMap)),void 0!==t.lightMapIntensity&&(i.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(i.aoMap=n(t.aoMap)),void 0!==t.aoMapIntensity&&(i.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(i.gradientMap=n(t.gradientMap)),void 0!==t.clearcoatMap&&(i.clearcoatMap=n(t.clearcoatMap)),void 0!==t.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=n(t.clearcoatRoughnessMap)),void 0!==t.clearcoatNormalMap&&(i.clearcoatNormalMap=n(t.clearcoatNormalMap)),void 0!==t.clearcoatNormalScale&&(i.clearcoatNormalScale=(new vt).fromArray(t.clearcoatNormalScale)),void 0!==t.transmissionMap&&(i.transmissionMap=n(t.transmissionMap)),void 0!==t.thicknessMap&&(i.thicknessMap=n(t.thicknessMap)),i}setTextures(t){return this.textures=t,this}}class Pc{static decodeText(t){if("undefined"!=typeof TextDecoder)return(new TextDecoder).decode(t);let e="";for(let n=0,i=t.length;nNumber.EPSILON){if(l<0&&(n=e[s],o=-o,a=e[r],l=-l),t.ya.y)continue;if(t.y===n.y){if(t.x===n.x)return!0}else{const e=l*(t.x-n.x)-o*(t.y-n.y);if(0===e)return!0;if(e<0)continue;i=!i}}else{if(t.y!==n.y)continue;if(a.x<=t.x&&t.x<=n.x||n.x<=t.x&&t.x<=a.x)return!0}}return i}const r=ol.isClockWise,s=this.subPaths;if(0===s.length)return[];if(!0===e)return n(s);let a,o,l;const c=[];if(1===s.length)return o=s[0],l=new hc,l.curves=o.curves,c.push(l),c;let h=!r(s[0].getPoints());h=t?!h:h;const u=[],d=[];let p,m,f=[],g=0;d[g]=void 0,f[g]=[];for(let e=0,n=s.length;e1){let t=!1;const e=[];for(let t=0,e=d.length;t0&&(t||(f=u))}for(let t=0,e=d.length;t0){this.source.connect(this.filters[0]);for(let t=1,e=this.filters.length;t0){this.source.disconnect(this.filters[0]);for(let t=1,e=this.filters.length;t0&&this._mixBufferRegionAdditive(n,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(n[t]!==n[t+e]){a.setValue(n,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,n=this.valueSize,i=n*this._origIndex;t.getValue(e,i);for(let t=n,r=i;t!==r;++t)e[t]=e[i+t%n];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const t=3*this.valueSize;this.binding.setValue(this.buffer,t)}_setAdditiveIdentityNumeric(){const t=this._addIndex*this.valueSize,e=t+this.valueSize;for(let n=t;n=.5)for(let i=0;i!==r;++i)t[e+i]=t[n+i]}_slerp(t,e,n,i){Lt.slerpFlat(t,e,t,e,t,n,i)}_slerpAdditive(t,e,n,i,r){const s=this._workIndex*r;Lt.multiplyQuaternionsFlat(t,s,t,e,t,n),Lt.slerpFlat(t,e,t,e,t,s,i)}_lerp(t,e,n,i,r){const s=1-i;for(let a=0;a!==r;++a){const r=e+a;t[r]=t[r]*s+t[n+a]*i}}_lerpAdditive(t,e,n,i,r){for(let s=0;s!==r;++s){const r=e+s;t[r]=t[r]+t[n+s]*i}}}const oh="\\[\\]\\.:\\/",lh=new RegExp("[\\[\\]\\.:\\/]","g"),ch="[^\\[\\]\\.:\\/]",hh="[^"+oh.replace("\\.","")+"]",uh=/((?:WC+[\/:])*)/.source.replace("WC",ch),dh=/(WCOD+)?/.source.replace("WCOD",hh),ph=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",ch),mh=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",ch),fh=new RegExp("^"+uh+dh+ph+mh+"$"),gh=["material","materials","bones"];class vh{constructor(t,e,n){this.path=e,this.parsedPath=n||vh.parseTrackName(e),this.node=vh.findNode(t,this.parsedPath.nodeName)||t,this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,n){return t&&t.isAnimationObjectGroup?new vh.Composite(t,e,n):new vh(t,e,n)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(lh,"")}static parseTrackName(t){const e=fh.exec(t);if(!e)throw new Error("PropertyBinding: Cannot parse trackName: "+t);const n={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=n.nodeName&&n.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=n.nodeName.substring(i+1);-1!==gh.indexOf(t)&&(n.nodeName=n.nodeName.substring(0,i),n.objectName=t)}if(null===n.propertyName||0===n.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+t);return n}static findNode(t,e){if(!e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const n=t.skeleton.getBoneByName(e);if(void 0!==n)return n}if(t.children){const n=function(t){for(let i=0;i=r){const s=r++,c=t[s];e[c.uuid]=l,t[l]=c,e[o]=s,t[s]=a;for(let t=0,e=i;t!==e;++t){const e=n[t],i=e[s],r=e[l];e[l]=i,e[s]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,n=this._bindings,i=n.length;let r=this.nCachedObjects_,s=t.length;for(let a=0,o=arguments.length;a!==o;++a){const o=arguments[a].uuid,l=e[o];if(void 0!==l)if(delete e[o],l0&&(e[a.uuid]=l),t[l]=a,t.pop();for(let t=0,e=i;t!==e;++t){const e=n[t];e[l]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const n=this._bindingsIndicesByPath;let i=n[t];const r=this._bindings;if(void 0!==i)return r[i];const s=this._paths,a=this._parsedPaths,o=this._objects,l=o.length,c=this.nCachedObjects_,h=new Array(l);i=r.length,n[t]=i,s.push(t),a.push(e),r.push(h);for(let n=c,i=o.length;n!==i;++n){const i=o[n];h[n]=new vh(i,t,e)}return h}unsubscribe_(t){const e=this._bindingsIndicesByPath,n=e[t];if(void 0!==n){const i=this._paths,r=this._parsedPaths,s=this._bindings,a=s.length-1,o=s[a];e[t[a]]=n,s[n]=o,s.pop(),r[n]=r[a],r.pop(),i[n]=i[a],i.pop()}}}yh.prototype.isAnimationObjectGroup=!0;class xh{constructor(t,e,n=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=n,this.blendMode=i;const r=e.tracks,s=r.length,a=new Array(s),o={endingStart:k,endingEnd:k};for(let t=0;t!==s;++t){const e=r[t].createInterpolant(null);a[t]=e,e.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(s),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(t){return this._startTime=t,this}setLoop(t,e){return this.loop=t,this.repetitions=e,this}setEffectiveWeight(t){return this.weight=t,this._effectiveWeight=this.enabled?t:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(t){return this._scheduleFading(t,0,1)}fadeOut(t){return this._scheduleFading(t,1,0)}crossFadeFrom(t,e,n){if(t.fadeOut(e),this.fadeIn(e),n){const n=this._clip.duration,i=t._clip.duration,r=i/n,s=n/i;t.warp(1,r,e),this.warp(s,1,e)}return this}crossFadeTo(t,e,n){return t.crossFadeFrom(this,e,n)}stopFading(){const t=this._weightInterpolant;return null!==t&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}setEffectiveTimeScale(t){return this.timeScale=t,this._effectiveTimeScale=this.paused?0:t,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(t){return this.timeScale=this._clip.duration/t,this.stopWarping()}syncWith(t){return this.time=t.time,this.timeScale=t.timeScale,this.stopWarping()}halt(t){return this.warp(this._effectiveTimeScale,0,t)}warp(t,e,n){const i=this._mixer,r=i.time,s=this.timeScale;let a=this._timeScaleInterpolant;null===a&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const o=a.parameterPositions,l=a.sampleValues;return o[0]=r,o[1]=r+n,l[0]=t/s,l[1]=e/s,this}stopWarping(){const t=this._timeScaleInterpolant;return null!==t&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(t,e,n,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*n;if(i<0||0===n)return;this._startTime=null,e=n*i}e*=this._updateTimeScale(t);const s=this._updateTime(e),a=this._updateWeight(t);if(a>0){const t=this._interpolants,e=this._propertyBindings;switch(this.blendMode){case q:for(let n=0,i=t.length;n!==i;++n)t[n].evaluate(s),e[n].accumulateAdditive(a);break;case j:default:for(let n=0,r=t.length;n!==r;++n)t[n].evaluate(s),e[n].accumulate(i,a)}}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const n=this._weightInterpolant;if(null!==n){const i=n.evaluate(t)[0];e*=i,t>n.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=e,e}_updateTimeScale(t){let e=0;if(!this.paused){e=this.timeScale;const n=this._timeScaleInterpolant;if(null!==n){e*=n.evaluate(t)[0],t>n.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e)}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,n=this.loop;let i=this.time+t,r=this._loopCount;const s=2202===n;if(0===t)return-1===r?i:s&&1==(1&r)?e-i:i;if(2200===n){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));t:{if(i>=e)i=e;else{if(!(i<0)){this.time=i;break t}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t<0?-1:1})}}else{if(-1===r&&(t>=0?(r=0,this._setEndings(!0,0===this.repetitions,s)):this._setEndings(0===this.repetitions,!0,s)),i>=e||i<0){const n=Math.floor(i/e);i-=e*n,r+=Math.abs(n);const a=this.repetitions-r;if(a<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=t>0?e:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t>0?1:-1});else{if(1===a){const e=t<0;this._setEndings(e,!e,s)}else this._setEndings(!1,!1,s);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:n})}}else this.time=i;if(s&&1==(1&r))return e-i}return i}_setEndings(t,e,n){const i=this._interpolantSettings;n?(i.endingStart=V,i.endingEnd=V):(i.endingStart=t?this.zeroSlopeAtStart?V:k:W,i.endingEnd=e?this.zeroSlopeAtEnd?V:k:W)}_scheduleFading(t,e,n){const i=this._mixer,r=i.time;let s=this._weightInterpolant;null===s&&(s=i._lendControlInterpolant(),this._weightInterpolant=s);const a=s.parameterPositions,o=s.sampleValues;return a[0]=r,o[0]=e,a[1]=r+t,o[1]=n,this}}class _h extends rt{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(t,e){const n=t._localRoot||this._root,i=t._clip.tracks,r=i.length,s=t._propertyBindings,a=t._interpolants,o=n.uuid,l=this._bindingsByRootAndName;let c=l[o];void 0===c&&(c={},l[o]=c);for(let t=0;t!==r;++t){const r=i[t],l=r.name;let h=c[l];if(void 0!==h)s[t]=h;else{if(h=s[t],void 0!==h){null===h._cacheIndex&&(++h.referenceCount,this._addInactiveBinding(h,o,l));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;h=new ah(vh.create(n,l,i),r.ValueTypeName,r.getValueSize()),++h.referenceCount,this._addInactiveBinding(h,o,l),s[t]=h}a[t].resultBuffer=h.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,n=t._clip.uuid,i=this._actionsByClip[n];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,n,e)}const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==n.useCount++&&(this._lendBinding(n),n.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,n=e.length;t!==n;++t){const n=e[t];0==--n.useCount&&(n.restoreOriginalState(),this._takeBackBinding(n))}this._takeBackAction(t)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const t=this;this.stats={actions:{get total(){return t._actions.length},get inUse(){return t._nActiveActions}},bindings:{get total(){return t._bindings.length},get inUse(){return t._nActiveBindings}},controlInterpolants:{get total(){return t._controlInterpolants.length},get inUse(){return t._nActiveControlInterpolants}}}}_isActiveAction(t){const e=t._cacheIndex;return null!==e&&e=0;--e)t[e].stop();return this}update(t){t*=this.timeScale;const e=this._actions,n=this._nActiveActions,i=this.time+=t,r=Math.sign(t),s=this._accuIndex^=1;for(let a=0;a!==n;++a){e[a]._update(i,t,r,s)}const a=this._bindings,o=this._nActiveBindings;for(let t=0;t!==o;++t)a[t].apply(s);return this}setTime(t){this.time=0;for(let t=0;tthis.max.x||t.ythis.max.y)}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(t){return!(t.max.xthis.max.x||t.max.ythis.max.y)}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return Eh.copy(t).clamp(this.min,this.max).sub(t).length()}intersect(t){return this.min.max(t.min),this.max.min(t.max),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}Ah.prototype.isBox2=!0;const Lh=new Rt,Rh=new Rt;class Ch{constructor(t=new Rt,e=new Rt){this.start=t,this.end=e}set(t,e){return this.start.copy(t),this.end.copy(e),this}copy(t){return this.start.copy(t.start),this.end.copy(t.end),this}getCenter(t){return t.addVectors(this.start,this.end).multiplyScalar(.5)}delta(t){return t.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(t,e){return this.delta(e).multiplyScalar(t).add(this.start)}closestPointToPointParameter(t,e){Lh.subVectors(t,this.start),Rh.subVectors(this.end,this.start);const n=Rh.dot(Rh);let i=Rh.dot(Lh)/n;return e&&(i=ht(i,0,1)),i}closestPointToPoint(t,e,n){const i=this.closestPointToPointParameter(t,e);return this.delta(n).multiplyScalar(i).add(this.start)}applyMatrix4(t){return this.start.applyMatrix4(t),this.end.applyMatrix4(t),this}equals(t){return t.start.equals(this.start)&&t.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}class Ph extends Pe{constructor(t){super(),this.material=t,this.render=function(){},this.hasPositions=!1,this.hasNormals=!1,this.hasColors=!1,this.hasUvs=!1,this.positionArray=null,this.normalArray=null,this.colorArray=null,this.uvArray=null,this.count=0}}Ph.prototype.isImmediateRenderObject=!0;const Ih=new Rt;const Dh=new Rt,Nh=new ae,zh=new ae;class Bh extends qa{constructor(t){const e=Fh(t),n=new wn,i=[],r=[],s=new Qe(0,0,1),a=new Qe(0,1,0);for(let t=0;t.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{Zh.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(Zh,e)}}setLength(t,e=.2*t,n=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(n,e,n),this.cone.position.y=t,this.cone.updateMatrix()}setColor(t){this.line.material.color.set(t),this.cone.material.color.set(t)}copy(t){return super.copy(t,!1),this.line.copy(t.line),this.cone.copy(t.cone),this}},t.Audio=th,t.AudioAnalyser=sh,t.AudioContext=kc,t.AudioListener=class extends Pe{constructor(){super(),this.type="AudioListener",this.context=kc.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Yc}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(t){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=t,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(t){return this.gain.gain.setTargetAtTime(t,this.context.currentTime,.01),this}updateMatrixWorld(t){super.updateMatrixWorld(t);const e=this.context.listener,n=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Zc,Qc,Kc),$c.set(0,0,-1).applyQuaternion(Qc),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(Zc.x,t),e.positionY.linearRampToValueAtTime(Zc.y,t),e.positionZ.linearRampToValueAtTime(Zc.z,t),e.forwardX.linearRampToValueAtTime($c.x,t),e.forwardY.linearRampToValueAtTime($c.y,t),e.forwardZ.linearRampToValueAtTime($c.z,t),e.upX.linearRampToValueAtTime(n.x,t),e.upY.linearRampToValueAtTime(n.y,t),e.upZ.linearRampToValueAtTime(n.z,t)}else e.setPosition(Zc.x,Zc.y,Zc.z),e.setOrientation($c.x,$c.y,$c.z,n.x,n.y,n.z)}},t.AudioLoader=Vc,t.AxesHelper=$h,t.AxisHelper=function(t){return console.warn("THREE.AxisHelper has been renamed to THREE.AxesHelper."),new $h(t)},t.BackSide=1,t.BasicDepthPacking=3200,t.BasicShadowMap=0,t.BinaryTextureLoader=function(t){return console.warn("THREE.BinaryTextureLoader has been renamed to THREE.DataTextureLoader."),new ac(t)},t.Bone=Ea,t.BooleanKeyframeTrack=Vl,t.BoundingBoxHelper=function(t,e){return console.warn("THREE.BoundingBoxHelper has been deprecated. Creating a THREE.BoxHelper instead."),new Jh(t,e)},t.Box2=Ah,t.Box3=It,t.Box3Helper=class extends qa{constructor(t,e=16776960){const n=new Uint16Array([0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7]),i=new wn;i.setIndex(new en(n,1)),i.setAttribute("position",new un([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)),super(i,new Fa({color:e,toneMapped:!1})),this.box=t,this.type="Box3Helper",this.geometry.computeBoundingSphere()}updateMatrixWorld(t){const e=this.box;e.isEmpty()||(e.getCenter(this.position),e.getSize(this.scale),this.scale.multiplyScalar(.5),super.updateMatrixWorld(t))}},t.BoxBufferGeometry=Vn,t.BoxGeometry=Vn,t.BoxHelper=Jh,t.BufferAttribute=en,t.BufferGeometry=wn,t.BufferGeometryLoader=Dc,t.ByteType=1010,t.Cache=Kl,t.Camera=Yn,t.CameraHelper=class extends qa{constructor(t){const e=new wn,n=new Fa({color:16777215,vertexColors:!0,toneMapped:!1}),i=[],r=[],s={},a=new Qe(16755200),o=new Qe(16711680),l=new Qe(43775),c=new Qe(16777215),h=new Qe(3355443);function u(t,e,n){d(t,n),d(e,n)}function d(t,e){i.push(0,0,0),r.push(e.r,e.g,e.b),void 0===s[t]&&(s[t]=[]),s[t].push(i.length/3-1)}u("n1","n2",a),u("n2","n4",a),u("n4","n3",a),u("n3","n1",a),u("f1","f2",a),u("f2","f4",a),u("f4","f3",a),u("f3","f1",a),u("n1","f1",a),u("n2","f2",a),u("n3","f3",a),u("n4","f4",a),u("p","n1",o),u("p","n2",o),u("p","n3",o),u("p","n4",o),u("u1","u2",l),u("u2","u3",l),u("u3","u1",l),u("c","t",c),u("p","c",h),u("cn1","cn2",h),u("cn3","cn4",h),u("cf1","cf2",h),u("cf3","cf4",h),e.setAttribute("position",new un(i,3)),e.setAttribute("color",new un(r,3)),super(e,n),this.type="CameraHelper",this.camera=t,this.camera.updateProjectionMatrix&&this.camera.updateProjectionMatrix(),this.matrix=t.matrixWorld,this.matrixAutoUpdate=!1,this.pointMap=s,this.update()}update(){const t=this.geometry,e=this.pointMap;qh.projectionMatrixInverse.copy(this.camera.projectionMatrixInverse),Xh("c",e,t,qh,0,0,-1),Xh("t",e,t,qh,0,0,1),Xh("n1",e,t,qh,-1,-1,-1),Xh("n2",e,t,qh,1,-1,-1),Xh("n3",e,t,qh,-1,1,-1),Xh("n4",e,t,qh,1,1,-1),Xh("f1",e,t,qh,-1,-1,1),Xh("f2",e,t,qh,1,-1,1),Xh("f3",e,t,qh,-1,1,1),Xh("f4",e,t,qh,1,1,1),Xh("u1",e,t,qh,.7,1.1,-1),Xh("u2",e,t,qh,-.7,1.1,-1),Xh("u3",e,t,qh,0,2,-1),Xh("cf1",e,t,qh,-1,0,1),Xh("cf2",e,t,qh,1,0,1),Xh("cf3",e,t,qh,0,-1,1),Xh("cf4",e,t,qh,0,1,1),Xh("cn1",e,t,qh,-1,0,-1),Xh("cn2",e,t,qh,1,0,-1),Xh("cn3",e,t,qh,0,-1,-1),Xh("cn4",e,t,qh,0,1,-1),t.getAttribute("position").needsUpdate=!0}dispose(){this.geometry.dispose(),this.material.dispose()}},t.CanvasRenderer=function(){console.error("THREE.CanvasRenderer has been removed")},t.CanvasTexture=io,t.CatmullRomCurve3=So,t.CineonToneMapping=3,t.CircleBufferGeometry=so,t.CircleGeometry=so,t.ClampToEdgeWrapping=u,t.Clock=Yc,t.Color=Qe,t.ColorKeyframeTrack=Wl,t.CompressedTexture=no,t.CompressedTextureLoader=class extends ec{constructor(t){super(t)}load(t,e,n,i){const r=this,s=[],a=new no,o=new ic(this.manager);o.setPath(this.path),o.setResponseType("arraybuffer"),o.setRequestHeader(this.requestHeader),o.setWithCredentials(r.withCredentials);let l=0;function c(c){o.load(t[c],(function(t){const n=r.parse(t,!0);s[c]={width:n.width,height:n.height,format:n.format,mipmaps:n.mipmaps},l+=1,6===l&&(1===n.mipmapCount&&(a.minFilter=g),a.image=s,a.format=n.format,a.needsUpdate=!0,e&&e(a))}),n,i)}if(Array.isArray(t))for(let e=0,n=t.length;e>16&32768,i=e>>12&2047;const r=e>>23&255;return r<103?n:r>142?(n|=31744,n|=(255==r?0:1)&&8388607&e,n):r<113?(i|=2048,n|=(i>>114-r)+(i>>113-r&1),n):(n|=r-112<<10|i>>1,n+=1&i,n)}},t.DecrementStencilOp=7683,t.DecrementWrapStencilOp=34056,t.DefaultLoadingManager=tc,t.DepthFormat=A,t.DepthStencilFormat=L,t.DepthTexture=ro,t.DirectionalLight=Tc,t.DirectionalLightHelper=class extends Pe{constructor(t,e,n){super(),this.light=t,this.light.updateMatrixWorld(),this.matrix=t.matrixWorld,this.matrixAutoUpdate=!1,this.color=n,void 0===e&&(e=1);let i=new wn;i.setAttribute("position",new un([-e,e,0,e,e,0,e,-e,0,-e,-e,0,-e,e,0],3));const r=new Fa({fog:!1,toneMapped:!1});this.lightPlane=new Va(i,r),this.add(this.lightPlane),i=new wn,i.setAttribute("position",new un([0,0,0,0,0,1],3)),this.targetLine=new Va(i,r),this.add(this.targetLine),this.update()}dispose(){this.lightPlane.geometry.dispose(),this.lightPlane.material.dispose(),this.targetLine.geometry.dispose(),this.targetLine.material.dispose()}update(){kh.setFromMatrixPosition(this.light.matrixWorld),Vh.setFromMatrixPosition(this.light.target.matrixWorld),Wh.subVectors(Vh,kh),this.lightPlane.lookAt(Vh),void 0!==this.color?(this.lightPlane.material.color.set(this.color),this.targetLine.material.color.set(this.color)):(this.lightPlane.material.color.copy(this.light.color),this.targetLine.material.color.copy(this.light.color)),this.targetLine.lookAt(Vh),this.targetLine.scale.z=Wh.length()}},t.DiscreteInterpolant=Gl,t.DodecahedronBufferGeometry=co,t.DodecahedronGeometry=co,t.DoubleSide=2,t.DstAlphaFactor=206,t.DstColorFactor=208,t.DynamicBufferAttribute=function(t,e){return console.warn("THREE.DynamicBufferAttribute has been removed. Use new THREE.BufferAttribute().setUsage( THREE.DynamicDrawUsage ) instead."),new en(t,e).setUsage(nt)},t.DynamicCopyUsage=35050,t.DynamicDrawUsage=nt,t.DynamicReadUsage=35049,t.EdgesGeometry=fo,t.EdgesHelper=function(t,e){return console.warn("THREE.EdgesHelper has been removed. Use THREE.EdgesGeometry instead."),new qa(new fo(t.geometry),new Fa({color:void 0!==e?e:16777215}))},t.EllipseCurve=vo,t.EqualDepth=4,t.EqualStencilFunc=514,t.EquirectangularReflectionMapping=a,t.EquirectangularRefractionMapping=o,t.Euler=ge,t.EventDispatcher=rt,t.ExtrudeBufferGeometry=hl,t.ExtrudeGeometry=hl,t.FaceColors=1,t.FileLoader=ic,t.FlatShading=1,t.Float16BufferAttribute=hn,t.Float32Attribute=function(t,e){return console.warn("THREE.Float32Attribute has been removed. Use new THREE.Float32BufferAttribute() instead."),new un(t,e)},t.Float32BufferAttribute=un,t.Float64Attribute=function(t,e){return console.warn("THREE.Float64Attribute has been removed. Use new THREE.Float64BufferAttribute() instead."),new dn(t,e)},t.Float64BufferAttribute=dn,t.FloatType=M,t.Fog=Zs,t.FogExp2=Js,t.Font=Uc,t.FontLoader=class extends ec{constructor(t){super(t)}load(t,e,n,i){const r=this,s=new ic(this.manager);s.setPath(this.path),s.setRequestHeader(this.requestHeader),s.setWithCredentials(r.withCredentials),s.load(t,(function(t){let n;try{n=JSON.parse(t)}catch(e){console.warn("THREE.FontLoader: typeface.js support is being deprecated. Use typeface.json instead."),n=JSON.parse(t.substring(65,t.length-2))}const i=r.parse(n);e&&e(i)}),n,i)}parse(t){return new Uc(t)}},t.FrontSide=0,t.Frustum=ai,t.GLBufferAttribute=wh,t.GLSL1="100",t.GLSL3=it,t.GammaEncoding=J,t.GreaterDepth=6,t.GreaterEqualDepth=5,t.GreaterEqualStencilFunc=518,t.GreaterStencilFunc=516,t.GridHelper=Gh,t.Group=ks,t.HalfFloatType=w,t.HemisphereLight=dc,t.HemisphereLightHelper=class extends Pe{constructor(t,e,n){super(),this.light=t,this.light.updateMatrixWorld(),this.matrix=t.matrixWorld,this.matrixAutoUpdate=!1,this.color=n;const i=new ml(e);i.rotateY(.5*Math.PI),this.material=new Ke({wireframe:!0,fog:!1,toneMapped:!1}),void 0===this.color&&(this.material.vertexColors=!0);const r=i.getAttribute("position"),s=new Float32Array(3*r.count);i.setAttribute("color",new en(s,3)),this.add(new Gn(i,this.material)),this.update()}dispose(){this.children[0].geometry.dispose(),this.children[0].material.dispose()}update(){const t=this.children[0];if(void 0!==this.color)this.material.color.set(this.color);else{const e=t.geometry.getAttribute("color");Uh.copy(this.light.color),Hh.copy(this.light.groundColor);for(let t=0,n=e.count;t0){const n=new $l(e);r=new rc(n),r.setCrossOrigin(this.crossOrigin);for(let e=0,n=t.length;e0){i=new rc(this.manager),i.setCrossOrigin(this.crossOrigin);for(let e=0,i=t.length;e +#endif + +#include +#include + +namespace mikk { + +struct AtomicHashSetLinearProbeFcn { + inline size_t operator()(size_t idx, size_t /* numProbes */, size_t capacity) const + { + idx += 1; // linear probing + + // Avoid modulus because it's slow + return (idx < capacity) ? idx : (idx - capacity); + } +}; + +struct AtomicHashSetQuadraticProbeFcn { + inline size_t operator()(size_t idx, size_t numProbes, size_t capacity) const + { + idx += numProbes; // quadratic probing + + // Avoid modulus because it's slow + return (idx < capacity) ? idx : (idx - capacity); + } +}; + +template, + class KeyEqual = std::equal_to, + class ProbeFcn = AtomicHashSetLinearProbeFcn> +class AtomicHashSet { + static_assert((std::is_convertible::value || + std::is_convertible::value || + std::is_convertible::value), + "You are trying to use AtomicHashSet with disallowed key " + "types. You must use atomically compare-and-swappable integer " + "keys, or a different container class."); + + public: + const size_t capacity_; + const KeyT kEmptyKey_; + + KeyHash hasher_; + KeyEqual equalityChecker_; + + private: + size_t kAnchorMask_; + /* When using a single thread, we can avoid overhead by not bothering with atomic cells. */ + typedef typename std::conditional, KeyT>::type cell_type; + std::vector cells_; + + public: + struct Config { + KeyT emptyKey; + double maxLoadFactor; + double growthFactor; + size_t capacity; // if positive, overrides maxLoadFactor + + // Cannot have constexpr ctor because some compilers rightly complain. + Config() : emptyKey((KeyT)-1), maxLoadFactor(0.8), growthFactor(-1), capacity(0) {} + }; + + /* Instead of a mess of arguments, we take a max size and a Config struct to + * simulate named ctor parameters. The Config struct has sensible defaults + * for everything, but is overloaded - if you specify a positive capacity, + * that will be used directly instead of computing it based on maxLoadFactor. + */ + AtomicHashSet(size_t maxSize, + KeyHash hasher = KeyHash(), + KeyEqual equalityChecker = KeyEqual(), + const Config &c = Config()) + : capacity_(size_t(double(maxSize) / c.maxLoadFactor) + 1), + kEmptyKey_(c.emptyKey), + hasher_(hasher), + equalityChecker_(equalityChecker), + cells_(capacity_) + { + /* Get next power of two. Could be done more effiently with builtin_clz, but this is not + * performance-critical. */ + kAnchorMask_ = 1; + while (kAnchorMask_ < capacity_) { + kAnchorMask_ *= 2; + } + /* Get mask for lower bits. */ + kAnchorMask_ -= 1; + + /* Not great, but the best we can do to support both atomic and non-atomic cells + * since std::atomic doesn't have a copy constructor so cells_(capacity_, kEmptyKey_) + * in the initializer list won't work. */ + std::fill((KeyT *)cells_.data(), (KeyT *)cells_.data() + capacity_, kEmptyKey_); + } + + AtomicHashSet(const AtomicHashSet &) = delete; + AtomicHashSet &operator=(const AtomicHashSet &) = delete; + + ~AtomicHashSet() = default; + + /* Sequential specialization. */ + bool tryUpdateCell(KeyT *cell, KeyT &existingKey, KeyT newKey) + { + if (*cell == existingKey) { + *cell = newKey; + return true; + } + existingKey = *cell; + return false; + } + + /* Atomic specialization. */ + bool tryUpdateCell(std::atomic *cell, KeyT &existingKey, KeyT newKey) + { + return cell->compare_exchange_strong(existingKey, newKey, std::memory_order_acq_rel); + } + + std::pair emplace(KeyT key) + { + size_t idx = keyToAnchorIdx(key); + size_t numProbes = 0; + for (;;) { + cell_type *cell = &cells_[idx]; + KeyT existingKey = kEmptyKey_; + /* Try to replace empty cell with our key. */ + if (tryUpdateCell(cell, existingKey, key)) { + /* Cell was empty, we're done. */ + return std::make_pair(key, true); + } + + /* Cell was not empty, check if the existing key is equal. */ + if (equalityChecker_(existingKey, key)) { + /* Found equal element, we're done. */ + return std::make_pair(existingKey, false); + } + + /* Continue to next cell according to probe strategy. */ + ++numProbes; + if ((numProbes >= capacity_)) { + // probed every cell...fail + assert(false); + return std::make_pair(kEmptyKey_, false); + } + + idx = ProbeFcn()(idx, numProbes, capacity_); + } + } + + private: + inline size_t keyToAnchorIdx(const KeyT k) const + { + const size_t hashVal = hasher_(k); + const size_t probe = hashVal & kAnchorMask_; + return (probe < capacity_) ? probe : hashVal % capacity_; + } + +}; // AtomicHashSet + +} // namespace mikk diff --git a/indra/externals/mikktspace/mikktspace/mikk_float3.hh b/indra/externals/mikktspace/mikktspace/mikk_float3.hh new file mode 100644 index 00000000000..b0b34e9fde3 --- /dev/null +++ b/indra/externals/mikktspace/mikktspace/mikk_float3.hh @@ -0,0 +1,120 @@ +/* SPDX-FileCopyrightText: 2020-2023 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/** \file + * \ingroup mikktspace + */ + +#pragma once + +#include + +namespace mikk { + +struct float3 { + float x, y, z; + + float3() = default; + + float3(const float *ptr) : x{ptr[0]}, y{ptr[1]}, z{ptr[2]} {} + + float3(const float (*ptr)[3]) : float3((const float *)ptr) {} + + explicit float3(float value) : x(value), y(value), z(value) {} + + explicit float3(int value) : x((float)value), y((float)value), z((float)value) {} + + float3(float x_, float y_, float z_) : x{x_}, y{y_}, z{z_} {} + + static float3 zero() + { + return {0.0f, 0.0f, 0.0f}; + } + + friend float3 operator*(const float3 &a, float b) + { + return {a.x * b, a.y * b, a.z * b}; + } + + friend float3 operator*(float b, const float3 &a) + { + return {a.x * b, a.y * b, a.z * b}; + } + + friend float3 operator-(const float3 &a, const float3 &b) + { + return {a.x - b.x, a.y - b.y, a.z - b.z}; + } + + friend float3 operator-(const float3 &a) + { + return {-a.x, -a.y, -a.z}; + } + + friend bool operator==(const float3 &a, const float3 &b) + { + return a.x == b.x && a.y == b.y && a.z == b.z; + } + + float length_squared() const + { + return x * x + y * y + z * z; + } + + float length() const + { + return sqrt(length_squared()); + } + + static float distance(const float3 &a, const float3 &b) + { + return (a - b).length(); + } + + friend float3 operator+(const float3 &a, const float3 &b) + { + return {a.x + b.x, a.y + b.y, a.z + b.z}; + } + + void operator+=(const float3 &b) + { + this->x += b.x; + this->y += b.y; + this->z += b.z; + } + + friend float3 operator*(const float3 &a, const float3 &b) + { + return {a.x * b.x, a.y * b.y, a.z * b.z}; + } + + float3 normalize() const + { + const float len = length(); + return (len != 0.0f) ? *this * (1.0f / len) : *this; + } + + float reduce_add() const + { + return x + y + z; + } +}; + +inline float dot(const float3 &a, const float3 &b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +inline float distance(const float3 &a, const float3 &b) +{ + return float3::distance(a, b); +} + +/* Projects v onto the surface with normal n. */ +inline float3 project(const float3 &n, const float3 &v) +{ + return (v - n * dot(n, v)).normalize(); +} + +} // namespace mikk diff --git a/indra/externals/mikktspace/mikktspace/mikk_util.hh b/indra/externals/mikktspace/mikktspace/mikk_util.hh new file mode 100644 index 00000000000..bff35a3b1af --- /dev/null +++ b/indra/externals/mikktspace/mikktspace/mikk_util.hh @@ -0,0 +1,158 @@ +/* SPDX-FileCopyrightText: 2022-2023 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/** \file + * \ingroup mikktspace + */ + +#pragma once + +#include +#include + +#ifndef M_PI_F +# define M_PI_F (3.1415926535897932f) /* pi */ +#endif + +namespace mikk { + +inline bool not_zero(const float fX) +{ + return fabsf(fX) > FLT_MIN; +} + +/* Helpers for (un)packing a 2-bit vertex index and a 30-bit face index to one integer. */ +static uint pack_index(const uint face, const uint vert) +{ + assert((vert & 0x3) == vert); + return (face << 2) | (vert & 0x3); +} + +static void unpack_index(uint &face, uint &vert, const uint indexIn) +{ + vert = indexIn & 0x3; + face = indexIn >> 2; +} + +/* From intern/cycles/util/math_fast.h */ +inline float fast_acosf(float x) +{ + const float f = fabsf(x); + /* clamp and crush denormals. */ + const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f; + /* Based on http://www.pouet.net/topic.php?which=9132&page=2 + * 85% accurate (ULP 0) + * Examined 2130706434 values of acos: + * 15.2000597 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // without "denormal crush" + * Examined 2130706434 values of acos: + * 15.2007108 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // with "denormal crush" + */ + const float a = sqrtf(1.0f - m) * + (1.5707963267f + m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f))); + return x < 0 ? M_PI_F - a : a; +} + +static uint rotl(uint x, uint k) +{ + return (x << k) | (x >> (32 - k)); +} + +static uint hash_uint3(uint kx, uint ky, uint kz) +{ + uint a, b, c; + a = b = c = 0xdeadbeef + (2 << 2) + 13; + + c += kz; + b += ky; + a += kx; + + c = (c ^ b) - rotl(b, 14); + a = (a ^ c) - rotl(c, 11); + b = (b ^ a) - rotl(a, 25); + c = (c ^ b) - rotl(b, 16); + + return c; +} + +static uint hash_uint3_fast(const uint x, const uint y, const uint z) +{ + return (x * 73856093) ^ (y * 19349663) ^ (z * 83492791); +} + +static uint float_as_uint(const float v) +{ + return *((uint *)(&v)); +} + +static float uint_as_float(const uint v) +{ + return *((float *)(&v)); +} + +static uint hash_float3_fast(const float x, const float y, const float z) +{ + return hash_uint3_fast(float_as_uint(x), float_as_uint(y), float_as_uint(z)); +} + +static uint hash_float3x3(const float3 &x, const float3 &y, const float3 &z) +{ + return hash_uint3(hash_float3_fast(x.x, x.y, x.z), + hash_float3_fast(y.x, y.y, y.z), + hash_float3_fast(z.x, z.y, z.z)); +} + +template +void radixsort(std::vector &data, std::vector &data2, KeyGetter getKey) +{ + typedef decltype(getKey(data[0])) key_t; + constexpr size_t datasize = sizeof(key_t); + static_assert(datasize % 2 == 0); + static_assert(std::is_integral::value); + + uint bins[datasize][257] = {{0}}; + + /* Count number of elements per bin. */ + for (const T &item : data) { + key_t key = getKey(item); + for (uint pass = 0; pass < datasize; pass++) + bins[pass][((key >> (8 * pass)) & 0xff) + 1]++; + } + + /* Compute prefix sum to find position of each bin in the sorted array. */ + for (uint pass = 0; pass < datasize; pass++) { + for (uint i = 2; i < 256; i++) { + bins[pass][i] += bins[pass][i - 1]; + } + } + + int shift = 0; + for (uint pass = 0; pass < datasize; pass++, shift += 8) { + /* Insert the elements in their correct location based on their bin. */ + for (const T &item : data) { + uint pos = bins[pass][(getKey(item) >> shift) & 0xff]++; + data2[pos] = item; + } + + /* Swap arrays. */ + std::swap(data, data2); + } +} + +static void float_add_atomic(float *val, float add) +{ + /* Hacky, but atomic floats are only supported from C++20 onward. + * This works in practice since `std::atomic` is really just an `uint32_t` in memory, + * so this cast lets us do a 32-bit CAS operation (which is used to build the atomic float + * operation) without needing any external libraries or compiler-specific builtins. */ + std::atomic *atomic_val = reinterpret_cast *>(val); + for (;;) { + uint32_t old_v = atomic_val->load(); + uint32_t new_v = float_as_uint(uint_as_float(old_v) + add); + if (atomic_val->compare_exchange_weak(old_v, new_v)) { + return; + } + } +} + +} // namespace mikk diff --git a/indra/externals/mikktspace/mikktspace/mikktspace.hh b/indra/externals/mikktspace/mikktspace/mikktspace.hh new file mode 100644 index 00000000000..9f1761c504c --- /dev/null +++ b/indra/externals/mikktspace/mikktspace/mikktspace.hh @@ -0,0 +1,839 @@ +/* SPDX-FileCopyrightText: 2011 Morten S. Mikkelsen + * SPDX-FileCopyrightText: 2022 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/** \file + * \ingroup mikktspace + */ + +#include +#include +#include +#include + +#ifdef WITH_TBB +# include +#endif + +typedef uint32_t uint; + +#include "mikk_atomic_hash_set.hh" +#include "mikk_float3.hh" +#include "mikk_util.hh" + +namespace mikk { + +static constexpr uint UNSET_ENTRY = 0xffffffffu; + +template class Mikktspace { + struct Triangle { + /* Stores neighboring triangle for group assignment. */ + std::array neighbor; + /* Stores assigned group of each vertex. */ + std::array group; + /* Stores vertex indices that make up the triangle. */ + std::array vertices; + + /* Computed face tangent, will be accumulated into group. */ + float3 tangent; + + /* Index of the face that this triangle belongs to. */ + uint faceIdx; + /* Index of the first of this triangle's vertices' TSpaces. */ + uint tSpaceIdx; + + /* Stores mapping from this triangle's vertices to the original + * face's vertices (relevant for quads). */ + std::array faceVertex; + + // flags + bool markDegenerate : 1; + bool quadOneDegenTri : 1; + bool groupWithAny : 1; + bool orientPreserving : 1; + + Triangle(uint faceIdx_, uint tSpaceIdx_) + : tangent{0.0f}, + faceIdx{faceIdx_}, + tSpaceIdx{tSpaceIdx_}, + markDegenerate{false}, + quadOneDegenTri{false}, + groupWithAny{true}, + orientPreserving{false} + { + neighbor.fill(UNSET_ENTRY); + group.fill(UNSET_ENTRY); + } + + void setVertices(uint8_t i0, uint8_t i1, uint8_t i2) + { + faceVertex[0] = i0; + faceVertex[1] = i1; + faceVertex[2] = i2; + vertices[0] = pack_index(faceIdx, i0); + vertices[1] = pack_index(faceIdx, i1); + vertices[2] = pack_index(faceIdx, i2); + } + }; + + struct Group { + float3 tangent; + uint vertexRepresentative; + bool orientPreserving; + + Group(uint vertexRepresentative_, bool orientPreserving_) + : tangent{0.0f}, + vertexRepresentative{vertexRepresentative_}, + orientPreserving{orientPreserving_} + { + } + + void normalizeTSpace() + { + tangent = tangent.normalize(); + } + + void accumulateTSpaceAtomic(float3 v_tangent) + { + float_add_atomic(&tangent.x, v_tangent.x); + float_add_atomic(&tangent.y, v_tangent.y); + float_add_atomic(&tangent.z, v_tangent.z); + } + + void accumulateTSpace(float3 v_tangent) + { + tangent += v_tangent; + } + }; + + struct TSpace { + float3 tangent = float3(1.0f, 0.0f, 0.0f); + uint counter = 0; + bool orientPreserving = false; + + void accumulateGroup(const Group &group) + { + assert(counter < 2); + + if (counter == 0) { + tangent = group.tangent; + } + else if (tangent == group.tangent) { + // this if is important. Due to floating point precision + // averaging when ts0==ts1 will cause a slight difference + // which results in tangent space splits later on, so do nothing + } + else { + tangent = (tangent + group.tangent).normalize(); + } + + counter++; + orientPreserving = group.orientPreserving; + } + }; + + Mesh &mesh; + + std::vector triangles; + std::vector tSpaces; + std::vector groups; + + uint nrTSpaces, nrFaces, nrTriangles, totalTriangles; + + int nrThreads; + bool isParallel; + + public: + Mikktspace(Mesh &mesh_) : mesh(mesh_) {} + + void genTangSpace() + { + nrFaces = uint(mesh.GetNumFaces()); + +#ifdef WITH_TBB + nrThreads = tbb::this_task_arena::max_concurrency(); + isParallel = (nrThreads > 1) && (nrFaces > 10000); +#else + nrThreads = 1; + isParallel = false; +#endif + + // make an initial triangle --> face index list + generateInitialVerticesIndexList(); + + if (nrTriangles == 0) { + return; + } + + // make a welded index list of identical positions and attributes (pos, norm, texc) + generateSharedVerticesIndexList(); + + // mark all triangle pairs that belong to a quad with only one + // good triangle. These need special treatment in degenEpilogue(). + // Additionally, move all good triangles to the start of + // triangles[] without changing order and + // put the degenerate triangles last. + degenPrologue(); + + if (nrTriangles == 0) { + // No point in building tangents if there are no non-degenerate triangles, so just zero them + tSpaces.resize(nrTSpaces); + } + else { + // evaluate triangle level attributes and neighbor list + initTriangle(); + + // match up edge pairs + buildNeighbors(); + + // based on the 4 rules, identify groups based on connectivity + build4RuleGroups(); + + // make tspaces, each group is split up into subgroups. + // Finally a tangent space is made for every resulting subgroup + generateTSpaces(); + + // degenerate quads with one good triangle will be fixed by copying a space from + // the good triangle to the coinciding vertex. + // all other degenerate triangles will just copy a space from any good triangle + // with the same welded index in vertices[]. + degenEpilogue(); + } + + uint index = 0; + for (uint f = 0; f < nrFaces; f++) { + const uint verts = mesh.GetNumVerticesOfFace(f); + if (verts != 3 && verts != 4) { + continue; + } + + // set data + for (uint i = 0; i < verts; i++) { + const TSpace &tSpace = tSpaces[index++]; + mesh.SetTangentSpace(f, i, tSpace.tangent, tSpace.orientPreserving); + } + } + } + + protected: + template void runParallel(uint start, uint end, F func) + { +#ifdef WITH_TBB + if (isParallel) { + tbb::parallel_for(start, end, func); + } + else +#endif + { + for (uint i = start; i < end; i++) { + func(i); + } + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////// + + float3 getPosition(uint vertexID) + { + uint f, v; + unpack_index(f, v, vertexID); + return mesh.GetPosition(f, v); + } + + float3 getNormal(uint vertexID) + { + uint f, v; + unpack_index(f, v, vertexID); + return mesh.GetNormal(f, v); + } + + float3 getTexCoord(uint vertexID) + { + uint f, v; + unpack_index(f, v, vertexID); + return mesh.GetTexCoord(f, v); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////// + + void generateInitialVerticesIndexList() + { + nrTriangles = 0; + for (uint f = 0; f < nrFaces; f++) { + const uint verts = mesh.GetNumVerticesOfFace(f); + if (verts == 3) { + nrTriangles += 1; + } + else if (verts == 4) { + nrTriangles += 2; + } + } + + triangles.reserve(nrTriangles); + + nrTSpaces = 0; + for (uint f = 0; f < nrFaces; f++) { + const uint verts = mesh.GetNumVerticesOfFace(f); + if (verts != 3 && verts != 4) { + continue; + } + + uint tA = uint(triangles.size()); + triangles.emplace_back(f, nrTSpaces); + Triangle &triA = triangles[tA]; + + if (verts == 3) { + triA.setVertices(0, 1, 2); + } + else { + uint tB = uint(triangles.size()); + triangles.emplace_back(f, nrTSpaces); + Triangle &triB = triangles[tB]; + + // need an order independent way to evaluate + // tspace on quads. This is done by splitting + // along the shortest diagonal. + float distSQ_02 = (mesh.GetTexCoord(f, 2) - mesh.GetTexCoord(f, 0)).length_squared(); + float distSQ_13 = (mesh.GetTexCoord(f, 3) - mesh.GetTexCoord(f, 1)).length_squared(); + bool quadDiagIs_02; + if (distSQ_02 != distSQ_13) { + quadDiagIs_02 = (distSQ_02 < distSQ_13); + } + else { + distSQ_02 = (mesh.GetPosition(f, 2) - mesh.GetPosition(f, 0)).length_squared(); + distSQ_13 = (mesh.GetPosition(f, 3) - mesh.GetPosition(f, 1)).length_squared(); + quadDiagIs_02 = !(distSQ_13 < distSQ_02); + } + + if (quadDiagIs_02) { + triA.setVertices(0, 1, 2); + triB.setVertices(0, 2, 3); + } + else { + triA.setVertices(0, 1, 3); + triB.setVertices(1, 2, 3); + } + } + + nrTSpaces += verts; + } + } + + struct VertexHash { + Mikktspace *mikk; + inline uint operator()(const uint &k) const + { + return hash_float3x3(mikk->getPosition(k), mikk->getNormal(k), mikk->getTexCoord(k)); + } + }; + + struct VertexEqual { + Mikktspace *mikk; + inline bool operator()(const uint &kA, const uint &kB) const + { + return mikk->getTexCoord(kA) == mikk->getTexCoord(kB) && + mikk->getNormal(kA) == mikk->getNormal(kB) && + mikk->getPosition(kA) == mikk->getPosition(kB); + } + }; + + /* Merge identical vertices. + * To find vertices with identical position, normal and texcoord, we calculate a hash of the 9 + * values. Then, by sorting based on that hash, identical elements (having identical hashes) will + * be moved next to each other. Since there might be hash collisions, the elements of each block + * are then compared with each other and duplicates are merged. + */ + template void generateSharedVerticesIndexList_impl() + { + uint numVertices = nrTriangles * 3; + AtomicHashSet set(numVertices, {this}, {this}); + runParallel(0u, nrTriangles, [&](uint t) { + for (uint i = 0; i < 3; i++) { + auto res = set.emplace(triangles[t].vertices[i]); + if (!res.second) { + triangles[t].vertices[i] = res.first; + } + } + }); + } + void generateSharedVerticesIndexList() + { + if (isParallel) { + generateSharedVerticesIndexList_impl(); + } + else { + generateSharedVerticesIndexList_impl(); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////// Degenerate triangles //////////////////////////////////// + + void degenPrologue() + { + // Mark all degenerate triangles + totalTriangles = nrTriangles; + std::atomic degenTriangles(0); + runParallel(0u, totalTriangles, [&](uint t) { + const float3 p0 = getPosition(triangles[t].vertices[0]); + const float3 p1 = getPosition(triangles[t].vertices[1]); + const float3 p2 = getPosition(triangles[t].vertices[2]); + if (p0 == p1 || p0 == p2 || p1 == p2) // degenerate + { + triangles[t].markDegenerate = true; + degenTriangles.fetch_add(1); + } + }); + nrTriangles -= degenTriangles.load(); + + if (totalTriangles == nrTriangles) { + return; + } + + // locate quads with only one good triangle + runParallel(0u, totalTriangles - 1, [&](uint t) { + Triangle &triangleA = triangles[t], &triangleB = triangles[t + 1]; + if (triangleA.faceIdx != triangleB.faceIdx) { + /* Individual triangle, skip. */ + return; + } + if (triangleA.markDegenerate != triangleB.markDegenerate) { + triangleA.quadOneDegenTri = true; + triangleB.quadOneDegenTri = true; + } + }); + + std::stable_partition(triangles.begin(), triangles.end(), [](const Triangle &tri) { + return !tri.markDegenerate; + }); + } + + void degenEpilogue() + { + if (nrTriangles == totalTriangles) { + return; + } + + std::unordered_map goodTriangleMap; + for (uint t = 0; t < nrTriangles; t++) { + for (uint i = 0; i < 3; i++) { + goodTriangleMap.emplace(triangles[t].vertices[i], pack_index(t, i)); + } + } + + // deal with degenerate triangles + // punishment for degenerate triangles is O(nrTriangles) extra memory. + for (uint t = nrTriangles; t < totalTriangles; t++) { + // degenerate triangles on a quad with one good triangle are skipped + // here but processed in the next loop + if (triangles[t].quadOneDegenTri) { + continue; + } + + for (uint i = 0; i < 3; i++) { + const auto entry = goodTriangleMap.find(triangles[t].vertices[i]); + if (entry == goodTriangleMap.end()) { + // Matching vertex from good triangle is not found. + continue; + } + + uint tSrc, iSrc; + unpack_index(tSrc, iSrc, entry->second); + const uint iSrcVert = triangles[tSrc].faceVertex[iSrc]; + const uint iSrcOffs = triangles[tSrc].tSpaceIdx; + const uint iDstVert = triangles[t].faceVertex[i]; + const uint iDstOffs = triangles[t].tSpaceIdx; + // copy tspace + tSpaces[iDstOffs + iDstVert] = tSpaces[iSrcOffs + iSrcVert]; + } + } + + // deal with degenerate quads with one good triangle + for (uint t = 0; t < nrTriangles; t++) { + // this triangle belongs to a quad where the + // other triangle is degenerate + if (!triangles[t].quadOneDegenTri) { + continue; + } + uint vertFlag = (1u << triangles[t].faceVertex[0]) | (1u << triangles[t].faceVertex[1]) | + (1u << triangles[t].faceVertex[2]); + uint missingFaceVertex = 0; + if ((vertFlag & 2) == 0) { + missingFaceVertex = 1; + } + else if ((vertFlag & 4) == 0) { + missingFaceVertex = 2; + } + else if ((vertFlag & 8) == 0) { + missingFaceVertex = 3; + } + + uint faceIdx = triangles[t].faceIdx; + float3 dstP = mesh.GetPosition(faceIdx, missingFaceVertex); + bool found = false; + for (uint i = 0; i < 3; i++) { + const uint faceVertex = triangles[t].faceVertex[i]; + const float3 srcP = mesh.GetPosition(faceIdx, faceVertex); + if (srcP == dstP) { + const uint offset = triangles[t].tSpaceIdx; + tSpaces[offset + missingFaceVertex] = tSpaces[offset + faceVertex]; + found = true; + break; + } + } + assert(found); + (void)found; + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////// + + // returns the texture area times 2 + float calcTexArea(uint tri) + { + const float3 t1 = getTexCoord(triangles[tri].vertices[0]); + const float3 t2 = getTexCoord(triangles[tri].vertices[1]); + const float3 t3 = getTexCoord(triangles[tri].vertices[2]); + + const float t21x = t2.x - t1.x; + const float t21y = t2.y - t1.y; + const float t31x = t3.x - t1.x; + const float t31y = t3.y - t1.y; + + const float signedAreaSTx2 = t21x * t31y - t21y * t31x; + return fabsf(signedAreaSTx2); + } + + void initTriangle() + { + // triangles[f].iFlag is cleared in generateInitialVerticesIndexList() + // which is called before this function. + + // evaluate first order derivatives + runParallel(0u, nrTriangles, [&](uint t) { + Triangle &triangle = triangles[t]; + + // initial values + const float3 v1 = getPosition(triangle.vertices[0]); + const float3 v2 = getPosition(triangle.vertices[1]); + const float3 v3 = getPosition(triangle.vertices[2]); + const float3 t1 = getTexCoord(triangle.vertices[0]); + const float3 t2 = getTexCoord(triangle.vertices[1]); + const float3 t3 = getTexCoord(triangle.vertices[2]); + + const float t21x = t2.x - t1.x; + const float t21y = t2.y - t1.y; + const float t31x = t3.x - t1.x; + const float t31y = t3.y - t1.y; + const float3 d1 = v2 - v1, d2 = v3 - v1; + + const float signedAreaSTx2 = t21x * t31y - t21y * t31x; + const float3 vOs = (t31y * d1) - (t21y * d2); // eq 18 + const float3 vOt = (-t31x * d1) + (t21x * d2); // eq 19 + + triangle.orientPreserving = (signedAreaSTx2 > 0); + + if (not_zero(signedAreaSTx2)) { + const float lenOs2 = vOs.length_squared(); + const float lenOt2 = vOt.length_squared(); + const float fS = triangle.orientPreserving ? 1.0f : (-1.0f); + if (not_zero(lenOs2)) { + triangle.tangent = vOs * (fS / sqrtf(lenOs2)); + } + + // if this is a good triangle + if (not_zero(lenOs2) && not_zero(lenOt2)) { + triangle.groupWithAny = false; + } + } + }); + + // force otherwise healthy quads to a fixed orientation + runParallel(0u, nrTriangles - 1, [&](uint t) { + Triangle &triangleA = triangles[t], &triangleB = triangles[t + 1]; + if (triangleA.faceIdx != triangleB.faceIdx) { + // this is not a quad + return; + } + + // bad triangles should already have been removed by + // degenPrologue(), but just in case check that neither are degenerate + if (!(triangleA.markDegenerate || triangleB.markDegenerate)) { + // if this happens the quad has extremely bad mapping!! + if (triangleA.orientPreserving != triangleB.orientPreserving) { + bool chooseOrientFirstTri = false; + if (triangleB.groupWithAny) { + chooseOrientFirstTri = true; + } + else if (calcTexArea(t) >= calcTexArea(t + 1)) { + chooseOrientFirstTri = true; + } + + // force match + const uint t0 = chooseOrientFirstTri ? t : (t + 1); + const uint t1 = chooseOrientFirstTri ? (t + 1) : t; + triangles[t1].orientPreserving = triangles[t0].orientPreserving; + } + } + }); + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////// Edges /////////////////////////////////////////// + + struct NeighborShard { + struct Entry { + Entry(uint32_t key_, uint data_) : key(key_), data(data_) {} + uint key, data; + }; + std::vector entries; + + NeighborShard(size_t capacity) + { + entries.reserve(capacity); + } + + void buildNeighbors(Mikktspace *mikk) + { + /* Entries are added by iterating over t, so by using a stable sort, + * we don't have to compare based on t as well. */ + { + std::vector tempEntries(entries.size(), {0, 0}); + radixsort(entries, tempEntries, [](const Entry &e) { return e.key; }); + } + + for (uint i = 0; i < entries.size(); i++) { + const Entry &a = entries[i]; + uint tA, iA; + unpack_index(tA, iA, a.data); + Mikktspace::Triangle &triA = mikk->triangles[tA]; + + if (triA.neighbor[iA] != UNSET_ENTRY) { + continue; + } + + uint i0A = triA.vertices[iA], i1A = triA.vertices[(iA != 2) ? (iA + 1) : 0]; + for (uint j = i + 1; j < entries.size(); j++) { + const Entry &b = entries[j]; + uint tB, iB; + unpack_index(tB, iB, b.data); + Mikktspace::Triangle &triB = mikk->triangles[tB]; + + if (b.key != a.key) + break; + + if (triB.neighbor[iB] != UNSET_ENTRY) { + continue; + } + + uint i1B = triB.vertices[iB], i0B = triB.vertices[(iB != 2) ? (iB + 1) : 0]; + if (i0A == i0B && i1A == i1B) { + triA.neighbor[iA] = tB; + triB.neighbor[iB] = tA; + break; + } + } + } + } + }; + + void buildNeighbors() + { + /* In order to parallelize the processing, we divide the vertices into shards. + * Since only vertex pairs with the same key will be checked, we can process + * shards independently as long as we ensure that all vertices with the same + * key go into the same shard. + * This is done by hashing the key to get the shard index of each vertex. + */ + // TODO: Two-step filling that first counts and then fills? Could be parallel then. + uint targetNrShards = isParallel ? uint(4 * nrThreads) : 1; + uint nrShards = 1, hashShift = 32; + while (nrShards < targetNrShards) { + nrShards *= 2; + hashShift -= 1; + } + + /* Reserve 25% extra to account for variation due to hashing. */ + size_t reserveSize = size_t(double(3 * nrTriangles) * 1.25 / nrShards); + std::vector shards(nrShards, {reserveSize}); + + for (uint t = 0; t < nrTriangles; t++) { + Triangle &triangle = triangles[t]; + for (uint i = 0; i < 3; i++) { + const uint i0 = triangle.vertices[i]; + const uint i1 = triangle.vertices[(i != 2) ? (i + 1) : 0]; + const uint high = std::max(i0, i1), low = std::min(i0, i1); + const uint hash = hash_uint3(high, low, 0); + /* TODO: Reusing the hash here means less hash space inside each shard. + * Computing a second hash with a different seed it probably not worth it? */ + const uint shard = isParallel ? (hash >> hashShift) : 0; + shards[shard].entries.emplace_back(hash, pack_index(t, i)); + } + } + + runParallel(0u, nrShards, [&](uint s) { shards[s].buildNeighbors(this); }); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////// + + void assignRecur(const uint t, uint groupId) + { + if (t == UNSET_ENTRY) { + return; + } + + Triangle &triangle = triangles[t]; + Group &group = groups[groupId]; + + // track down vertex + const uint vertRep = group.vertexRepresentative; + uint i = 3; + if (triangle.vertices[0] == vertRep) { + i = 0; + } + else if (triangle.vertices[1] == vertRep) { + i = 1; + } + else if (triangle.vertices[2] == vertRep) { + i = 2; + } + assert(i < 3); + + // early out + if (triangle.group[i] != UNSET_ENTRY) { + return; + } + + if (triangle.groupWithAny) { + // first to group with a group-with-anything triangle + // determines its orientation. + // This is the only existing order dependency in the code!! + if (triangle.group[0] == UNSET_ENTRY && triangle.group[1] == UNSET_ENTRY && + triangle.group[2] == UNSET_ENTRY) + { + triangle.orientPreserving = group.orientPreserving; + } + } + + if (triangle.orientPreserving != group.orientPreserving) { + return; + } + + triangle.group[i] = groupId; + + const uint t_L = triangle.neighbor[i]; + const uint t_R = triangle.neighbor[i > 0 ? (i - 1) : 2]; + assignRecur(t_L, groupId); + assignRecur(t_R, groupId); + } + + void build4RuleGroups() + { + /* NOTE: This could be parallelized by grouping all [t, i] pairs into + * shards by hash(triangles[t].vertices[i]). This way, each shard can be processed + * independently and in parallel. + * However, the `groupWithAny` logic needs special handling (e.g. lock a mutex when + * encountering a `groupWithAny` triangle, then sort it out, then unlock and proceed). */ + for (uint t = 0; t < nrTriangles; t++) { + Triangle &triangle = triangles[t]; + for (uint i = 0; i < 3; i++) { + // if not assigned to a group + if (triangle.groupWithAny || triangle.group[i] != UNSET_ENTRY) { + continue; + } + + const uint newGroupId = uint(groups.size()); + triangle.group[i] = newGroupId; + + groups.emplace_back(triangle.vertices[i], bool(triangle.orientPreserving)); + + const uint t_L = triangle.neighbor[i]; + const uint t_R = triangle.neighbor[i > 0 ? (i - 1) : 2]; + assignRecur(t_L, newGroupId); + assignRecur(t_R, newGroupId); + } + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////// + + template void accumulateTSpaces(uint t) + { + const Triangle &triangle = triangles[t]; + // only valid triangles get to add their contribution + if (triangle.groupWithAny) { + return; + } + + /* Todo: Vectorize? + * Also: Could add special case for flat shading, when all normals are equal half of the fCos + * projections and two of the three tangent projections are unnecessary. */ + std::array n, p; + for (uint i = 0; i < 3; i++) { + n[i] = getNormal(triangle.vertices[i]); + p[i] = getPosition(triangle.vertices[i]); + } + + std::array fCos = {dot(project(n[0], p[1] - p[0]), project(n[0], p[2] - p[0])), + dot(project(n[1], p[2] - p[1]), project(n[1], p[0] - p[1])), + dot(project(n[2], p[0] - p[2]), project(n[2], p[1] - p[2]))}; + + for (uint i = 0; i < 3; i++) { + uint groupId = triangle.group[i]; + if (groupId != UNSET_ENTRY) { + float3 tangent = project(n[i], triangle.tangent) * + fast_acosf(std::clamp(fCos[i], -1.0f, 1.0f)); + if constexpr (atomic) { + groups[groupId].accumulateTSpaceAtomic(tangent); + } + else { + groups[groupId].accumulateTSpace(tangent); + } + } + } + } + + void generateTSpaces() + { + if (isParallel) { + runParallel(0u, nrTriangles, [&](uint t) { accumulateTSpaces(t); }); + } + else { + for (uint t = 0; t < nrTriangles; t++) { + accumulateTSpaces(t); + } + } + + /* TODO: Worth parallelizing? Probably not. */ + for (Group &group : groups) { + group.normalizeTSpace(); + } + + tSpaces.resize(nrTSpaces); + + for (uint t = 0; t < nrTriangles; t++) { + Triangle &triangle = triangles[t]; + for (uint i = 0; i < 3; i++) { + uint groupId = triangle.group[i]; + if (groupId == UNSET_ENTRY) { + continue; + } + const Group group = groups[groupId]; + assert(triangle.orientPreserving == group.orientPreserving); + + // output tspace + const uint offset = triangle.tSpaceIdx; + const uint faceVertex = triangle.faceVertex[i]; + tSpaces[offset + faceVertex].accumulateGroup(group); + } + } + } +}; + +} // namespace mikk diff --git a/indra/externals/tut/LICENSE.txt b/indra/externals/tut/LICENSE.txt new file mode 100644 index 00000000000..bcd715a17b5 --- /dev/null +++ b/indra/externals/tut/LICENSE.txt @@ -0,0 +1,10 @@ + Copyright 2002-2006 Vladimir Dyuzhev +Copyright 2007 Denis Kononenko +Copyright 2008 Micha? Rzechonek + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/indra/externals/tut/tut/tut.hpp b/indra/externals/tut/tut/tut.hpp new file mode 100644 index 00000000000..a7245e2206c --- /dev/null +++ b/indra/externals/tut/tut/tut.hpp @@ -0,0 +1,575 @@ +#ifndef TUT_H_GUARD +#define TUT_H_GUARD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// these headers have all sorts of (what clang thinks are) unused functions +// -Wunused-function warnings and therefore errors on the clang (apple) build +// Leaving it as for clang only because if we ever switch to clang on other +// platforms the same issue will manifest itself. +#if __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" + #include "tut_exception.hpp" + #include "tut_result.hpp" + #include "tut_posix.hpp" + #include "tut_assert.hpp" + #include "tut_runner.hpp" +#pragma clang diagnostic pop +#else + #include "tut_exception.hpp" + #include "tut_result.hpp" + #include "tut_posix.hpp" + #include "tut_assert.hpp" + #include "tut_runner.hpp" +#endif + +#if defined(TUT_USE_SEH) +#include +#include +#endif + +/** + * Template Unit Tests Framework for C++. + * http://tut.dozen.ru + * + * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com + */ +namespace tut +{ + +/** + * Test object. Contains data test run upon and default test method + * implementation. Inherited from Data to allow tests to + * access test data as members. + */ +template +class test_object : public Data, public test_object_posix +{ +public: + + /** + * Default constructor + */ + test_object() + { + } + + void set_test_name(const std::string& current_test_name) + { + current_test_name_ = current_test_name; + } + + const std::string& get_test_name() const + { + return current_test_name_; + } + + /** + * Default do-nothing test. + */ + template + void test() + { + called_method_was_a_dummy_test_ = true; + } + + /** + * The flag is set to true by default (dummy) test. + * Used to detect usused test numbers and avoid unnecessary + * test object creation which may be time-consuming depending + * on operations described in Data::Data() and Data::~Data(). + * TODO: replace with throwing special exception from default test. + */ + bool called_method_was_a_dummy_test_; + +private: + std::string current_test_name_; +}; + + +/** + * Walks through test tree and stores address of each + * test method in group. Instantiation stops at 0. + */ +template +struct tests_registerer +{ + static void reg(Group& group) + { + group.reg(n, &Test::template test); + tests_registerer::reg(group); + } +}; + +template +struct tests_registerer +{ + static void reg(Group&) + { + } +}; + +/** + * Test group; used to recreate test object instance for + * each new test since we have to have reinitialized + * Data base class. + */ +template +class test_group : public group_base, public test_group_posix +{ + const char* name_; + + typedef void (test_object::*testmethod)(); + typedef std::map tests; + typedef typename tests::iterator tests_iterator; + typedef typename tests::const_iterator tests_const_iterator; + typedef typename tests::const_reverse_iterator + tests_const_reverse_iterator; + typedef typename tests::size_type size_type; + + tests tests_; + tests_iterator current_test_; + + /** + * Exception-in-destructor-safe smart-pointer class. + */ + template + class safe_holder + { + T* p_; + bool permit_throw_in_dtor; + + safe_holder(const safe_holder&); + safe_holder& operator=(const safe_holder&); + + public: + safe_holder() + : p_(0), + permit_throw_in_dtor(false) + { + } + + ~safe_holder() + { + release(); + } + + T* operator->() const + { + return p_; + } + + T* get() const + { + return p_; + } + + /** + * Tell ptr it can throw from destructor. Right way is to + * use std::uncaught_exception(), but some compilers lack + * correct implementation of the function. + */ + void permit_throw() + { + permit_throw_in_dtor = true; + } + + /** + * Specially treats exceptions in test object destructor; + * if test itself failed, exceptions in destructor + * are ignored; if test was successful and destructor failed, + * warning exception throwed. + */ + void release() + { + try + { + if (delete_obj() == false) + { + boost::throw_exception(warning("destructor of test object raised" + " an SEH exception")); + } + } + catch (const std::exception& ex) + { + if (permit_throw_in_dtor) + { + std::string msg = "destructor of test object raised" + " exception: "; + msg += ex.what(); + boost::throw_exception(warning(msg)); + } + } + catch( ... ) + { + if (permit_throw_in_dtor) + { + boost::throw_exception(warning("destructor of test object raised an" + " exception")); + } + } + } + + /** + * Re-init holder to get brand new object. + */ + void reset() + { + release(); + permit_throw_in_dtor = false; + p_ = new T(); + } + + bool delete_obj() + { +#if defined(TUT_USE_SEH) + __try + { +#endif + T* p = p_; + p_ = 0; + delete p; +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + if (permit_throw_in_dtor) + { + return false; + } + } +#endif + return true; + } + }; + +public: + + typedef test_object object; + + /** + * Creates and registers test group with specified name. + */ + test_group(const char* name) + : name_(name) + { + // register itself + runner.get().register_group(name_,this); + + // register all tests + tests_registerer::reg(*this); + } + + /** + * This constructor is used in self-test run only. + */ + test_group(const char* name, test_runner& another_runner) + : name_(name) + { + // register itself + another_runner.register_group(name_, this); + + // register all tests + tests_registerer, test_group, + MaxTestsInGroup>::reg(*this); + }; + + /** + * Registers test method under given number. + */ + void reg(int n, testmethod tm) + { + tests_[n] = tm; + } + + /** + * Reset test position before first test. + */ + void rewind() + { + current_test_ = tests_.begin(); + } + + /** + * Runs next test. + */ + test_result run_next() + { + if (current_test_ == tests_.end()) + { + boost::throw_exception(no_more_tests()); + } + + // find next user-specialized test + safe_holder obj; + while (current_test_ != tests_.end()) + { + try + { + tests_iterator current_test = current_test_++; + + test_result tr = run_test_(current_test, obj); + + return tr; + } + catch (const no_such_test&) + { + continue; + } + } + + boost::throw_exception(no_more_tests()); + } + + /** + * Runs one test by position. + */ + test_result run_test(int n) + { + // beyond tests is special case to discover upper limit + if (tests_.rbegin() == tests_.rend()) + { + boost::throw_exception(beyond_last_test()); + } + + if (tests_.rbegin()->first < n) + { + boost::throw_exception(beyond_last_test()); + } + + // withing scope; check if given test exists + tests_iterator ti = tests_.find(n); + if (ti == tests_.end()) + { + boost::throw_exception(no_such_test()); + } + + safe_holder obj; + test_result tr = run_test_(ti, obj); + + return tr; + } + + + /** + * VC allows only one exception handling type per function, + * so I have to split the method. + */ + test_result run_test_(const tests_iterator& ti, safe_holder& obj) + { + std::string current_test_name; + + test_result tr(name_, ti->first, current_test_name, test_result::ok); + + try + { + if (run_test_seh_(ti->second, obj, current_test_name) == false) + { + boost::throw_exception(seh("seh")); + } + } + catch (const no_such_test&) + { + throw; + } + catch (const rethrown& ex) + { + tr = ex.tr; + tr.result = test_result::rethrown; + } + catch (const tut_error& ex) + { + tr.result = ex.result(); + tr.exception_typeid = typeid(ex).name(); + tr.message = ex.what(); + } + catch (const boost::exception& ex) + { + const tut_error* tutex = dynamic_cast(&ex); + const std::exception* stdex = dynamic_cast(&ex); + tr.exception_typeid = typeid(ex).name(); + if (tutex) + { + tr.result = tutex->result(); + tr.message = tutex->what(); + } + else + { + tr.result = test_result::ex; + if (stdex) + { + tr.message = stdex->what(); + } + else + { + tr.message = boost::diagnostic_information(ex); + } + } + } + catch (const std::exception& ex) + { + tr.result = test_result::ex; + tr.exception_typeid = typeid(ex).name(); + tr.message = ex.what(); + } + catch (...) + { + const tut_error* tutex = boost::current_exception_cast(); + const std::exception* stdex = boost::current_exception_cast(); + // test failed with unknown exception + tr.result = test_result::ex; + if (tutex) + { + tr.result = tutex->result(); + tr.exception_typeid = typeid(*tutex).name(); + tr.message = tutex->what(); + } + else if (stdex) + { + tr.exception_typeid = typeid(*stdex).name(); + tr.message = stdex->what(); + } + else + { + tr.message = boost::current_exception_diagnostic_information(); + } + } + + if (obj.get()) + { + tr.name = obj->get_test_name(); + + // try to report to parent, if exists + send_result_(obj.get(), tr); + } + else + { + tr.name = current_test_name; + } + + return tr; + } + + /** + * Runs one under SEH if platform supports it. + */ + bool run_test_seh_(testmethod tm, safe_holder& obj, + std::string& current_test_name) + { +#if defined(TUT_USE_SEH) + __try + { +#endif + if (obj.get() == 0) + { + reset_holder_(obj); + } + + obj->called_method_was_a_dummy_test_ = false; + +#if defined(TUT_USE_SEH) + + __try + { +#endif + (obj.get()->*tm)(); +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + // throw seh("SEH"); + current_test_name = obj->get_test_name(); + return false; + } +#endif + + if (obj->called_method_was_a_dummy_test_) + { + // do not call obj.release(); reuse object + boost::throw_exception(no_such_test()); + } + + current_test_name = obj->get_test_name(); + obj.permit_throw(); + obj.release(); +#if defined(TUT_USE_SEH) + } + __except(handle_seh_(::GetExceptionCode())) + { + return false; + } +#endif + return true; + } + + void reset_holder_(safe_holder& obj) + { + try + { + obj.reset(); + } + catch (const std::exception& ex) + { + boost::throw_exception(bad_ctor(ex.what())); + } + catch (...) + { + boost::throw_exception(bad_ctor("test constructor has generated an exception;" + " group execution is terminated")); + } + } +}; + +#if defined(TUT_USE_SEH) +/** + * Decides should we execute handler or ignore SE. + */ +inline int handle_seh_(DWORD excode) +{ + switch(excode) + { + case EXCEPTION_ACCESS_VIOLATION: + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_BREAKPOINT: + case EXCEPTION_SINGLE_STEP: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_INEXACT_RESULT: + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_OVERFLOW: + case EXCEPTION_PRIV_INSTRUCTION: + case EXCEPTION_IN_PAGE_ERROR: + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + case EXCEPTION_STACK_OVERFLOW: + case EXCEPTION_INVALID_DISPOSITION: + case EXCEPTION_GUARD_PAGE: + case EXCEPTION_INVALID_HANDLE: + return EXCEPTION_EXECUTE_HANDLER; + }; + + return EXCEPTION_CONTINUE_SEARCH; +} +#endif +} + +#endif + diff --git a/indra/externals/tut/tut/tut_assert.hpp b/indra/externals/tut/tut/tut_assert.hpp new file mode 100644 index 00000000000..361307aef97 --- /dev/null +++ b/indra/externals/tut/tut/tut_assert.hpp @@ -0,0 +1,168 @@ +#ifndef TUT_ASSERT_H_GUARD +#define TUT_ASSERT_H_GUARD + +#include "tut_exception.hpp" +#include + +#if defined(TUT_USE_POSIX) +#include +#include +#endif + +namespace tut +{ + +namespace +{ + +void fail(const std::string &msg); + +/** + * Tests provided condition. + * Throws if false. + */ +void ensure(bool cond) +{ + if (!cond) + { + // TODO: default ctor? + fail(""); + } +} + +/** + * Tests provided condition. + * Throws if true. + */ +void ensure_not(bool cond) +{ + ensure(!cond); +} + +/** + * Tests provided condition. + * Throws if false. + */ +template +void ensure(const T msg, bool cond) +{ + if (!cond) + { + fail(msg); + } +} + +/** + * Tests provided condition. + * Throws if true. + */ +template +void ensure_not(const T msg, bool cond) +{ + ensure(msg, !cond); +} + +/** + * Tests two objects for being equal. + * Throws if false. + * + * NB: both T and Q must have operator << defined somewhere, or + * client code will not compile at all! + */ +template +void ensure_equals(const std::string& msg, const Q& actual, const T& expected) +{ + if (expected != actual) + { + std::ostringstream ss; + if (! msg.empty()) + ss << msg << ": "; + ss << "expected '" + << expected + << "' actual '" + << actual + << '\''; + fail(ss.str()); + } +} + +template +void ensure_equals(const Q& actual, const T& expected) +{ + ensure_equals("", actual, expected); +} + +/** + * Tests two objects for being at most in given distance one from another. + * Borders are excluded. + * Throws if false. + * + * NB: T must have operator << defined somewhere, or + * client code will not compile at all! Also, T shall have + * operators + and -, and be comparable. + */ +template +void ensure_distance(const char* msg, const T& actual, const T& expected, + const T& distance) +{ + if (expected-distance >= actual || expected+distance <= actual) + { + std::stringstream ss; + ss << (msg ? msg : "") + << (msg? ":" : "") + << " expected (" + << expected-distance + << " - " + << expected+distance + << ") actual '" + << actual + << '\''; + fail(ss.str()); + } +} + +template +void ensure_distance(const T& actual, const T& expected, const T& distance) +{ + ensure_distance<>(0, actual, expected, distance); +} + +void ensure_errno(const char *msg, bool cond) +{ + if(!cond) + { +#if defined(TUT_USE_POSIX) + char e[512]; + std::stringstream ss; + ss << (msg ? msg : "") + << (msg? ": " : "") + << strerror_r(errno, e, sizeof(e)); + fail(ss.str()); +#else + fail(msg); +#endif + } +} + +/** + * Unconditionally fails with message. + */ +void fail(const std::string &msg) +{ + boost::throw_exception(failure(msg)); +} + +/** + * Skip test because of known failure. + */ +void skip(const std::string& msg) +{ + boost::throw_exception(skip_failure(msg)); +} + +} // end of namespace + +} + +#endif + diff --git a/indra/externals/tut/tut/tut_exception.hpp b/indra/externals/tut/tut/tut_exception.hpp new file mode 100644 index 00000000000..85e8f0a7873 --- /dev/null +++ b/indra/externals/tut/tut/tut_exception.hpp @@ -0,0 +1,228 @@ +#ifndef TUT_EXCEPTION_H_GUARD +#define TUT_EXCEPTION_H_GUARD + +#include +#include "tut_result.hpp" + +namespace tut +{ + +/** + * The base for all TUT exceptions. + */ +struct tut_error : public std::exception +{ + tut_error(const std::string& msg) + : err_msg(msg) + { + } + + virtual test_result::result_type result() const + { + return test_result::ex; + } + + const char* what() const throw() + { + return err_msg.c_str(); + } + + ~tut_error() throw() + { + } + +private: + + std::string err_msg; +}; + +/** + * Exception to be throwed when attempted to execute + * missed test by number. + */ +struct no_such_test : public tut_error +{ + no_such_test() + : tut_error("no such test") + { + } + + ~no_such_test() throw() + { + } +}; + +/** + * No such test and passed test number is higher than + * any test number in current group. Used in one-by-one + * test running when upper bound is not known. + */ +struct beyond_last_test : public no_such_test +{ + beyond_last_test() + { + } + + ~beyond_last_test() throw() + { + } +}; + +/** + * Group not found exception. + */ +struct no_such_group : public tut_error +{ + no_such_group(const std::string& grp) + : tut_error(grp) + { + } + + ~no_such_group() throw() + { + } +}; + +/** + * Internal exception to be throwed when + * no more tests left in group or journal. + */ +struct no_more_tests: public std::exception +{ + no_more_tests() + { + } + + const char* what() const throw() { return "no more tests"; } + + ~no_more_tests() throw() + { + } +}; + +/** + * Internal exception to be throwed when + * test constructor has failed. + */ +struct bad_ctor : public tut_error +{ + bad_ctor(const std::string& msg) + : tut_error(msg) + { + } + + test_result::result_type result() const + { + return test_result::ex_ctor; + } + + ~bad_ctor() throw() + { + } +}; + +/** + * Exception to be throwed when ensure() fails or fail() called. + */ +struct failure : public tut_error +{ + failure(const std::string& msg) + : tut_error(msg) + { + } + + test_result::result_type result() const + { + return test_result::fail; + } + + ~failure() throw() + { + } +}; + +/** + * Exception to be throwed when test desctructor throwed an exception. + */ +struct warning : public tut_error +{ + warning(const std::string& msg) + : tut_error(msg) + { + } + + test_result::result_type result() const + { + return test_result::warn; + } + + ~warning() throw() + { + } +}; + +/** + * Exception to be throwed when test issued SEH (Win32) + */ +struct seh : public tut_error +{ + seh(const std::string& msg) + : tut_error(msg) + { + } + + virtual test_result::result_type result() const + { + return test_result::term; + } + + ~seh() throw() + { + } +}; + +/** + * Exception to be throwed when child processes fail. + */ +struct rethrown : public failure +{ + explicit rethrown(const test_result &result) + : failure(result.message), tr(result) + { + } + + virtual test_result::result_type result() const + { + return test_result::rethrown; + } + + ~rethrown() throw() + { + } + + const test_result tr; +}; + +/** + * Exception to be throwed when skip_fail() is called. + */ +struct skip_failure : public failure +{ + skip_failure(const std::string& msg) + : failure(msg) + { + } + + test_result::result_type result() const + { + return test_result::skip; + } + + ~skip_failure() throw() + { + } +}; + +} + +#endif diff --git a/indra/externals/tut/tut/tut_posix.hpp b/indra/externals/tut/tut/tut_posix.hpp new file mode 100644 index 00000000000..80643143f30 --- /dev/null +++ b/indra/externals/tut/tut/tut_posix.hpp @@ -0,0 +1,451 @@ +#ifndef TUT_FORK_H_GUARD +#define TUT_FORK_H_GUARD + +#if defined(TUT_USE_POSIX) +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "tut_result.hpp" +#include "tut_assert.hpp" +#include "tut_runner.hpp" + +namespace tut +{ + +template +class test_group; + +template +class test_object; + +class test_group_posix +{ +private: + template + friend class test_group; + + template + void send_result_(const T *obj, const test_result &tr) + { + if(obj->get_pipe_() == -1) + { + return; + } + + if(tr.result != test_result::ok) + { + std::stringstream ss; + ss << int(tr.result) << "\n" + << tr.group << "\n" + << tr.test << "\n" + << tr.name << "\n" + << tr.exception_typeid << "\n"; + std::copy( tr.message.begin(), tr.message.end(), std::ostreambuf_iterator(ss.rdbuf()) ); + + int size = ss.str().length(); + int w = write(obj->get_pipe_(), ss.str().c_str(), size); + ensure_errno("write() failed", w == size); + } + } +}; + +template +struct tut_posix +{ + pid_t fork() + { + test_object *self = dynamic_cast< tut::test_object* >(this); + ensure("trying to call 'fork' in ctor of test object", self != NULL); + + return self->fork_(); + } + + void ensure_child_exit(pid_t pid, int exit_status = 0) + { + test_object *self = dynamic_cast< tut::test_object* >(this); + ensure("trying to call 'ensure_child_exit' in ctor of test object", self != NULL); + + int status; + self->waitpid_(pid, &status); + + self->ensure_child_exit_(status, exit_status); + } + + + void ensure_child_signal(pid_t pid, int signal = SIGTERM) + { + test_object *self = dynamic_cast< tut::test_object* >(this); + ensure("trying to call 'ensure_child_signal' in ctor of test object", self != NULL); + + int status; + self->waitpid_(pid, &status); + + self->ensure_child_signal_(status, signal); + } + + std::set get_pids() const + { + using namespace std; + + const test_object *self = dynamic_cast< const tut::test_object* >(this); + ensure("trying to call 'get_pids' in ctor of test object", self != NULL); + + return self->get_pids_(); + } + + virtual ~tut_posix() + { + } + +}; + +class test_object_posix +{ +public: + typedef std::map pid_map; + + /** + * Default constructor + */ + test_object_posix() + : pipe_(-1) + { + } + + + virtual ~test_object_posix() + { + // we have forked + if(pipe_ != -1) + { + // in child, force exit + std::exit(0); + } + + if(!pids_.empty()) + { + std::stringstream ss; + + // in parent, reap children + for(std::map::iterator i = pids_.begin(); i != pids_.end(); ++i) + { + try { + kill_child_(i->first); + } catch(const rethrown &ex) { + ss << std::endl << "child " << ex.tr.pid << " has thrown an exception: " << ex.what(); + } catch(const failure &ex) { + ss << std::endl << ex.what(); + } + } + + if(!ss.str().empty()) + { + fail(ss.str().c_str()); + } + } + } + +private: + template + friend class tut_posix; + + friend class test_group_posix; + + int get_pipe_() const + { + return pipe_; + } + + + pid_t fork_() + { + // create pipe + int fds[2]; + ensure_errno("pipe() failed", ::pipe(fds) == 0); + + pid_t pid = ::fork(); + + ensure_errno("fork() failed", pid >= 0); + + if(pid != 0) + { + // in parent, register pid + ensure("duplicated child", pids_.insert( std::make_pair(pid, fds[0]) ).second); + + // close writing side + close(fds[1]); + } + else + { + // in child, shutdown reporter + tut::runner.get().set_callback(NULL); + + // close reading side + close(fds[0]); + pipe_ = fds[1]; + } + + return pid; + } + + void kill_child_(pid_t pid) + { + int status; + + if(waitpid_(pid, &status, WNOHANG) == pid) + { + ensure_child_exit_(status, 0); + return; + } + + if(::kill(pid, SIGTERM) != 0) + { + if(errno == ESRCH) + { + // no such process + return; + } + else + { + // cannot kill, we are in trouble + std::stringstream ss; + char e[1024]; + ss << "child " << pid << " could not be killed with SIGTERM, " << strerror_r(errno, e, sizeof(e)) << std::endl; + fail(ss.str()); + } + } + + if(waitpid_(pid, &status, WNOHANG) == pid) + { + // child killed, check signal + ensure_child_signal_(status, SIGTERM); + + ensure_equals("child process exists after SIGTERM", ::kill(pid, 0), -1); + return; + } + + // child seems to be still exiting, give it some time + sleep(2); + + if(waitpid_(pid, &status, WNOHANG) != pid) + { + // child is still running, kill it + if(::kill(pid, SIGKILL) != 0) + { + if(errno == ESRCH) + { + // no such process + return; + } + else + { + std::stringstream ss; + char e[1024]; + ss << "child " << pid << " could not be killed with SIGKILL, " << strerror_r(errno, e, sizeof(e)) << std::endl; + fail(ss.str()); + } + } + + ensure_equals("wait after SIGKILL", waitpid_(pid, &status), pid); + ensure_child_signal_(status, SIGKILL); + + ensure_equals("child process exists after SIGKILL", ::kill(pid, 0), -1); + + std::stringstream ss; + ss << "child " << pid << " had to be killed with SIGKILL"; + fail(ss.str()); + } + } + + test_result receive_result_(std::istream &ss, pid_t pid) + { + test_result tr; + + int type; + ss >> type; + tr.result = test_result::result_type(type); + ss.ignore(1024, '\n'); + + std::getline(ss, tr.group); + ss >> tr.test; + ss.ignore(1024, '\n'); + std::getline(ss, tr.name); + std::getline(ss, tr.exception_typeid); + std::copy( std::istreambuf_iterator(ss.rdbuf()), + std::istreambuf_iterator(), + std::back_inserter(tr.message) ); + + tr.pid = pid; + + return tr; + } + + pid_t waitpid_(pid_t pid, int *status, int flags = 0) + { + ensure("trying to wait for unknown pid", pids_.count(pid) > 0); + + pid_t p = ::waitpid(pid, status, flags); + if( (flags & WNOHANG) && (p != pid) ) + { + return p; + } + + // read child result from pipe + fd_set fdset; + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(&fdset); + + int pipe = pids_[pid]; + FD_SET(pipe, &fdset); + + int result = select(pipe+1, &fdset, NULL, NULL, &tv); + ensure_errno("sanity check on select() failed", result >= 0); + + if(result > 0) + { + ensure("sanity check on FD_ISSET() failed", FD_ISSET(pipe, &fdset) ); + + std::stringstream ss; + + //TODO: max failure length + char buffer[1024]; + int r = read(pipe, buffer, sizeof(buffer)); + ensure_errno("sanity check on read() failed", r >= 0); + + if(r > 0) + { + ss.write(buffer, r); + boost::throw_exception(rethrown( receive_result_(ss, pid) )); + } + } + + return pid; + } + + void ensure_child_exit_(int status, int exit_status) + { + if(WIFSIGNALED(status)) + { + std::stringstream ss; + ss << "child killed by signal " << WTERMSIG(status) + << ": expected exit with code " << exit_status; + + fail(ss.str().c_str()); + } + + if(WIFEXITED(status)) + { + if(WEXITSTATUS(status) != exit_status) + { + std::stringstream ss; + ss << "child exited, expected '" + << exit_status + << "' actual '" + << WEXITSTATUS(status) + << '\''; + + fail(ss.str().c_str()); + } + } + + if(WIFSTOPPED(status)) + { + std::stringstream ss; + ss << "child stopped by signal " << WTERMSIG(status) + << ": expected exit with code " << exit_status; + fail(ss.str().c_str()); + } + } + + void ensure_child_signal_(int status, int signal) + { + if(WIFSIGNALED(status)) + { + if(WTERMSIG(status) != signal) + { + std::stringstream ss; + ss << "child killed by signal, expected '" + << signal + << "' actual '" + << WTERMSIG(status) + << '\''; + fail(ss.str().c_str()); + } + } + + if(WIFEXITED(status)) + { + std::stringstream ss; + ss << "child exited with code " << WEXITSTATUS(status) + << ": expected signal " << signal; + + fail(ss.str().c_str()); + } + + if(WIFSTOPPED(status)) + { + std::stringstream ss; + ss << "child stopped by signal " << WTERMSIG(status) + << ": expected kill by signal " << signal; + + fail(ss.str().c_str()); + } + } + + std::set get_pids_() const + { + using namespace std; + + set pids; + for(pid_map::const_iterator i = pids_.begin(); i != pids_.end(); ++i) + { + pids.insert( i->first ); + } + + return pids; + } + + pid_map pids_; + int pipe_; +}; + +} // namespace tut + +#else + +namespace tut +{ + +struct test_object_posix +{ +}; + +struct test_group_posix +{ + template + void send_result_(const T*, const test_result &) + { + } +}; + +} // namespace tut + +#endif + + +#endif + diff --git a/indra/externals/tut/tut/tut_reporter.hpp b/indra/externals/tut/tut/tut_reporter.hpp new file mode 100644 index 00000000000..8422bec92b4 --- /dev/null +++ b/indra/externals/tut/tut/tut_reporter.hpp @@ -0,0 +1,243 @@ +#ifndef TUT_REPORTER +#define TUT_REPORTER + +#include + +/** + * Template Unit Tests Framework for C++. + * http://tut.dozen.ru + * + * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com + */ +namespace +{ + +std::ostream& operator<<(std::ostream& os, const tut::test_result& tr) +{ + switch(tr.result) + { + case tut::test_result::ok: + os << '.'; + break; + case tut::test_result::fail: + os << '[' << tr.test << "=F]"; + break; + case tut::test_result::ex_ctor: + os << '[' << tr.test << "=C]"; + break; + case tut::test_result::ex: + os << '[' << tr.test << "=X]"; + break; + case tut::test_result::warn: + os << '[' << tr.test << "=W]"; + break; + case tut::test_result::term: + os << '[' << tr.test << "=T]"; + break; + case tut::test_result::rethrown: + os << '[' << tr.test << "=P]"; + break; + } + + return os; +} + +} // end of namespace + +namespace tut +{ + +/** + * Default TUT callback handler. + */ +class reporter : public tut::callback +{ + std::string current_group; + typedef std::vector not_passed_list; + not_passed_list not_passed; + std::ostream& os; + +public: + + int ok_count; + int exceptions_count; + int failures_count; + int terminations_count; + int warnings_count; + + reporter() + : os(std::cout) + { + init(); + } + + reporter(std::ostream& out) + : os(out) + { + init(); + } + + void run_started() + { + init(); + } + + void test_completed(const tut::test_result& tr) + { + if (tr.group != current_group) + { + os << std::endl << tr.group << ": " << std::flush; + current_group = tr.group; + } + + os << tr << std::flush; + if (tr.result == tut::test_result::ok) + { + ok_count++; + } + else if (tr.result == tut::test_result::ex) + { + exceptions_count++; + } + else if (tr.result == tut::test_result::ex_ctor) + { + exceptions_count++; + } + else if (tr.result == tut::test_result::fail) + { + failures_count++; + } + else if (tr.result == tut::test_result::rethrown) + { + failures_count++; + } + else if (tr.result == tut::test_result::warn) + { + warnings_count++; + } + else + { + terminations_count++; + } + + if (tr.result != tut::test_result::ok) + { + not_passed.push_back(tr); + } + } + + void run_completed() + { + os << std::endl; + + if (not_passed.size() > 0) + { + not_passed_list::const_iterator i = not_passed.begin(); + while (i != not_passed.end()) + { + tut::test_result tr = *i; + + os << std::endl; + + os << "---> " << "group: " << tr.group + << ", test: test<" << tr.test << ">" + << (!tr.name.empty() ? (std::string(" : ") + tr.name) : std::string()) + << std::endl; + +#if defined(TUT_USE_POSIX) + if(tr.pid != getpid()) + { + os << " child pid: " << tr.pid << std::endl; + } +#endif + os << " problem: "; + switch(tr.result) + { + case test_result::rethrown: + os << "assertion failed in child" << std::endl; + break; + case test_result::fail: + os << "assertion failed" << std::endl; + break; + case test_result::ex: + case test_result::ex_ctor: + os << "unexpected exception" << std::endl; + if( tr.exception_typeid != "" ) + { + os << " exception typeid: " + << tr.exception_typeid << std::endl; + } + break; + case test_result::term: + os << "would be terminated" << std::endl; + break; + case test_result::warn: + os << "test passed, but cleanup code (destructor) raised" + " an exception" << std::endl; + break; + default: + break; + } + + if (!tr.message.empty()) + { + if (tr.result == test_result::fail) + { + os << " failed assertion: \"" << tr.message << "\"" + << std::endl; + } + else + { + os << " message: \"" << tr.message << "\"" + << std::endl; + } + } + + ++i; + } + } + + os << std::endl; + + os << "tests summary:"; + if (terminations_count > 0) + { + os << " terminations:" << terminations_count; + } + if (exceptions_count > 0) + { + os << " exceptions:" << exceptions_count; + } + if (failures_count > 0) + { + os << " failures:" << failures_count; + } + if (warnings_count > 0) + { + os << " warnings:" << warnings_count; + } + os << " ok:" << ok_count; + os << std::endl; + } + + bool all_ok() const + { + return not_passed.empty(); + } + +private: + + void init() + { + ok_count = 0; + exceptions_count = 0; + failures_count = 0; + terminations_count = 0; + warnings_count = 0; + not_passed.clear(); + } +}; + +} + +#endif diff --git a/indra/externals/tut/tut/tut_restartable.hpp b/indra/externals/tut/tut/tut_restartable.hpp new file mode 100644 index 00000000000..7fa152f6875 --- /dev/null +++ b/indra/externals/tut/tut/tut_restartable.hpp @@ -0,0 +1,395 @@ +#ifndef TUT_RESTARTABLE_H_GUARD +#define TUT_RESTARTABLE_H_GUARD + +#include +#include +#include +#include +#include + +/** + * Template Unit Tests Framework for C++. + * http://tut.dozen.ru + * + * Optional restartable wrapper for test_runner. Allows to restart test runs + * finished due to abnormal test application termination (such as segmentation + * fault or math error). + * + * @author Vladimir Dyuzhev, Vladimir.Dyuzhev@gmail.com + */ + +namespace tut +{ + +namespace util +{ + +/** + * Escapes non-alphabetical characters in string. + */ +std::string escape(const std::string& orig) +{ + std::string rc; + std::string::const_iterator i,e; + i = orig.begin(); + e = orig.end(); + + while (i != e) + { + if ((*i >= 'a' && *i <= 'z') || + (*i >= 'A' && *i <= 'Z') || + (*i >= '0' && *i <= '9') ) + { + rc += *i; + } + else + { + rc += '\\'; + rc += ('a'+(((unsigned int)*i) >> 4)); + rc += ('a'+(((unsigned int)*i) & 0xF)); + } + + ++i; + } + return rc; +} + +/** + * Un-escapes string. + */ +std::string unescape(const std::string& orig) +{ + std::string rc; + std::string::const_iterator i,e; + i = orig.begin(); + e = orig.end(); + + while (i != e) + { + if (*i != '\\') + { + rc += *i; + } + else + { + ++i; + if (i == e) + { + boost::throw_exception(std::invalid_argument("unexpected end of string")); + } + unsigned int c1 = *i; + ++i; + if (i == e) + { + boost::throw_exception(std::invalid_argument("unexpected end of string")); + } + unsigned int c2 = *i; + rc += (((c1 - 'a') << 4) + (c2 - 'a')); + } + + ++i; + } + return rc; +} + +/** + * Serialize test_result avoiding interfering with operator <<. + */ +void serialize(std::ostream& os, const tut::test_result& tr) +{ + os << escape(tr.group) << std::endl; + os << tr.test << ' '; + switch(tr.result) + { + case test_result::ok: + os << 0; + break; + case test_result::fail: + os << 1; + break; + case test_result::ex: + os << 2; + break; + case test_result::warn: + os << 3; + break; + case test_result::term: + os << 4; + break; + default: + boost::throw_exception(std::logic_error("operator << : bad result_type")); + } + os << ' ' << escape(tr.message) << std::endl; +} + +/** + * deserialization for test_result + */ +void deserialize(std::istream& is, tut::test_result& tr) +{ + std::getline(is,tr.group); + if (is.eof()) + { + boost::throw_exception(tut::no_more_tests()); + } + tr.group = unescape(tr.group); + + tr.test = -1; + is >> tr.test; + if (tr.test < 0) + { + boost::throw_exception(std::logic_error("operator >> : bad test number")); + } + + int n = -1; + is >> n; + switch(n) + { + case 0: + tr.result = test_result::ok; + break; + case 1: + tr.result = test_result::fail; + break; + case 2: + tr.result = test_result::ex; + break; + case 3: + tr.result = test_result::warn; + break; + case 4: + tr.result = test_result::term; + break; + default: + boost::throw_exception(std::logic_error("operator >> : bad result_type")); + } + + is.ignore(1); // space + std::getline(is,tr.message); + tr.message = unescape(tr.message); + if (!is.good()) + { + boost::throw_exception(std::logic_error("malformed test result")); + } +} +}; + +/** + * Restartable test runner wrapper. + */ +class restartable_wrapper +{ + test_runner& runner_; + callback* callback_; + + std::string dir_; + std::string log_; // log file: last test being executed + std::string jrn_; // journal file: results of all executed tests + +public: + /** + * Default constructor. + * @param dir Directory where to search/put log and journal files + */ + restartable_wrapper(const std::string& dir = ".") + : runner_(runner.get()), + callback_(0), + dir_(dir) + { + // dozen: it works, but it would be better to use system path separator + jrn_ = dir_ + '/' + "journal.tut"; + log_ = dir_ + '/' + "log.tut"; + } + + /** + * Stores another group for getting by name. + */ + void register_group(const std::string& name, group_base* gr) + { + runner_.register_group(name,gr); + } + + /** + * Stores callback object. + */ + void set_callback(callback* cb) + { + callback_ = cb; + } + + /** + * Returns callback object. + */ + callback& get_callback() const + { + return runner_.get_callback(); + } + + /** + * Returns list of known test groups. + */ + groupnames list_groups() const + { + return runner_.list_groups(); + } + + /** + * Runs all tests in all groups. + */ + void run_tests() const + { + // where last run was failed + std::string fail_group; + int fail_test; + read_log_(fail_group,fail_test); + bool fail_group_reached = (fail_group == ""); + + // iterate over groups + tut::groupnames gn = list_groups(); + tut::groupnames::const_iterator gni,gne; + gni = gn.begin(); + gne = gn.end(); + while (gni != gne) + { + // skip all groups before one that failed + if (!fail_group_reached) + { + if (*gni != fail_group) + { + ++gni; + continue; + } + fail_group_reached = true; + } + + // first or restarted run + int test = (*gni == fail_group && fail_test >= 0) ? fail_test + 1 : 1; + while(true) + { + // last executed test pos + register_execution_(*gni,test); + + try + { + tut::test_result tr = runner_.run_test(*gni,test); + register_test_(tr); + } + catch (const tut::beyond_last_test&) + { + break; + } + catch(const tut::no_such_test&) + { + // it's ok + } + + ++test; + } + + ++gni; + } + + // show final results to user + invoke_callback_(); + + // truncate files as mark of successful finish + truncate_(); + } + +private: + /** + * Shows results from journal file. + */ + void invoke_callback_() const + { + runner_.set_callback(callback_); + runner_.get_callback().run_started(); + + std::string current_group; + std::ifstream ijournal(jrn_.c_str()); + while (ijournal.good()) + { + // read next test result + try + { + tut::test_result tr; + util::deserialize(ijournal,tr); + runner_.get_callback().test_completed(tr); + } + catch (const no_more_tests&) + { + break; + } + } + + runner_.get_callback().run_completed(); + } + + /** + * Register test into journal. + */ + void register_test_(const test_result& tr) const + { + std::ofstream ojournal(jrn_.c_str(), std::ios::app); + util::serialize(ojournal, tr); + ojournal << std::flush; + if (!ojournal.good()) + { + boost::throw_exception(std::runtime_error("unable to register test result in file " + + jrn_)); + } + } + + /** + * Mark the fact test going to be executed + */ + void register_execution_(const std::string& grp, int test) const + { + // last executed test pos + std::ofstream olog(log_.c_str()); + olog << util::escape(grp) << std::endl << test << std::endl << std::flush; + if (!olog.good()) + { + boost::throw_exception(std::runtime_error("unable to register execution in file " + + log_)); + } + } + + /** + * Truncate tests. + */ + void truncate_() const + { + std::ofstream olog(log_.c_str()); + std::ofstream ojournal(jrn_.c_str()); + } + + /** + * Read log file + */ + void read_log_(std::string& fail_group, int& fail_test) const + { + // read failure point, if any + std::ifstream ilog(log_.c_str()); + std::getline(ilog,fail_group); + fail_group = util::unescape(fail_group); + ilog >> fail_test; + if (!ilog.good()) + { + fail_group = ""; + fail_test = -1; + truncate_(); + } + else + { + // test was terminated... + tut::test_result tr(fail_group, fail_test, "", tut::test_result::term); + register_test_(tr); + } + } +}; + +} + +#endif + diff --git a/indra/externals/tut/tut/tut_result.hpp b/indra/externals/tut/tut/tut_result.hpp new file mode 100644 index 00000000000..6262e76e5af --- /dev/null +++ b/indra/externals/tut/tut/tut_result.hpp @@ -0,0 +1,130 @@ +#ifndef TUT_RESULT_H_GUARD +#define TUT_RESULT_H_GUARD + +#include + +namespace tut +{ + +#if defined(TUT_USE_POSIX) +struct test_result_posix +{ + test_result_posix() + : pid(getpid()) + { + } + + pid_t pid; +}; +#else +struct test_result_posix +{ +}; +#endif + +/** + * Return type of runned test/test group. + * + * For test: contains result of test and, possible, message + * for failure or exception. + */ +struct test_result : public test_result_posix +{ + /** + * Test group name. + */ + std::string group; + + /** + * Test number in group. + */ + int test; + + /** + * Test name (optional) + */ + std::string name; + + /** + * ok - test finished successfully + * fail - test failed with ensure() or fail() methods + * ex - test throwed an exceptions + * warn - test finished successfully, but test destructor throwed + * term - test forced test application to terminate abnormally + * skip - test skpped because it is a known failure case + */ + enum result_type + { + ok, + fail, + ex, + warn, + term, + ex_ctor, + rethrown, + skip, + }; + + result_type result; + + /** + * Exception message for failed test. + */ + std::string message; + std::string exception_typeid; + + /** + * Default constructor. + */ + test_result() + : test(0), + result(ok) + { + } + + /** + * Constructor. + */ + test_result(const std::string& grp, int pos, + const std::string& test_name, result_type res) + : group(grp), + test(pos), + name(test_name), + result(res) + { + } + + /** + * Constructor with exception. + */ + test_result(const std::string& grp,int pos, + const std::string& test_name, result_type res, + const std::exception& ex) + : group(grp), + test(pos), + name(test_name), + result(res), + message(ex.what()), + exception_typeid(typeid(ex).name()) + { + } + + /** Constructor with typeid. + */ + test_result(const std::string& grp,int pos, + const std::string& test_name, result_type res, + const std::string& ex_typeid, + const std::string& msg) + : group(grp), + test(pos), + name(test_name), + result(res), + message(msg), + exception_typeid(ex_typeid) + { + } +}; + +} + +#endif diff --git a/indra/externals/tut/tut/tut_runner.hpp b/indra/externals/tut/tut/tut_runner.hpp new file mode 100644 index 00000000000..28083d75cf8 --- /dev/null +++ b/indra/externals/tut/tut/tut_runner.hpp @@ -0,0 +1,303 @@ +#ifndef TUT_RUNNER_H_GUARD +#define TUT_RUNNER_H_GUARD + +#include +#include +#include "tut_exception.hpp" +#include + +namespace tut +{ + +/** + * Interface. + * Test group operations. + */ +struct group_base +{ + virtual ~group_base() + { + } + + // execute tests iteratively + virtual void rewind() = 0; + virtual test_result run_next() = 0; + + // execute one test + virtual test_result run_test(int n) = 0; +}; + + +/** + * Test runner callback interface. + * Can be implemented by caller to update + * tests results in real-time. User can implement + * any of callback methods, and leave unused + * in default implementation. + */ +struct callback +{ + /** + * Virtual destructor is a must for subclassed types. + */ + virtual ~callback() + { + } + + /** + * Called when new test run started. + */ + virtual void run_started() + { + } + + /** + * Called when a group started + * @param name Name of the group + */ + virtual void group_started(const std::string& /*name*/) + { + } + + /** + * Called when a test finished. + * @param tr Test results. + */ + virtual void test_completed(const test_result& /*tr*/) + { + } + + /** + * Called when a group is completed + * @param name Name of the group + */ + virtual void group_completed(const std::string& /*name*/) + { + } + + /** + * Called when all tests in run completed. + */ + virtual void run_completed() + { + } +}; + +/** + * Typedef for runner::list_groups() + */ +typedef std::vector groupnames; + +/** + * Test runner. + */ +class test_runner +{ + +public: + + /** + * Constructor + */ + test_runner() + : callback_(&default_callback_) + { + } + + /** + * Stores another group for getting by name. + */ + void register_group(const std::string& name, group_base* gr) + { + if (gr == 0) + { + boost::throw_exception(tut_error("group shall be non-null")); + } + + if (groups_.find(name) != groups_.end()) + { + std::string msg("attempt to add already existent group " + name); + // this exception terminates application so we use cerr also + // TODO: should this message appear in stream? + std::cerr << msg << std::endl; + boost::throw_exception(tut_error(msg)); + } + + groups_.insert( std::make_pair(name, gr) ); + } + + /** + * Stores callback object. + */ + void set_callback(callback* cb) + { + callback_ = cb == 0 ? &default_callback_ : cb; + } + + /** + * Returns callback object. + */ + callback& get_callback() const + { + return *callback_; + } + + /** + * Returns list of known test groups. + */ + const groupnames list_groups() const + { + groupnames ret; + const_iterator i = groups_.begin(); + const_iterator e = groups_.end(); + while (i != e) + { + ret.push_back(i->first); + ++i; + } + return ret; + } + + /** + * Runs all tests in all groups. + * @param callback Callback object if exists; null otherwise + */ + void run_tests() const + { + callback_->run_started(); + + const_iterator i = groups_.begin(); + const_iterator e = groups_.end(); + while (i != e) + { + callback_->group_started(i->first); + try + { + run_all_tests_in_group_(i); + } + catch (const no_more_tests&) + { + callback_->group_completed(i->first); + } + + ++i; + } + + callback_->run_completed(); + } + + /** + * Runs all tests in specified group. + */ + void run_tests(const std::string& group_name) const + { + callback_->run_started(); + + const_iterator i = groups_.find(group_name); + if (i == groups_.end()) + { + callback_->run_completed(); + boost::throw_exception(no_such_group(group_name)); + } + + callback_->group_started(group_name); + try + { + run_all_tests_in_group_(i); + } + catch (const no_more_tests&) + { + // ok + } + + callback_->group_completed(group_name); + callback_->run_completed(); + } + + /** + * Runs one test in specified group. + */ + test_result run_test(const std::string& group_name, int n) const + { + callback_->run_started(); + + const_iterator i = groups_.find(group_name); + if (i == groups_.end()) + { + callback_->run_completed(); + boost::throw_exception(no_such_group(group_name)); + } + + callback_->group_started(group_name); + try + { + test_result tr = i->second->run_test(n); + callback_->test_completed(tr); + callback_->group_completed(group_name); + callback_->run_completed(); + return tr; + } + catch (const beyond_last_test&) + { + callback_->group_completed(group_name); + callback_->run_completed(); + throw; + } + catch (const no_such_test&) + { + callback_->group_completed(group_name); + callback_->run_completed(); + throw; + } + } + +protected: + + typedef std::map groups; + typedef groups::iterator iterator; + typedef groups::const_iterator const_iterator; + groups groups_; + + callback default_callback_; + callback* callback_; + + +private: + + void run_all_tests_in_group_(const_iterator i) const + { + i->second->rewind(); + for ( ;; ) + { + test_result tr = i->second->run_next(); + callback_->test_completed(tr); + + if (tr.result == test_result::ex_ctor) + { + boost::throw_exception(no_more_tests()); + } + } + } +}; + +/** + * Singleton for test_runner implementation. + * Instance with name runner_singleton shall be implemented + * by user. + */ +class test_runner_singleton +{ +public: + + static test_runner& get() + { + static test_runner tr; + return tr; + } +}; + +extern test_runner_singleton runner; + +} + +#endif diff --git a/indra/integration_tests/llimage_libtest/CMakeLists.txt b/indra/integration_tests/llimage_libtest/CMakeLists.txt index 40837c8abba..07cd6af9914 100644 --- a/indra/integration_tests/llimage_libtest/CMakeLists.txt +++ b/indra/integration_tests/llimage_libtest/CMakeLists.txt @@ -1,21 +1,13 @@ # -*- cmake -*- # Integration tests of the llimage library (JPEG2000, PNG, jpeg, etc... images reading and writing) -if (LL_TESTS) - -project (llimage_libtest) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLMath) +if (BUILD_TESTING) set(llimage_libtest_SOURCE_FILES llimage_libtest.cpp ) set(llimage_libtest_HEADER_FILES - CMakeLists.txt llimage_libtest.h ) @@ -30,13 +22,6 @@ set_target_properties(llimage_libtest FOLDER "Tests" ) -if(DARWIN) - set_target_properties(llimage_libtest - PROPERTIES - OSX_ARCHITECTURES ${LL_MACOS_TEST_ARCHITECTURE} - ) -endif() - # Libraries on which this application depends on # Sort by high-level to low-level target_link_libraries(llimage_libtest @@ -46,7 +31,9 @@ target_link_libraries(llimage_libtest llimage ) -# Ensure people working on the viewer don't break this library -add_dependencies(viewer llimage_libtest) +if (BUILD_VIEWER) + # Ensure people working on the viewer don't break this library + add_dependencies(viewer llimage_libtest) +endif (BUILD_VIEWER) -endif(LL_TESTS) +endif() diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt index 19ae1ae2159..b249660ff80 100644 --- a/indra/integration_tests/llui_libtest/CMakeLists.txt +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -4,24 +4,6 @@ # related to the viewer if (VIEWER) -project (llui_libtest) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLImageJ2COJ) # ugh, needed for images -include(LLKDU) -include(LLMath) -include(LLMessage) -include(LLRender) -include(LLWindow) -include(LLUI) -include(LLFileSystem) -include(LLXML) -include(Hunspell) -include(Linking) -# include(Tut) - set(llui_libtest_SOURCE_FILES llui_libtest.cpp llwidgetreg.cpp @@ -71,13 +53,6 @@ if (WINDOWS) ) endif (WINDOWS) -if(DARWIN) - set_target_properties(llui_libtest - PROPERTIES - OSX_ARCHITECTURES ${LL_MACOS_TEST_ARCHITECTURE} - ) -endif() - # Ensure people working on the viewer don't break this library # *NOTE: This could be removed, or only built by Parabuild, if the build # and link times become too long. JC diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index 1bd65eb57df..244c5c5a633 100644 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -71,9 +71,9 @@ def proper_windows_path(path, current_platform = sys.platform): path = path.strip() drive_letter = None rel = None - match = re.match("/cygdrive/([a-z])/(.*)", path) + match = re.match(r"/cygdrive/([a-z])/(.*)", path) if not match: - match = re.match('([a-zA-Z]):\\\(.*)', path) + match = re.match(r'([a-zA-Z]):\\(.*)', path) if not match: return None # not an absolute path drive_letter = match.group(1) @@ -109,8 +109,8 @@ def get_default_platform(dummy): dict(name='arch', description="""This argument is appended to the platform string for determining which manifest class to run. - Example use: %(name)s --arch=i686 - On Linux this would try to use Linux_i686Manifest.""", + Example use: %(name)s --arch=x86_64 + On Linux this would try to use Linux_x86_64_Manifest.""", default=""), dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE), dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE), @@ -129,6 +129,9 @@ def get_default_platform(dummy): description="""The build configurations sub directory used.""", default="Release"), dict(name='dest', description='Destination directory.', default=DEFAULT_SRCTREE), + dict(name='generator', + description="""Name of cmake generator used to create project""", + default=None), dict(name='grid', description="""Which grid the client will try to connect to.""", default=None), @@ -139,6 +142,7 @@ def get_default_platform(dummy): dict(name='login_url', description="""The url that the login screen displays in the client.""", default=None), + dict(name='vcpkg_dir', description='vcpkg directory.', default=None), dict(name='platform', description="""The current platform, to be used for looking up which manifest class to run.""", @@ -309,7 +313,7 @@ def main(extra=[]): class LLManifestRegistry(type): def __init__(cls, name, bases, dct): super(LLManifestRegistry, cls).__init__(name, bases, dct) - match = re.match("(\w+)Manifest", name) + match = re.match(r"(\w+)Manifest", name) if match: cls.manifests[match.group(1).lower()] = cls @@ -658,11 +662,12 @@ def process_either(self, src, dst): def process_file(self, src, dst): if self.includes(src, dst): - for action in self.actions: - methodname = action + "_action" - method = getattr(self, methodname, None) - if method is not None: - method(src, dst) + if src != dst: + for action in self.actions: + methodname = action + "_action" + method = getattr(self, methodname, None) + if method is not None: + method(src, dst) self.file_list.append([src, dst]) return 1 else: @@ -848,7 +853,6 @@ def try_path(src): count = 0 if self.wildcard_pattern.search(src): for s,d in self.expand_globs(src, dst): - assert(s != d) count += self.process_file(s, d) else: # if we're specifying a single path (not a glob), diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt index 5b6d68fa377..c409edbf2d7 100644 --- a/indra/llappearance/CMakeLists.txt +++ b/indra/llappearance/CMakeLists.txt @@ -1,14 +1,5 @@ # -*- cmake -*- -project(llappearance) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLCoreHttp) -include(LLWindow) -include(Linking) - set(llappearance_SOURCE_FILES llavatarappearance.cpp llavatarjoint.cpp @@ -30,8 +21,6 @@ set(llappearance_SOURCE_FILES ) set(llappearance_HEADER_FILES - CMakeLists.txt - llavatarappearance.h llavatarjoint.h llavatarjointmesh.h @@ -56,6 +45,7 @@ list(APPEND llappearance_SOURCE_FILES ${llappearance_HEADER_FILES}) add_library (llappearance ${llappearance_SOURCE_FILES}) target_link_libraries(llappearance + PUBLIC llcharacter llinventory llimage @@ -68,16 +58,14 @@ target_link_libraries(llappearance llcommon ) target_include_directories( llappearance INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llappearance REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llappearance REUSE_FROM llprecompiled) if (BUILD_HEADLESS) add_library (llappearanceheadless ${llappearance_SOURCE_FILES}) target_include_directories( llappearanceheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(llappearanceheadless + PUBLIC llcharacter llinventory llimage @@ -89,8 +77,6 @@ if (BUILD_HEADLESS) llcorehttp llcommon ) - - if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llappearanceheadless REUSE_FROM llprecompiled) - endif () + + target_precompile_headers(llappearanceheadless REUSE_FROM llprecompiled) endif (BUILD_HEADLESS) diff --git a/indra/llappearanceutility/CMakeLists.txt b/indra/llappearanceutility/CMakeLists.txt index 53b5ce1cbeb..face97f4c89 100644 --- a/indra/llappearanceutility/CMakeLists.txt +++ b/indra/llappearanceutility/CMakeLists.txt @@ -1,16 +1,5 @@ # -*- cmake -*- -project(appearance_utility) - -include(00-Common) -include(Boost) -include(LLAppearance) -include(LLCommon) -include(LLImage) -include(LLMath) -include(LLWindow) -include(Linking) - set(appearance_utility_SOURCE_FILES appearance_utility.cpp llappappearanceutility.cpp @@ -30,7 +19,6 @@ set(appearance_utility_SOURCE_FILES ) set(appearance_utility_HEADER_FILES - CMakeLists.txt llappappearanceutility.h llbakingavatar.h llbakingjoint.h @@ -63,13 +51,11 @@ target_link_libraries(appearance-utility-bin llxml ) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(appearance-utility-bin REUSE_FROM llprecompiled) -endif () +target_precompile_headers(appearance-utility-bin REUSE_FROM llprecompiled_exe) if (BUILD_HEADLESS) add_executable(appearance-utility-headless-bin ${appearance_utility_SOURCE_FILES}) - + target_link_libraries(appearance-utility-headless-bin llcharacter llinventory @@ -78,9 +64,7 @@ if (BUILD_HEADLESS) llrenderheadless llxml ) - - if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(appearance-utility-headless-bin REUSE_FROM llprecompiled) - endif () + + target_precompile_headers(appearance-utility-headless-bin REUSE_FROM llprecompiled_exe) endif (BUILD_HEADLESS) diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 18e29fb194c..b9390202b2a 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -1,22 +1,19 @@ # -*- cmake -*- -project(llaudio) +add_library(llaudio STATIC) -include(00-Common) -include(LLAudio) -include(OPENAL) -include(LLCommon) - -set(llaudio_SOURCE_FILES +target_sources(llaudio + PRIVATE llaudioengine.cpp lllistener.cpp llaudiodecodemgr.cpp llvorbisencode.cpp ) -set(llaudio_HEADER_FILES - CMakeLists.txt - +target_sources(llaudio + PUBLIC + FILE_SET HEADERS + FILES llaudioengine.h lllistener.h llaudiodecodemgr.h @@ -24,23 +21,9 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (TARGET ll::openal) - list(APPEND llaudio_SOURCE_FILES - llaudioengine_openal.cpp - lllistener_openal.cpp - ) - - list(APPEND llaudio_HEADER_FILES - llaudioengine_openal.h - lllistener_openal.h - ) -endif () - -list(APPEND llaudio_SOURCE_FILES ${llaudio_HEADER_FILES}) - -add_library (llaudio ${llaudio_SOURCE_FILES}) target_include_directories( llaudio INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries( llaudio + PUBLIC llcommon llmath llmessage @@ -48,13 +31,22 @@ target_link_libraries( llaudio ll::vorbis ) -if( TARGET ll::openal ) - target_link_libraries( llaudio ll::openal ) -endif() -if( TARGET ll::fmodstudio ) - target_link_libraries( llaudio ll::fmodstudio ) -endif() +target_precompile_headers(llaudio REUSE_FROM llprecompiled) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llaudio REUSE_FROM llprecompiled) +if (TARGET ll::openal) + target_sources(llaudio + PRIVATE + llaudioengine_openal.cpp + lllistener_openal.cpp + ) + + target_sources(llaudio + PUBLIC + FILE_SET HEADERS + FILES + llaudioengine_openal.h + lllistener_openal.h + ) + + target_link_libraries(llaudio PUBLIC ll::openal) endif () diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt index 9dbbddde8ae..57263237feb 100644 --- a/indra/llcharacter/CMakeLists.txt +++ b/indra/llcharacter/CMakeLists.txt @@ -1,11 +1,9 @@ # -*- cmake -*- -project(llcharacter) +add_library(llcharacter STATIC) -include(00-Common) -include(LLCommon) - -set(llcharacter_SOURCE_FILES +target_sources(llcharacter + PRIVATE llanimationstates.cpp llbvhloader.cpp llcharacter.cpp @@ -27,9 +25,11 @@ set(llcharacter_SOURCE_FILES llvisualparam.cpp ) -set(llcharacter_HEADER_FILES - CMakeLists.txt - +target_sources(llcharacter + PUBLIC + FILE_SET HEADERS + BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} + FILES llanimationstates.h llbvhloader.h llbvhconsts.h @@ -53,32 +53,27 @@ set(llcharacter_HEADER_FILES llvisualparam.h ) -list(APPEND llcharacter_SOURCE_FILES ${llcharacter_HEADER_FILES}) - -add_library (llcharacter ${llcharacter_SOURCE_FILES}) -target_include_directories( llcharacter INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(llcharacter INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries( - llcharacter - llcommon - llmath - llmessage - llfilesystem - llxml + llcharacter + PUBLIC + llcommon + llmath + llmessage + llfilesystem + llxml ) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llcharacter REUSE_FROM llprecompiled) -endif () - +target_precompile_headers(llcharacter REUSE_FROM llprecompiled) -if (LL_TESTS) - include(LLAddBuildTest) +if (BUILD_TESTING) # SET(llcharacter_TEST_SOURCE_FILES # ) # LL_ADD_PROJECT_UNIT_TESTS(llcharacter "${llcharacter_TEST_SOURCE_FILES}") #set(TEST_DEBUG on) set(test_libs llcommon llmath) - LL_ADD_INTEGRATION_TEST(lljoint "lljoint.cpp" "${test_libs}") + set(test_project llcharacter) + LL_ADD_INTEGRATION_TEST(lljoint "lljoint.cpp" "${test_libs}" "${test_project}") endif() diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index bff3c669241..d9ab0673d22 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -1,19 +1,9 @@ # -*- cmake -*- -project(llcommon) +add_library(llcommon STATIC) -include(00-Common) -include(LLCommon) -include(bugsplat) -include(Linking) -include(Boost) -include(LLSharedLibs) -include(Copy3rdPartyLibs) -include(ZLIBNG) -include(Tracy) -include(SSE2NEON) - -set(llcommon_SOURCE_FILES +target_sources(llcommon + PRIVATE apply.cpp commoncontrol.cpp indra_constants.cpp @@ -106,12 +96,12 @@ set(llcommon_SOURCE_FILES u64.cpp threadpool.cpp workqueue.cpp - StackWalker.cpp - ) - -set(llcommon_HEADER_FILES - CMakeLists.txt +) +target_sources(llcommon + PUBLIC + FILE_SET HEADERS + FILES always_return.h apply.h chrono.h @@ -249,12 +239,17 @@ set(llcommon_HEADER_FILES tuple.h u64.h workqueue.h - StackWalker.h ) if (DARWIN) - list(APPEND llcommon_HEADER_FILES llsys_objc.h) - list(APPEND llcommon_SOURCE_FILES llsys_objc.mm) + target_sources(llcommon + PRIVATE + llsys_objc.mm + PUBLIC + FILE_SET HEADERS + FILES + llsys_objc.h + ) set_source_files_properties( llsys_objc.mm @@ -264,23 +259,17 @@ if (DARWIN) endif (DARWIN) if (USE_TRACY) - list(APPEND llcommon_SOURCE_FILES llprofiler.cpp) - # Skip precompiled headers on these files due to special compilation needs set_source_files_properties( llfasttimer.cpp - llprofiler.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE ) endif () -list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) - -add_library (llcommon ${llcommon_SOURCE_FILES}) - target_link_libraries( llcommon + PUBLIC ll::apr ll::expat ll::zlib-ng @@ -288,19 +277,18 @@ target_link_libraries( ll::oslibraries ll::tracy ll::sse2neon + ll::xxhash + Threads::Threads ) target_include_directories(llcommon PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories(llcommon PRIVATE ${CMAKE_SOURCE_DIR}/llmath) +target_include_directories(llcommon PRIVATE ${INDRA_SOURCE_DIR}/llmath) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llcommon REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llcommon REUSE_FROM llprecompiled) add_dependencies(llcommon stage_third_party_libs) -if (LL_TESTS) - include(LLAddBuildTest) +if (BUILD_TESTING) SET(llcommon_TEST_SOURCE_FILES # unit-testing llcommon is not possible right now as the test-harness *itself* depends upon llcommon, causing a circular dependency. Add your 'unit' tests as integration tests for now. ) @@ -308,54 +296,55 @@ if (LL_TESTS) #set(TEST_DEBUG on) set(test_libs llcommon) - LL_ADD_INTEGRATION_TEST(apply "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(classic_callback "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lazyeventapi "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llapp "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llcond "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lldate "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lldeadmantimer "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lldependencies "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lldoubledispatch "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lleventfilter "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llevents "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llfile "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llhttpdate "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llheteromap "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llmainthreadtask "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llpounceable "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llsd "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llsdutil "" "llcommon;llmath") - LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llstreamtools "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lltrace "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(threadsafeschedule "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(tuple "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(workqueue "" "${test_libs}") + set(test_project llcommon) + LL_ADD_INTEGRATION_TEST(apply "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(bitpack "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(classic_callback "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(commonmisc "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lazyeventapi "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llapp "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llbase64 "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llcond "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lldate "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lldeadmantimer "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lldependencies "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lldoubledispatch "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lleventfilter "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llevents "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llfile "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llhttpdate "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llheteromap "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llleap "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llmainthreadtask "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llpounceable "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llprocess "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llsd "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llsdutil "" "llcommon;llmath" "${test_project}") + LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llstreamtools "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lltrace "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(threadsafeschedule "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(tuple "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(workqueue "" "${test_libs}" "${test_project}") ## llexception_test.cpp isn't a regression test, and doesn't need to be run ## every build. It's to help a developer make implementation choices about ## throwing and catching exceptions. -##LL_ADD_INTEGRATION_TEST(llexception "" "${test_libs}") +##LL_ADD_INTEGRATION_TEST(llexception "" "${test_libs}" "${test_project}") # Skip precompiled header for tests that need special handling set_source_files_properties( @@ -364,4 +353,4 @@ if (LL_TESTS) SKIP_PRECOMPILE_HEADERS TRUE ) -endif (LL_TESTS) +endif () diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp deleted file mode 100644 index a281fe83f66..00000000000 --- a/indra/llcommon/StackWalker.cpp +++ /dev/null @@ -1,1393 +0,0 @@ -/********************************************************************** - * - * StackWalker.cpp - * http://stackwalker.codeplex.com/ - * - * - * $LicenseInfo:firstyear=2016&license=bsd$ - * - * Linden notes: Small modifications from the original source at https://stackwalker.codeplex.com/ - * - * History: - * 2005-07-27 v1 - First public release on http://www.codeproject.com/ - * http://www.codeproject.com/threads/StackWalker.asp - * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack - * (to simplify the usage) - * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL - * (should also be enough) - * - Changed to compile correctly with the PSDK of VC7.0 - * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: - * it uses LPSTR instead of LPCSTR as first paremeter) - * - Added declarations to support VC5/6 without using 'dbghelp.h' - * - Added a 'pUserData' member to the ShowCallstack function and the - * PReadProcessMemoryRoutine declaration (to pass some user-defined data, - * which can be used in the readMemoryFunction-callback) - * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default - * - Added example for doing an exception-callstack-walking in main.cpp - * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268) - * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse! - * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx - * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN" - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx - * Fixed Bug: Compiling with "/Wall" - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx - * Fixed Bug: Now checking SymUseSymSrv - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx - * Fixed Bug: Support for recursive function calls - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx - * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32" - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx - * Fixed Bug: SymDia is number 7, not 9! - * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8! - * Thanks to Teajay which reported the bug... - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx - * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory - * Thanks to Luiz Salamon which reported this "bug"... - * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx - * 2009-04-10 v9 License slihtly corrected ( replaced) - * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/ - * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available - * 2010-04-15 v12 Added support for VS2010 RTM - * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon: - * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx - * 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed: - * http://stackwalker.codeplex.com/workitem/10511 - * - * - * LICENSE (http://www.opensource.org/licenses/bsd-license.php) - * - * Copyright (c) 2005-2013, Jochen Kalmbach - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - **********************************************************************/ -#if LL_WINDOWS - -#include -#include -#include -#include -#pragma comment(lib, "version.lib") // for "VerQueryValue" -#pragma warning(disable:4826) - -#include "StackWalker.h" - - -// If VC7 and later, then use the shipped 'dbghelp.h'-file -#pragma pack(push,8) -#if _MSC_VER >= 1300 -#pragma warning (push) -#pragma warning (disable:4091) // a microsoft header has warnings. Very nice. -#include -#pragma warning (pop) -#else -// inline the important dbghelp.h-declarations... -typedef enum { - SymNone = 0, - SymCoff, - SymCv, - SymPdb, - SymExport, - SymDeferred, - SymSym, - SymDia, - SymVirtual, - NumSymTypes -} SYM_TYPE; -typedef struct _IMAGEHLP_LINE64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) - PVOID Key; // internal - DWORD LineNumber; // line number in file - PCHAR FileName; // full filename - DWORD64 Address; // first instruction of line -} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; -typedef struct _IMAGEHLP_MODULE64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name -} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; -typedef struct _IMAGEHLP_SYMBOL64 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) - DWORD64 Address; // virtual address including dll base address - DWORD Size; // estimated size of symbol, can be zero - DWORD Flags; // info about the symbols, see the SYMF defines - DWORD MaxNameLength; // maximum size of symbol name in 'Name' - CHAR Name[1]; // symbol name (null terminated string) -} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; -typedef enum { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat -} ADDRESS_MODE; -typedef struct _tagADDRESS64 { - DWORD64 Offset; - WORD Segment; - ADDRESS_MODE Mode; -} ADDRESS64, *LPADDRESS64; -typedef struct _KDHELP64 { - DWORD64 Thread; - DWORD ThCallbackStack; - DWORD ThCallbackBStore; - DWORD NextCallback; - DWORD FramePointer; - DWORD64 KiCallUserMode; - DWORD64 KeUserCallbackDispatcher; - DWORD64 SystemRangeStart; - DWORD64 Reserved[8]; -} KDHELP64, *PKDHELP64; -typedef struct _tagSTACKFRAME64 { - ADDRESS64 AddrPC; // program counter - ADDRESS64 AddrReturn; // return address - ADDRESS64 AddrFrame; // frame pointer - ADDRESS64 AddrStack; // stack pointer - ADDRESS64 AddrBStore; // backing store pointer - PVOID FuncTableEntry; // pointer to pdata/fpo or NULL - DWORD64 Params[4]; // possible arguments to the function - BOOL Far; // WOW far call - BOOL Virtual; // is this a virtual frame? - DWORD64 Reserved[3]; - KDHELP64 KdHelp; -} STACKFRAME64, *LPSTACKFRAME64; -typedef -BOOL -(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( - HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead - ); -typedef -PVOID -(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( - HANDLE hProcess, - DWORD64 AddrBase - ); -typedef -DWORD64 -(__stdcall *PGET_MODULE_BASE_ROUTINE64)( - HANDLE hProcess, - DWORD64 Address - ); -typedef -DWORD64 -(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( - HANDLE hProcess, - HANDLE hThread, - LPADDRESS64 lpaddr - ); -#define SYMOPT_CASE_INSENSITIVE 0x00000001 -#define SYMOPT_UNDNAME 0x00000002 -#define SYMOPT_DEFERRED_LOADS 0x00000004 -#define SYMOPT_NO_CPP 0x00000008 -#define SYMOPT_LOAD_LINES 0x00000010 -#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 -#define SYMOPT_LOAD_ANYTHING 0x00000040 -#define SYMOPT_IGNORE_CVREC 0x00000080 -#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 -#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 -#define SYMOPT_EXACT_SYMBOLS 0x00000400 -#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 -#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 -#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 -#define SYMOPT_PUBLICS_ONLY 0x00004000 -#define SYMOPT_NO_PUBLICS 0x00008000 -#define SYMOPT_AUTO_PUBLICS 0x00010000 -#define SYMOPT_NO_IMAGE_SEARCH 0x00020000 -#define SYMOPT_SECURE 0x00040000 -#define SYMOPT_DEBUG 0x80000000 -#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration -#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; -#endif // _MSC_VER < 1300 -#pragma pack(pop) - -// Some missing defines (for VC5/6): -#ifndef INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif - - -// secure-CRT_functions are only available starting with VC8 -#if _MSC_VER < 1400 -#define strcpy_s(dst, len, src) strcpy(dst, src) -#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src) -#define strcat_s(dst, len, src) strcat(dst, src) -#define _snprintf_s _snprintf -#define _tcscat_s _tcscat -#endif - -static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc) -{ - if (nMaxDestSize <= 0) return; - strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE); - szDest[nMaxDestSize-1] = 0; // INFO: _TRUNCATE will ensure that it is nul-terminated; but with older compilers (<1400) it uses "strncpy" and this does not!) -} // MyStrCpy - -// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL') -#define USED_CONTEXT_FLAGS CONTEXT_FULL - - -class StackWalkerInternal -{ -public: - StackWalkerInternal(StackWalker *parent, HANDLE hProcess) - { - m_parent = parent; - m_hDbhHelp = NULL; - pSC = NULL; - m_hProcess = hProcess; - m_szSymPath = NULL; - pSFTA = NULL; - pSGLFA = NULL; - pSGMB = NULL; - pSGMI = NULL; - pSGO = NULL; - pSGSFA = NULL; - pSI = NULL; - pSLM = NULL; - pSSO = NULL; - pSW = NULL; - pUDSN = NULL; - pSGSP = NULL; - } - ~StackWalkerInternal() - { - if (pSC != NULL) - pSC(m_hProcess); // SymCleanup - if (m_hDbhHelp != NULL) - FreeLibrary(m_hDbhHelp); - m_hDbhHelp = NULL; - m_parent = NULL; - if(m_szSymPath != NULL) - free(m_szSymPath); - m_szSymPath = NULL; - } - bool Init(LPCSTR szSymPath) - { - if (m_parent == NULL) - return false; - // Dynamically load the Entry-Points for dbghelp.dll: - // First try to load the newsest one from - TCHAR szTemp[4096]; - // But before wqe do this, we first check if the ".local" file exists - if (GetModuleFileName(NULL, szTemp, 4096) > 0) - { - _tcscat_s(szTemp, _T(".local")); - if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES) - { - // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows" - // Ok, first try the new path according to the archtitecture: -#ifdef _M_IX86 - if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#elif _M_X64 - if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#elif _M_IA64 - if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#endif - // If still not found, try the old directories... - if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll")); - // now check if the file exists: - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#if defined _M_X64 || defined _M_IA64 - // Still not found? Then try to load the (old) 64-Bit version: - if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ) - { - _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll")); - if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES) - { - m_hDbhHelp = LoadLibrary(szTemp); - } - } -#endif - } - } - if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one - m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") ); - if (m_hDbhHelp == NULL) - return false; - pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" ); - pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" ); - - pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" ); - pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" ); - pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" ); - - pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" ); - pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" ); - pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" ); - pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" ); - pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" ); - pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" ); - pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" ); - pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" ); - - if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || - pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL || - pSW == NULL || pUDSN == NULL || pSLM == NULL ) - { - FreeLibrary(m_hDbhHelp); - m_hDbhHelp = NULL; - pSC = NULL; - return false; - } - - // SymInitialize - if (szSymPath != NULL) - m_szSymPath = _strdup(szSymPath); - if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) - this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); - - DWORD symOptions = this->pSGO(); // SymGetOptions - symOptions |= SYMOPT_LOAD_LINES; - symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; - //symOptions |= SYMOPT_NO_PROMPTS; - // SymSetOptions - symOptions = this->pSSO(symOptions); - - char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0}; - if (this->pSGSP != NULL) - { - if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE) - this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0); - } - char szUserName[1024] = {0}; - DWORD dwSize = 1024; - GetUserNameA(szUserName, &dwSize); - this->m_parent->OnSymInit(buf, symOptions, szUserName); - - return true; - } - - StackWalker *m_parent; - - HMODULE m_hDbhHelp; - HANDLE m_hProcess; - LPSTR m_szSymPath; - -#pragma pack(push,8) -struct IMAGEHLP_MODULE64_V3 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name - // new elements: 07-Jun-2002 - CHAR LoadedPdbName[256]; // pdb file name - DWORD CVSig; // Signature of the CV record in the debug directories - CHAR CVData[MAX_PATH * 3]; // Contents of the CV record - DWORD PdbSig; // Signature of PDB - GUID PdbSig70; // Signature of PDB (VC 7 and up) - DWORD PdbAge; // DBI age of pdb - BOOL PdbUnmatched; // loaded an unmatched pdb - BOOL DbgUnmatched; // loaded an unmatched dbg - BOOL LineNumbers; // we have line number information - BOOL GlobalSymbols; // we have internal symbol information - BOOL TypeInfo; // we have type information - // new elements: 17-Dec-2003 - BOOL SourceIndexed; // pdb supports source server - BOOL Publics; // contains public symbols -}; - -struct IMAGEHLP_MODULE64_V2 { - DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) - DWORD64 BaseOfImage; // base load address of module - DWORD ImageSize; // virtual size of the loaded module - DWORD TimeDateStamp; // date/time stamp from pe header - DWORD CheckSum; // checksum from the pe header - DWORD NumSyms; // number of symbols in the symbol table - SYM_TYPE SymType; // type of symbols loaded - CHAR ModuleName[32]; // module name - CHAR ImageName[256]; // image name - CHAR LoadedImageName[256]; // symbol file name -}; -#pragma pack(pop) - - - // SymCleanup() - typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess ); - tSC pSC; - - // SymFunctionTableAccess64() - typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase ); - tSFTA pSFTA; - - // SymGetLineFromAddr64() - typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, - OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line ); - tSGLFA pSGLFA; - - // SymGetModuleBase64() - typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr ); - tSGMB pSGMB; - - // SymGetModuleInfo64() - typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo ); - tSGMI pSGMI; - - // SymGetOptions() - typedef DWORD (__stdcall *tSGO)( VOID ); - tSGO pSGO; - - // SymGetSymFromAddr64() - typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr, - OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol ); - tSGSFA pSGSFA; - - // SymInitialize() - typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess ); - tSI pSI; - - // SymLoadModule64() - typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile, - IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll ); - tSLM pSLM; - - // SymSetOptions() - typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions ); - tSSO pSSO; - - // StackWalk64() - typedef BOOL (__stdcall *tSW)( - DWORD MachineType, - HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, - PVOID ContextRecord, - PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, - PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress ); - tSW pSW; - - // UnDecorateSymbolName() - typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName, - DWORD UndecoratedLength, DWORD Flags ); - tUDSN pUDSN; - - typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength); - tSGSP pSGSP; - - -private: - // **************************************** ToolHelp32 ************************ - #define MAX_MODULE_NAME32 255 - #define TH32CS_SNAPMODULE 0x00000008 - #pragma pack( push, 8 ) - typedef struct tagMODULEENTRY32 - { - DWORD dwSize; - DWORD th32ModuleID; // This module - DWORD th32ProcessID; // owning process - DWORD GlblcntUsage; // Global usage count on the module - DWORD ProccntUsage; // Module usage count in th32ProcessID's context - BYTE * modBaseAddr; // Base address of module in th32ProcessID's context - DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr - HMODULE hModule; // The hModule of this module in th32ProcessID's context - char szModule[MAX_MODULE_NAME32 + 1]; - char szExePath[MAX_PATH]; - } MODULEENTRY32; - typedef MODULEENTRY32 * PMODULEENTRY32; - typedef MODULEENTRY32 * LPMODULEENTRY32; - #pragma pack( pop ) - - bool GetModuleListTH32(HANDLE hProcess, DWORD pid) - { - // CreateToolhelp32Snapshot() - typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID); - // Module32First() - typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - // Module32Next() - typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - - // try both dlls... - const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") }; - HINSTANCE hToolhelp = NULL; - tCT32S pCT32S = NULL; - tM32F pM32F = NULL; - tM32N pM32N = NULL; - - HANDLE hSnap; - MODULEENTRY32 me; - me.dwSize = sizeof(me); - BOOL keepGoing; - size_t i; - - for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ ) - { - hToolhelp = LoadLibrary( dllname[i] ); - if (hToolhelp == NULL) - continue; - pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot"); - pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First"); - pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next"); - if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) ) - break; // found the functions! - FreeLibrary(hToolhelp); - hToolhelp = NULL; - } - - if (hToolhelp == NULL) - return false; - - hSnap = pCT32S( TH32CS_SNAPMODULE, pid ); - if (hSnap == (HANDLE) -1) - { - FreeLibrary(hToolhelp); - return false; - } - - keepGoing = !!pM32F( hSnap, &me ); - int cnt = 0; - while (keepGoing) - { - this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize); - cnt++; - keepGoing = !!pM32N( hSnap, &me ); - } - CloseHandle(hSnap); - FreeLibrary(hToolhelp); - if (cnt <= 0) - return false; - return true; - } // GetModuleListTH32 - - // **************************************** PSAPI ************************ - typedef struct _MODULEINFO { - LPVOID lpBaseOfDll; - DWORD SizeOfImage; - LPVOID EntryPoint; - } MODULEINFO, *LPMODULEINFO; - - bool GetModuleListPSAPI(HANDLE hProcess) - { - // EnumProcessModules() - typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded ); - // GetModuleFileNameEx() - typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); - // GetModuleBaseName() - typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize ); - // GetModuleInformation() - typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize ); - - HINSTANCE hPsapi; - tEPM pEPM; - tGMFNE pGMFNE; - tGMBN pGMBN; - tGMI pGMI; - - DWORD i; - //ModuleEntry e; - DWORD cbNeeded; - MODULEINFO mi; - HMODULE *hMods = 0; - char *tt = NULL; - char *tt2 = NULL; - const SIZE_T TTBUFLEN = 8096; - int cnt = 0; - - hPsapi = LoadLibrary( _T("psapi.dll") ); - if (hPsapi == NULL) - return false; - - pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" ); - pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" ); - pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" ); - pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" ); - if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ) - { - // we couldn't find all functions - FreeLibrary(hPsapi); - return false; - } - - hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE))); - tt = (char*) malloc(sizeof(char) * TTBUFLEN); - tt2 = (char*) malloc(sizeof(char) * TTBUFLEN); - if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) ) - goto cleanup; - - if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) ) - { - //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle ); - goto cleanup; - } - - if ( cbNeeded > TTBUFLEN ) - { - //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) ); - goto cleanup; - } - - for ( i = 0; i < cbNeeded / sizeof(hMods[0]); i++ ) - { - // base address, size - pGMI(hProcess, hMods[i], &mi, sizeof(mi)); - // image file name - tt[0] = 0; - pGMFNE(hProcess, hMods[i], tt, TTBUFLEN ); - // module name - tt2[0] = 0; - pGMBN(hProcess, hMods[i], tt2, TTBUFLEN ); - - DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage); - if (dwRes != ERROR_SUCCESS) - this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0); - cnt++; - } - - cleanup: - if (hPsapi != NULL) FreeLibrary(hPsapi); - if (tt2 != NULL) free(tt2); - if (tt != NULL) free(tt); - if (hMods != NULL) free(hMods); - - return cnt != 0; - } // GetModuleListPSAPI - - DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size) - { - CHAR *szImg = _strdup(img); - CHAR *szMod = _strdup(mod); - DWORD result = ERROR_SUCCESS; - if ( (szImg == NULL) || (szMod == NULL) ) - result = ERROR_NOT_ENOUGH_MEMORY; - else - { - if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0) - result = GetLastError(); - } - ULONGLONG fileVersion = 0; - if ( (m_parent != NULL) && (szImg != NULL) ) - { - // try to retrive the file-version: - if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0) - { - VS_FIXEDFILEINFO *fInfo = NULL; - DWORD dwHandle; - DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle); - if (dwSize > 0) - { - LPVOID vData = malloc(dwSize); - if (vData != NULL) - { - if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0) - { - UINT len; - TCHAR szSubBlock[] = _T("\\"); - if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0) - fInfo = NULL; - else - { - fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32); - } - } - free(vData); - } - } - } - - // Retrive some additional-infos about the module - IMAGEHLP_MODULE64_V3 Module; - const char *szSymType = "-unknown-"; - if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE) - { - switch(Module.SymType) - { - case SymNone: - szSymType = "-nosymbols-"; - break; - case SymCoff: // 1 - szSymType = "COFF"; - break; - case SymCv: // 2 - szSymType = "CV"; - break; - case SymPdb: // 3 - szSymType = "PDB"; - break; - case SymExport: // 4 - szSymType = "-exported-"; - break; - case SymDeferred: // 5 - szSymType = "-deferred-"; - break; - case SymSym: // 6 - szSymType = "SYM"; - break; - case 7: // SymDia: - szSymType = "DIA"; - break; - case 8: //SymVirtual: - szSymType = "Virtual"; - break; - case NumSymTypes: - break; - } - } - LPCSTR pdbName = Module.LoadedImageName; - if (Module.LoadedPdbName[0] != 0) - pdbName = Module.LoadedPdbName; - this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, fileVersion); - } - if (szImg != NULL) free(szImg); - if (szMod != NULL) free(szMod); - return result; - } -public: - bool LoadModules(HANDLE hProcess, DWORD dwProcessId) - { - // first try toolhelp32 - if (GetModuleListTH32(hProcess, dwProcessId)) - return true; - // then try psapi - return GetModuleListPSAPI(hProcess); - } - - - bool GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3 *pModuleInfo) - { - memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3)); - if(this->pSGMI == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return false; - } - // First try to use the larger ModuleInfo-Structure - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); - void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites... - if (pData == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return false; - } - memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3)); - static bool s_useV3Version = true; - if (s_useV3Version) - { - if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) - { - // only copy as much memory as is reserved... - memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3)); - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3); - free(pData); - return true; - } - s_useV3Version = false; // to prevent unneccessarry calls with the larger struct... - } - - // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)... - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); - memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2)); - if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE) - { - // only copy as much memory as is reserved... - memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2)); - pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2); - free(pData); - return true; - } - free(pData); - SetLastError(ERROR_DLL_INIT_FAILED); - return false; - } -}; - -// ############################################################# -StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess) -{ - this->m_verbose = true; - this->m_options = OptionsAll; - this->m_modulesLoaded = false; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; - this->m_szSymPath = NULL; - this->m_MaxRecursionCount = 1000; -} -StackWalker::StackWalker(bool verbose, int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess) -{ - this->m_verbose = verbose; - this->m_options = options; - this->m_modulesLoaded = false; - this->m_hProcess = hProcess; - this->m_sw = new StackWalkerInternal(this, this->m_hProcess); - this->m_dwProcessId = dwProcessId; - if (szSymPath != NULL) - { - this->m_szSymPath = _strdup(szSymPath); - this->m_options |= SymBuildPath; - } - else - this->m_szSymPath = NULL; - this->m_MaxRecursionCount = 1000; -} - -StackWalker::~StackWalker() -{ - if (m_szSymPath != NULL) - free(m_szSymPath); - m_szSymPath = NULL; - if (this->m_sw != NULL) - delete this->m_sw; - this->m_sw = NULL; -} - -bool StackWalker::LoadModules() -{ - if (this->m_sw == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return false; - } - if (m_modulesLoaded) - return true; - - // Build the sym-path: - char *szSymPath = NULL; - if ( (this->m_options & SymBuildPath) != 0) - { - const size_t nSymPathLen = 4096; - szSymPath = (char*) malloc(nSymPathLen); - if (szSymPath == NULL) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return false; - } - szSymPath[0] = 0; - // Now first add the (optional) provided sympath: - if (this->m_szSymPath != NULL) - { - strcat_s(szSymPath, nSymPathLen, this->m_szSymPath); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - strcat_s(szSymPath, nSymPathLen, ".;"); - - const size_t nTempLen = 1024; - char szTemp[nTempLen]; - // Now add the current directory: - if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - // Now add the path for the main-module: - if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p) - { - // locate the rightmost path separator - if ( (*p == '\\') || (*p == '/') || (*p == ':') ) - { - *p = 0; - break; - } - } // for (search for path separator...) - if (strlen(szTemp) > 0) - { - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - } - if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - // also add the "system32"-directory: - strcat_s(szTemp, nTempLen, "\\system32"); - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, ";"); - } - - if ( (this->m_options & SymUseSymSrv) != 0) - { - if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0) - { - szTemp[nTempLen-1] = 0; - strcat_s(szSymPath, nSymPathLen, "SRV*"); - strcat_s(szSymPath, nSymPathLen, szTemp); - strcat_s(szSymPath, nSymPathLen, "\\websymbols"); - strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;"); - } - else - strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;"); - } - } // if SymBuildPath - - // First Init the whole stuff... - bool bRet = this->m_sw->Init(szSymPath); - if (szSymPath != NULL) free(szSymPath); szSymPath = NULL; - if (!bRet) - { - this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0); - SetLastError(ERROR_DLL_INIT_FAILED); - return false; - } - - bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId); - if (bRet) - m_modulesLoaded = true; - return bRet; -} - - -// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction -// This has to be done due to a problem with the "hProcess"-parameter in x64... -// Because this class is in no case multi-threading-enabled (because of the limitations -// of dbghelp.dll) it is "safe" to use a static-variable -static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; -static LPVOID s_readMemoryFunction_UserData = NULL; - -bool StackWalker::ShowCallstack(bool verbose, HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData) -{ - m_verbose = verbose; - CONTEXT c; - CallstackEntry csEntry; - IMAGEHLP_SYMBOL64 *pSym = NULL; - StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module; - IMAGEHLP_LINE64 Line; - int frameNum; - bool bLastEntryCalled = true; - int curRecursionCount = 0; - - if (!m_modulesLoaded) - this->LoadModules(); // ignore the result... - - if (this->m_sw->m_hDbhHelp == NULL) - { - SetLastError(ERROR_DLL_INIT_FAILED); - return false; - } - - s_readMemoryFunction = readMemoryFunction; - s_readMemoryFunction_UserData = pUserData; - - if (context == NULL) - { - // If no context is provided, capture the context - // See: https://stackwalker.codeplex.com/discussions/446958 -#if _WIN32_WINNT <= 0x0501 - // If we need to support XP, we need to use the "old way", because "GetThreadId" is not available! - if (hThread == GetCurrentThread()) -#else - if (GetThreadId(hThread) == GetCurrentThreadId()) -#endif - { - GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS); - } - else - { - SuspendThread(hThread); - memset(&c, 0, sizeof(CONTEXT)); - c.ContextFlags = USED_CONTEXT_FLAGS; - if (GetThreadContext(hThread, &c) == FALSE) - { - ResumeThread(hThread); - return false; - } - } - } - else - c = *context; - - // init STACKFRAME for first call - STACKFRAME64 s; // in/out stackframe - memset(&s, 0, sizeof(s)); - DWORD imageType; -#ifdef _M_IX86 - // normally, call ImageNtHeader() and use machine info from PE header - imageType = IMAGE_FILE_MACHINE_I386; - s.AddrPC.Offset = c.Eip; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.Ebp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrStack.Offset = c.Esp; - s.AddrStack.Mode = AddrModeFlat; -#elif _M_X64 - imageType = IMAGE_FILE_MACHINE_AMD64; - s.AddrPC.Offset = c.Rip; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.Rsp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrStack.Offset = c.Rsp; - s.AddrStack.Mode = AddrModeFlat; -#elif _M_IA64 - imageType = IMAGE_FILE_MACHINE_IA64; - s.AddrPC.Offset = c.StIIP; - s.AddrPC.Mode = AddrModeFlat; - s.AddrFrame.Offset = c.IntSp; - s.AddrFrame.Mode = AddrModeFlat; - s.AddrBStore.Offset = c.RsBSP; - s.AddrBStore.Mode = AddrModeFlat; - s.AddrStack.Offset = c.IntSp; - s.AddrStack.Mode = AddrModeFlat; -#else -#error "Platform not supported!" -#endif - - pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - if (!pSym) goto cleanup; // not enough memory... - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN); - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - pSym->MaxNameLength = STACKWALK_MAX_NAMELEN; - - memset(&Line, 0, sizeof(Line)); - Line.SizeOfStruct = sizeof(Line); - - memset(&Module, 0, sizeof(Module)); - Module.SizeOfStruct = sizeof(Module); - - for (frameNum = 0; ; ++frameNum ) - { - // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64()) - // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can - // assume that either you are done, or that the stack is so hosed that the next - // deeper frame could not be found. - // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386! - if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) ) - { - // INFO: "StackWalk64" does not set "GetLastError"... - this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset); - break; - } - - csEntry.offset = s.AddrPC.Offset; - csEntry.name[0] = 0; - csEntry.undName[0] = 0; - csEntry.undFullName[0] = 0; - csEntry.offsetFromSmybol = 0; - csEntry.offsetFromLine = 0; - csEntry.lineFileName[0] = 0; - csEntry.lineNumber = 0; - csEntry.loadedImageName[0] = 0; - csEntry.moduleName[0] = 0; - if (s.AddrPC.Offset == s.AddrReturn.Offset) - { - if ( (this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount) ) - { - this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset); - break; - } - curRecursionCount++; - } - else - curRecursionCount = 0; - if (s.AddrPC.Offset != 0) - { - // we seem to have a valid PC - // show procedure info (SymGetSymFromAddr64()) - if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE) - { - MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name); - // UnDecorateSymbolName() - this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY ); - this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE ); - } - else - { - this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset); - } - - // show line number info, NT5.0-method (SymGetLineFromAddr64()) - if (this->m_sw->pSGLFA != NULL ) - { // yes, we have SymGetLineFromAddr64() - if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE) - { - csEntry.lineNumber = Line.LineNumber; - MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName); - } - else - { - this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset); - } - } // yes, we have SymGetLineFromAddr64() - - if (m_verbose) // getting module info is very slow, skip unless we're being verbose. - { - // show module info (SymGetModuleInfo64()) - if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE) - { // got module info OK - switch ( Module.SymType ) - { - case SymNone: - csEntry.symTypeString = "-nosymbols-"; - break; - case SymCoff: - csEntry.symTypeString = "COFF"; - break; - case SymCv: - csEntry.symTypeString = "CV"; - break; - case SymPdb: - csEntry.symTypeString = "PDB"; - break; - case SymExport: - csEntry.symTypeString = "-exported-"; - break; - case SymDeferred: - csEntry.symTypeString = "-deferred-"; - break; - case SymSym: - csEntry.symTypeString = "SYM"; - break; -#if API_VERSION_NUMBER >= 9 - case SymDia: - csEntry.symTypeString = "DIA"; - break; -#endif - case 8: //SymVirtual: - csEntry.symTypeString = "Virtual"; - break; - default: - //_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType ); - csEntry.symTypeString = NULL; - break; - } - - MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); - csEntry.baseOfImage = Module.BaseOfImage; - MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); - } // got module info OK - else - { - this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset); - } - } - else - { - MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, "MODULE?"); - } - } // we seem to have a valid PC - - CallstackEntryType et = nextEntry; - if (frameNum == 0) - et = firstEntry; - bLastEntryCalled = false; - this->OnCallstackEntry(et, csEntry); - - if (s.AddrReturn.Offset == 0) - { - bLastEntryCalled = true; - this->OnCallstackEntry(lastEntry, csEntry); - SetLastError(ERROR_SUCCESS); - break; - } - } // for ( frameNum ) - - cleanup: - if (pSym) free( pSym ); - - if (!bLastEntryCalled) - this->OnCallstackEntry(lastEntry, csEntry); - - if (context == NULL) - ResumeThread(hThread); - - return true; -} - -BOOL __stdcall StackWalker::myReadProcMem( - HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead - ) -{ - if (s_readMemoryFunction == NULL) - { - SIZE_T st; - BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st); - *lpNumberOfBytesRead = (DWORD) st; - //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet); - return bRet; - } - else - { - return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData); - } -} - -void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - if (fileVersion == 0) - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName); - else - { - DWORD v4 = (DWORD) (fileVersion & 0xFFFF); - DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF); - DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF); - DWORD v1 = (DWORD) ((fileVersion>>48) & 0xFFFF); - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4); - } - if (m_verbose) - { - OnOutput(buffer); - } -} - -void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - if ( (eType != lastEntry) && (entry.offset != 0) ) - { - if (entry.name[0] == 0) - MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)"); - if (entry.undName[0] != 0) - MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName); - if (entry.undFullName[0] != 0) - MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName); - if (entry.lineFileName[0] == 0) - { - MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)"); - if (entry.moduleName[0] == 0) - MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)"); - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name); - } - else - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name); - buffer[STACKWALK_MAX_NAMELEN-1] = 0; - OnOutput(buffer); - } -} - -void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr); - if (m_verbose) - { - OnOutput(buffer); - } -} - -#pragma warning (disable : 4996) - -void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName) -{ - CHAR buffer[STACKWALK_MAX_NAMELEN]; - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName); - if (m_verbose) - { - OnOutput(buffer); - } - // Also display the OS-version -#if _MSC_VER <= 1200 - OSVERSIONINFOA ver; - ZeroMemory(&ver, sizeof(OSVERSIONINFOA)); - ver.dwOSVersionInfoSize = sizeof(ver); - if (GetVersionExA(&ver) != FALSE) - { - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", - ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, - ver.szCSDVersion); - if (m_verbose) - { - OnOutput(buffer); - } - } -#else - OSVERSIONINFOEXA ver; - ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA)); - ver.dwOSVersionInfoSize = sizeof(ver); - if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) - { - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", - ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, - ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); - if (m_verbose) - { - OnOutput(buffer); - } - } -#endif -} - -void StackWalker::OnOutput(LPCSTR buffer) -{ - OutputDebugStringA(buffer); -} - -#endif // LL_WINDOWS diff --git a/indra/llcommon/StackWalker.h b/indra/llcommon/StackWalker.h deleted file mode 100644 index c76b07a739d..00000000000 --- a/indra/llcommon/StackWalker.h +++ /dev/null @@ -1,226 +0,0 @@ -/********************************************************************** - * - * StackWalker.h - * - * - * - * $LicenseInfo:firstyear=2016&license=bsd$ - * - * Linden notes: Small modifications from the original source at https://stackwalker.codeplex.com/ - * - * LICENSE (http://www.opensource.org/licenses/bsd-license.php) - * - * Copyright (c) 2005-2009, Jochen Kalmbach - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * **********************************************************************/ - -#if LL_WINDOWS - -// #pragma once is supported starting with _MCS_VER 1000, -// so we need not to check the version (because we only support _MSC_VER >= 1100)! -#pragma once - -#include - -// special defines for VC5/6 (if no actual PSDK is installed): -#if _MSC_VER < 1300 -typedef unsigned __int64 DWORD64, *PDWORD64; -#if defined(_WIN64) -typedef unsigned __int64 SIZE_T, *PSIZE_T; -#else -typedef unsigned long SIZE_T, *PSIZE_T; -#endif -#endif // _MSC_VER < 1300 - -class StackWalkerInternal; // forward -class StackWalker -{ -public: - typedef enum StackWalkOptions - { - // No addition info will be retrived - // (only the address is available) - RetrieveNone = 0, - - // Try to get the symbol-name - RetrieveSymbol = 1, - - // Try to get the line for this symbol - RetrieveLine = 2, - - // Try to retrieve the module-infos - RetrieveModuleInfo = 4, - - // Also retrieve the version for the DLL/EXE - RetrieveFileVersion = 8, - - // Contains all the abouve - RetrieveVerbose = 0xF, - - // Generate a "good" symbol-search-path - SymBuildPath = 0x10, - - // Also use the public Microsoft-Symbol-Server - SymUseSymSrv = 0x20, - - // Contains all the abouve "Sym"-options - SymAll = 0x30, - - // Contains all options (default) - OptionsAll = 0x3F - } StackWalkOptions; - - StackWalker( - bool verbose = true, - int options = OptionsAll, // 'int' is by design, to combine the enum-flags - LPCSTR szSymPath = NULL, - DWORD dwProcessId = GetCurrentProcessId(), - HANDLE hProcess = GetCurrentProcess() - ); - StackWalker(DWORD dwProcessId, HANDLE hProcess); - virtual ~StackWalker(); - - typedef BOOL (__stdcall *PReadProcessMemoryRoutine)( - HANDLE hProcess, - DWORD64 qwBaseAddress, - PVOID lpBuffer, - DWORD nSize, - LPDWORD lpNumberOfBytesRead, - LPVOID pUserData // optional data, which was passed in "ShowCallstack" - ); - - bool LoadModules(); - - bool ShowCallstack( - bool verbose, - HANDLE hThread = GetCurrentThread(), - const CONTEXT *context = NULL, - PReadProcessMemoryRoutine readMemoryFunction = NULL, - LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback - ); - -#if _MSC_VER >= 1300 -// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" -// in older compilers in order to use it... starting with VC7 we can declare it as "protected" -protected: -#endif - enum { STACKWALK_MAX_NAMELEN = 4096 }; // max name length for found symbols - -protected: - // Entry for each Callstack-Entry - typedef struct CallstackEntry - { - DWORD64 offset; // if 0, we have no valid entry - CHAR name[STACKWALK_MAX_NAMELEN]; - CHAR undName[STACKWALK_MAX_NAMELEN]; - CHAR undFullName[STACKWALK_MAX_NAMELEN]; - DWORD64 offsetFromSmybol; - DWORD offsetFromLine; - DWORD lineNumber; - CHAR lineFileName[STACKWALK_MAX_NAMELEN]; - DWORD symType; - LPCSTR symTypeString; - CHAR moduleName[STACKWALK_MAX_NAMELEN]; - DWORD64 baseOfImage; - CHAR loadedImageName[STACKWALK_MAX_NAMELEN]; - } CallstackEntry; - - enum CallstackEntryType {firstEntry, nextEntry, lastEntry}; - - virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName); - virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion); - virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry); - virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr); - virtual void OnOutput(LPCSTR szText); - - StackWalkerInternal *m_sw; - HANDLE m_hProcess; - DWORD m_dwProcessId; - bool m_modulesLoaded; - LPSTR m_szSymPath; - - bool m_verbose; - int m_options; - int m_MaxRecursionCount; - - static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead); - - friend StackWalkerInternal; -}; // class StackWalker - - -// The "ugly" assembler-implementation is needed for systems before XP -// If you have a new PSDK and you only compile for XP and later, then you can use -// the "RtlCaptureContext" -// Currently there is no define which determines the PSDK-Version... -// So we just use the compiler-version (and assumes that the PSDK is -// the one which was installed by the VS-IDE) - -// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... -// But I currently use it in x64/IA64 environments... -//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400) - -#if defined(_M_IX86) -#ifdef CURRENT_THREAD_VIA_EXCEPTION -// TODO: The following is not a "good" implementation, -// because the callstack is only valid in the "__except" block... -#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ - do { \ - memset(&c, 0, sizeof(CONTEXT)); \ - EXCEPTION_POINTERS *pExp = NULL; \ - __try { \ - throw 0; \ - } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \ - if (pExp != NULL) \ - memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - } while(0); -#else -// The following should be enough for walking the callstack... -#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ - do { \ - memset(&c, 0, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - __asm call x \ - __asm x: pop eax \ - __asm mov c.Eip, eax \ - __asm mov c.Ebp, ebp \ - __asm mov c.Esp, esp \ - } while(0); -#endif - -#else - -// The following is defined for x86 (XP and higher), x64 and IA64: -#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ - do { \ - memset(&c, 0, sizeof(CONTEXT)); \ - c.ContextFlags = contextFlags; \ - RtlCaptureContext(&c); \ -} while(0); -#endif - -#endif // LL_WINDOWS diff --git a/indra/llcommon/hbxxh.cpp b/indra/llcommon/hbxxh.cpp index 41d797a7e3b..f080c1f8915 100644 --- a/indra/llcommon/hbxxh.cpp +++ b/indra/llcommon/hbxxh.cpp @@ -33,8 +33,12 @@ // (*) SSE2 is normally used for x86(_64) builds, unless you enabled AVX2 // in your build, in which case the latter would be used instead. For ARM64 // builds, this would also automatically enable NEON vectorization. +#if LL_WINDOWS || LL_DARWIN #define XXH_INLINE_ALL -#include "xxhash/xxhash.h" +#else // GCC has issues force inlining all of xxhash +#define XXH_STATIC_LINKING_ONLY +#endif +#include #include "hbxxh.h" diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index bf8801c46b4..dde1155a818 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -33,7 +33,7 @@ #include "lltracethreadrecorder.h" #include "llcleanup.h" -#if LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY && TRACY_ENABLE +#if defined(LL_PROFILER_CONFIGURATION) && LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY // Override new/delete for tracy memory profiling void* ll_tracy_new(size_t size) diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 78101e21afc..9d99d9823ca 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -57,11 +57,6 @@ #include "lltimer.h" #include "llprofiler.h" -// On Mac, got: -// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define -// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if -// _Unwind_Backtrace is available without `_GNU_SOURCE`." -#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED #include namespace { @@ -346,7 +341,7 @@ namespace { }; #endif -#if LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY +#if defined(LL_PROFILER_CONFIGURATION) && LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY class RecordToTracy : public LLError::Recorder { public: @@ -801,7 +796,7 @@ namespace LLError::addRecorder(recordToWinDebug); #endif -#if LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY +#if defined(LL_PROFILER_CONFIGURATION) && LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY LLError::RecorderPtr recordToTracy(new RecordToTracy()); LLError::addRecorder(recordToTracy); #endif diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 343cc47e4c3..50f1fb8470f 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -55,9 +55,9 @@ const int LL_ERR_NOERR = 0; #define SHOW_ASSERT #else // _DEBUG -#ifdef LL_RELEASE_WITH_DEBUG_INFO +#if LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO #define SHOW_ASSERT -#endif // LL_RELEASE_WITH_DEBUG_INFO +#endif // LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO #ifdef RELEASE_SHOW_DEBUG #define SHOW_DEBUG diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index c0154a569f9..946e2c57d32 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -19,19 +19,6 @@ // external library headers #include #include -// On Mac, got: -// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define -// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if -// _Unwind_Backtrace is available without `_GNU_SOURCE`." -#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED - -#if LL_WINDOWS -// On Windows, header-only implementation causes macro collisions -- use -// prebuilt library -#define BOOST_STACKTRACE_LINK -#include -#endif // LL_WINDOWS - #include // other Linden headers #include "llerror.h" diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index a25387d321e..c4f60659f5a 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -75,7 +75,7 @@ LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment); #endif #if LL_ARM64 -#include "sse2neon.h" +#include "sse2neon/sse2neon.h" #else #include #endif diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 104d3cc1868..71e63c9227d 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -119,15 +119,6 @@ #endif -#if defined(LL_WINDOWS) -#define BOOST_REGEX_NO_LIB 1 -#define CURL_STATICLIB 1 -#ifndef XML_STATIC -#define XML_STATIC -#endif -#endif // LL_WINDOWS - - // Deal with VC++ problems #if LL_MSVC // level 4 warnings that we need to disable: @@ -212,15 +203,36 @@ #endif #if LL_ARM64 -#define GLM_FORCE_NEON 1 + #ifndef GLM_FORCE_NEON + #define GLM_FORCE_NEON 1 + #endif #else -#define GLM_FORCE_SSE2 1 -#endif + #ifdef LL_DARWIN + #ifndef GLM_FORCE_SSE42 + #define GLM_FORCE_SSE42 1 + #endif // GLM_FORCE_SSE42 + #else + #if defined(__AVX2__) + #ifndef GLM_FORCE_AVX2 + #define GLM_FORCE_AVX2 1 + #endif // GLM_FORCE_AVX2 + #elif defined(__AVX__) + #ifndef GLM_FORCE_AVX + #define GLM_FORCE_AVX 1 + #endif // GLM_FORCE_AVX + #else + #ifndef GLM_FORCE_SSE2 + #define GLM_FORCE_SSE2 1 + #endif // GLM_FORCE_SSE2 + #endif // AVX2 vs AVX + #endif // LL_DARWIN +#endif // LL_ARM64 #if LL_ARM64 #define KDU_NEON_INTRINSICS 1 #else #define KDU_X86_INTRINSICS 1 + #endif #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llprofiler.cpp b/indra/llcommon/llprofiler.cpp deleted file mode 100644 index b2ac7723d4f..00000000000 --- a/indra/llcommon/llprofiler.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/** -* @file llprofiler.cpp -* @brief Implementation of llprofiler -* @author Rye Cogtail -* -* $LicenseInfo:firstyear=2024&license=viewerlgpl$ -* Second Life Viewer Source Code -* Copyright (C) 2024, Linden Research, Inc. -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation; -* version 2.1 of the License only. -* -* This library 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 -* Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General Public -* License along with this library; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -* $/LicenseInfo$ -*/ - -#include "llpreprocessor.h" - -#include "TracyClient.cpp" diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp index acd4bafb853..57a898e67c2 100644 --- a/indra/llcommon/llsdjson.cpp +++ b/indra/llcommon/llsdjson.cpp @@ -33,8 +33,6 @@ #include "llsdutil.h" #include "llerror.h" -#include - //========================================================================= LLSD LlsdFromJson(const boost::json::value& val) { diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 7fe1f9cdd4a..41bfe7c3636 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -32,16 +32,11 @@ #include "llstreamtools.h" // for fullread #include -#include "apr_base64.h" +#include #include #include - -#ifdef LL_USESYSTEMLIBS -# include -#else -# include "zlib-ng/zlib.h" // for davep's dirty little zip functions -#endif +#include #if !LL_WINDOWS #include // htonl & ntohl diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index f399c51608e..88f807bb63c 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -37,11 +37,7 @@ extern "C" { -#ifdef LL_USESYSTEMLIBS # include -#else -# include "expat/expat.h" -#endif } /** diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 07adf71d18f..47e3d29570d 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -505,6 +505,24 @@ std::string utf16str_to_utf8str(const U16* utf16str, size_t len) return wstring_to_utf8str(utf16str_to_wstring(utf16str, len)); } +std::u8string str_to_u8str(const char* str, size_t len) +{ + if (!str || len == 0) return {}; + + // We treat std::string as utf8 in this codebase so pass through + std::string_view str_view(str, len); + return std::u8string(str_view.begin(), str_view.end()); +} + +std::string u8str_to_str(const char8_t* u8str, size_t len) +{ + if (!u8str || len == 0) return {}; + + // We treat std::string as utf8 in this codebase so pass through + std::u8string_view u8str_view(u8str, len); + return std::string(u8str_view.begin(), u8str_view.end()); +} + std::string utf8str_trim(const std::string& utf8str) { LLWString wstr = utf8str_to_wstring(utf8str); @@ -1759,7 +1777,7 @@ void LLStringUtilBase::testHarness() std::string s4 = s2; llassert( !s4.empty() ); - s4.empty(); + s4.clear(); llassert( s4.empty() ); std::string s5(""); diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 7dd8256e72c..9b47d098b15 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -678,6 +678,10 @@ ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_u // an older alias for utf16str_to_utf8str(llutf16string) inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} +// Convert to/from u8string +ll_convert_forms(ll_convert_alias, std::string, std::u8string, u8str_to_str); +ll_convert_forms(ll_convert_alias, std::u8string, std::string, str_to_u8str); + // Length of this UTF32 string in bytes when transformed to UTF8 LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 5ef042b5a7f..09b6e55eab3 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -33,11 +33,7 @@ #include "llsys.h" #include -#ifdef LL_USESYSTEMLIBS -# include -#else -# include "zlib-ng/zlib.h" -#endif +#include #include "llprocessor.h" #include "llerrorcontrol.h" diff --git a/indra/llcommon/llwin32headers.h b/indra/llcommon/llwin32headers.h index df433deb7a1..1ff373bca87 100644 --- a/indra/llcommon/llwin32headers.h +++ b/indra/llcommon/llwin32headers.h @@ -30,6 +30,7 @@ #ifdef LL_WINDOWS #include // Does not include winsock.h because WIN32_LEAN_AND_MEAN is defined #include // Requires windows.h +#include #endif #endif diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index ab174a8bde1..05c25e6627a 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -280,16 +280,16 @@ namespace tut LLCoros::instance().set_consuming(true); // should immediately retrieve 'first' without waiting LL_DEBUGS() << "listener coro waiting for first" << LL_ENDL; - data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1, LLSD())); + data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1f, LLSD())); // Don't use ensure() from within the coro -- ensure() failure // throws tut::fail, which won't propagate out to the main // test driver, which will result in an odd failure. // Wait for 'second' because it's not already pending. LL_DEBUGS() << "listener coro waiting for second" << LL_ENDL; - data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1, LLSD())); + data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1f, LLSD())); // and wait for 'third', which should involve no further waiting LL_DEBUGS() << "listener coro waiting for third" << LL_ENDL; - data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1, LLSD())); + data.append(llcoro::suspendUntilEventOnWithTimeout(pump, 0.1f, LLSD())); LL_DEBUGS() << "listener coro done" << LL_ENDL; running = false; }); @@ -312,7 +312,7 @@ namespace tut while (running) { LL_DEBUGS() << "test() waiting for coro done" << LL_ENDL; - llcoro::suspendUntilTimeout(0.1); + llcoro::suspendUntilTimeout(0.1f); } // okay, verify expected results ensure_equals("should have received three values", data, diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 5e653d0ba09..175ab090e67 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -433,11 +433,9 @@ namespace tut std::vector argv; apr_proc_t child; -#if defined(LL_WINDOWS) - argv.push_back("python"); -#else - argv.push_back("python3"); -#endif + auto PYTHON(LLStringUtil::getenv("PYTHON")); + tut::ensure("Set $PYTHON to the Python interpreter", !PYTHON.empty()); + argv.push_back(PYTHON.c_str()); // Have to have a named copy of this std::string so its c_str() value // will persist. std::string scriptname(script.getPath().string()); diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index a7abfda0997..639a096b550 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -2111,7 +2111,7 @@ namespace tut "]\n" // Don't forget raw-string syntax for Windows pathnames. // N.B. Using 'print' implicitly adds newlines. - "with open(r'" << (const char*)file.getPath().u8string().c_str() << "', 'wb') as f:\n" + "with open(r'" << ll_convert(file.getPath().u8string()).c_str() << "', 'wb') as f:\n" " for item in DATA:\n" " serialized = llsd." << pyformatter << "(item)\n" " f.write(lenformat.pack(len(serialized)))\n" diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index 58bbdb2d9a1..b5603a7a6ee 100644 --- a/indra/llcorehttp/CMakeLists.txt +++ b/indra/llcorehttp/CMakeLists.txt @@ -1,19 +1,9 @@ # -*- cmake -*- -project(llcorehttp) - -include(00-Common) -include(CURL) -include(OpenSSL) -include(NGHTTP2) -include(ZLIBNG) -include(LLCoreHttp) -include(LLAddBuildTest) -include(LLCommon) -include(Tut) -include(bugsplat) - -set(llcorehttp_SOURCE_FILES +add_library (llcorehttp STATIC) + +target_sources(llcorehttp + PRIVATE bufferarray.cpp bufferstream.cpp httpcommon.cpp @@ -38,9 +28,10 @@ set(llcorehttp_SOURCE_FILES _refcounted.cpp ) -set(llcorehttp_HEADER_FILES - CMakeLists.txt - +target_sources(llcorehttp + PUBLIC + FILE_SET HEADERS + FILES bufferarray.h bufferstream.h httpcommon.h @@ -70,37 +61,24 @@ set(llcorehttp_HEADER_FILES _thread.h ) -if (DARWIN OR LINUX) - # Boost headers define unused members in condition_variable so... - set_source_files_properties(${llcorehttp_SOURCE_FILES} - PROPERTIES COMPILE_FLAGS -Wno-unused-variable) -endif (DARWIN OR LINUX) - -list(APPEND llcorehttp_SOURCE_FILES ${llcorehttp_HEADER_FILES}) - -add_library (llcorehttp ${llcorehttp_SOURCE_FILES}) target_link_libraries( llcorehttp + PUBLIC llmath llcommon ll::libcurl ll::openssl - ll::nghttp2 ) target_include_directories( llcorehttp INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) # llmessage depends on llcorehttp, yet llcorehttp also depends on llmessage (at least for includes). # Cannot/Should not use target_link_libraries here to add llmessage to the dependencies, as that would # lead to circular dependencies (or in case of cmake, the first project declaring it's dependencies wins) -target_include_directories( llcorehttp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../llmessage) - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llcorehttp REUSE_FROM llprecompiled) -endif () +target_include_directories(llcorehttp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../llmessage) +target_precompile_headers(llcorehttp REUSE_FROM llprecompiled) # tests -set(LLCOREHTTP_TESTS ON CACHE BOOL - "Build and run llcorehttp integration tests specifically") -if (LL_TESTS AND LLCOREHTTP_TESTS) +option(LLCOREHTTP_TESTS "Build and run llcorehttp integration tests specifically" ON) +if (BUILD_TESTING AND LLCOREHTTP_TESTS) SET(llcorehttp_TEST_SOURCE_FILES ) @@ -125,6 +103,7 @@ if (LL_TESTS AND LLCOREHTTP_TESTS) llmessage llcommon ) + set(test_project llcorehttp) # If http_proxy is in the current environment (e.g. to fetch s3-proxy # autobuild packages), suppress it for this integration test: it screws up @@ -132,8 +111,9 @@ if (LL_TESTS AND LLCOREHTTP_TESTS) LL_ADD_INTEGRATION_TEST(llcorehttp "${llcorehttp_TEST_SOURCE_FILES}" "${test_libs}" + "${test_project}" "-Dhttp_proxy" - ${PYTHON_EXECUTABLE} + ${Python3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llcorehttp_peer.py" ) @@ -156,26 +136,13 @@ if (LL_TESTS AND LLCOREHTTP_TESTS) set_target_properties(http_texture_load PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${EXE_STAGING_DIR}" - FOLDER "Tests" + FOLDER "Tests/llcorehttp" ) - if (WINDOWS) - # The following come from LLAddBuildTest.cmake's INTEGRATION_TEST_xxxx target. - set_target_properties(http_texture_load - PROPERTIES - LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:CONSOLE" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO" - LINK_FLAGS_RELEASE "" - ) - endif (WINDOWS) + target_link_libraries(http_texture_load ${example_libs}) - if(DARWIN) - set_target_properties(http_texture_load - PROPERTIES - OSX_ARCHITECTURES ${LL_MACOS_TEST_ARCHITECTURE} - ) + if (WINDOWS) + target_link_options(http_texture_load PRIVATE $<$:/DEBUG:NONE>) endif() - target_link_libraries(http_texture_load ${example_libs}) - -endif (LL_TESTS AND LLCOREHTTP_TESTS) +endif (BUILD_TESTING AND LLCOREHTTP_TESTS) diff --git a/indra/llfilesystem/CMakeLists.txt b/indra/llfilesystem/CMakeLists.txt index a552e4bdbc6..28005e96ace 100644 --- a/indra/llfilesystem/CMakeLists.txt +++ b/indra/llfilesystem/CMakeLists.txt @@ -1,11 +1,9 @@ # -*- cmake -*- -project(llfilesystem) +add_library(llfilesystem STATIC) -include(00-Common) -include(LLCommon) - -set(llfilesystem_SOURCE_FILES +target_sources(llfilesystem + PRIVATE lldir.cpp lldiriterator.cpp lllfsthread.cpp @@ -13,8 +11,10 @@ set(llfilesystem_SOURCE_FILES llfilesystem.cpp ) -set(llfilesystem_HEADER_FILES - CMakeLists.txt +target_sources(llfilesystem + PUBLIC + FILE_SET HEADERS + FILES lldir.h lldirguard.h lldiriterator.h @@ -24,10 +24,16 @@ set(llfilesystem_HEADER_FILES ) if (DARWIN) - LIST(APPEND llfilesystem_SOURCE_FILES lldir_utils_objc.mm) - LIST(APPEND llfilesystem_SOURCE_FILES lldir_utils_objc.h) - LIST(APPEND llfilesystem_SOURCE_FILES lldir_mac.cpp) - LIST(APPEND llfilesystem_HEADER_FILES lldir_mac.h) + target_sources(llfilesystem + PRIVATE + lldir_mac.cpp + lldir_utils_objc.mm + PUBLIC + FILE_SET HEADERS + FILES + lldir_mac.h + lldir_utils_objc.h + ) set_source_files_properties( lldir_utils_objc.mm @@ -37,49 +43,55 @@ if (DARWIN) endif (DARWIN) if (LINUX) - LIST(APPEND llfilesystem_SOURCE_FILES lldir_linux.cpp) - LIST(APPEND llfilesystem_HEADER_FILES lldir_linux.h) + target_sources(llfilesystem + PRIVATE + lldir_linux.cpp + PUBLIC + FILE_SET HEADERS + FILES + lldir_linux.h + ) if (INSTALL) set_source_files_properties(lldir_linux.cpp PROPERTIES COMPILE_FLAGS "-DAPP_RO_DATA_DIR=\\\"${APP_SHARE_DIR}\\\"" ) - endif (INSTALL) -endif (LINUX) + endif () +endif () if (WINDOWS) - LIST(APPEND llfilesystem_SOURCE_FILES lldir_win32.cpp) - LIST(APPEND llfilesystem_HEADER_FILES lldir_win32.h) -endif (WINDOWS) - -list(APPEND llfilesystem_SOURCE_FILES ${llfilesystem_HEADER_FILES}) - -add_library (llfilesystem ${llfilesystem_SOURCE_FILES}) + target_sources(llfilesystem + PRIVATE + lldir_win32.cpp + PUBLIC + FILE_SET HEADERS + FILES + lldir_win32.h + ) +endif () target_link_libraries(llfilesystem - llmath - llcommon + PUBLIC + llmath + llcommon ) target_include_directories( llfilesystem INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llfilesystem REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llfilesystem REUSE_FROM llprecompiled) # Add tests -if (LL_TESTS) - include(LLAddBuildTest) +if (BUILD_TESTING) # UNIT TESTS SET(llfilesystem_TEST_SOURCE_FILES - lldiriterator.cpp + lldiriterator.cpp ) LL_ADD_PROJECT_UNIT_TESTS(llfilesystem "${llfilesystem_TEST_SOURCE_FILES}") # INTEGRATION TESTS set(test_libs llmath llcommon llfilesystem ) + set(test_project llfilesystem) # TODO: Some of these need refactoring to be proper Unit tests rather than Integration tests. - LL_ADD_INTEGRATION_TEST(lldir "" "${test_libs}") -endif (LL_TESTS) + LL_ADD_INTEGRATION_TEST(lldir "" "${test_libs}" "${test_project}") +endif () diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp index 1a647362c51..1aee4a4725d 100644 --- a/indra/llfilesystem/lldir.cpp +++ b/indra/llfilesystem/lldir.cpp @@ -103,7 +103,7 @@ std::vector LLDir::getFilesInDir(const std::string &dirname) { if (std::filesystem::is_regular_file(dir_itr->status())) { - v.push_back(dir_itr->path().filename().string()); + v.push_back(ll_convert(dir_itr->path().filename().u8string())); } } } diff --git a/indra/llfilesystem/lldiriterator.cpp b/indra/llfilesystem/lldiriterator.cpp index 60b55c7bf3f..90a99380706 100644 --- a/indra/llfilesystem/lldiriterator.cpp +++ b/indra/llfilesystem/lldiriterator.cpp @@ -127,7 +127,7 @@ bool LLDirIterator::Impl::next(std::string &fname) while (mIter != end_itr && !found) { boost::smatch match; - std::string name = mIter->path().filename().string(); + std::string name = ll_convert(mIter->path().filename().u8string()); found = ll_regex_match(name, match, mFilterExp); if (found) { diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp index 9b674d55285..8c68786db0a 100644 --- a/indra/llfilesystem/lldiskcache.cpp +++ b/indra/llfilesystem/lldiskcache.cpp @@ -39,7 +39,9 @@ #include "lldiskcache.h" - /** +using namespace std::literals; + +/** * The prefix inserted at the start of a cache file filename to * help identify it as a cache file. It's probably not required * (just the presence in the cache folder is enough) but I am @@ -48,6 +50,11 @@ * this will help to offset any damage if that happens. */ static const std::string CACHE_FILENAME_PREFIX("sl_cache"); +#if LL_WINDOWS +static constexpr std::wstring_view CACHE_FILENAME_PREFIX_NATIVE(L"sl_cache"sv); +#else +static constexpr std::string_view CACHE_FILENAME_PREFIX_NATIVE("sl_cache"sv); +#endif std::string LLDiskCache::sCacheDir; @@ -101,7 +108,7 @@ void LLDiskCache::purge() std::error_code ec; auto start_time = std::chrono::high_resolution_clock::now(); - typedef std::pair> file_info_t; + typedef std::pair> file_info_t; std::vector file_info; std::filesystem::path cache_path = fsyspath(sCacheDir); @@ -116,21 +123,20 @@ void LLDiskCache::purge() } if (std::filesystem::is_regular_file(*iter, ec) && !ec) { - if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) + if ((*iter).path().native().find(CACHE_FILENAME_PREFIX_NATIVE) != std::filesystem::path::string_type::npos) { uintmax_t file_size = std::filesystem::file_size(*iter, ec); if (ec) { continue; } - const std::string file_path = (*iter).path().string(); const std::filesystem::file_time_type file_time = std::filesystem::last_write_time(*iter, ec); if (ec) { continue; } - file_info.push_back(file_info_t(file_time, { file_size, file_path })); + file_info.push_back(file_info_t(file_time, { file_size, (*iter).path() })); } } iter.increment(ec); @@ -245,7 +251,7 @@ void LLDiskCache::clearCache() { if (std::filesystem::is_regular_file(*iter, ec) && !ec) { - if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) + if ((*iter).path().native().find(CACHE_FILENAME_PREFIX_NATIVE) != std::filesystem::path::string_type::npos) { std::filesystem::remove(*iter, ec); if (ec) @@ -262,8 +268,13 @@ void LLDiskCache::clearCache() void LLDiskCache::removeOldVFSFiles() { //VFS files won't be created, so consider removing this code later - static const char CACHE_FORMAT[] = "inv.llsd"; - static const char DB_FORMAT[] = "db2.x"; +#if LL_WINDOWS + static constexpr std::wstring_view CACHE_FORMAT(L"inv.llsd"sv); + static constexpr std::wstring_view DB_FORMAT(L"db2.x"sv); +#else + static constexpr std::string_view CACHE_FORMAT("inv.llsd"sv); + static constexpr std::string_view DB_FORMAT("db2.x"sv); +#endif std::error_code ec; std::filesystem::path cache_path = fsyspath(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "")); @@ -274,8 +285,8 @@ void LLDiskCache::removeOldVFSFiles() { if (std::filesystem::is_regular_file(*iter, ec) && !ec) { - if (((*iter).path().string().find(CACHE_FORMAT) != std::string::npos) || - ((*iter).path().string().find(DB_FORMAT) != std::string::npos)) + if (((*iter).path().native().find(CACHE_FORMAT) != std::filesystem::path::string_type::npos) || + ((*iter).path().native().find(DB_FORMAT) != std::filesystem::path::string_type::npos)) { std::filesystem::remove(*iter, ec); if (ec) @@ -311,7 +322,7 @@ uintmax_t LLDiskCache::dirFileSize(const std::string& dir) { if (std::filesystem::is_regular_file(*iter, ec) && !ec) { - if ((*iter).path().string().find(CACHE_FILENAME_PREFIX) != std::string::npos) + if ((*iter).path().native().find(CACHE_FILENAME_PREFIX_NATIVE) != std::filesystem::path::string_type::npos) { uintmax_t file_size = std::filesystem::file_size(*iter, ec); if (!ec) diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt index a81808343fb..cba512c670f 100644 --- a/indra/llimage/CMakeLists.txt +++ b/indra/llimage/CMakeLists.txt @@ -1,18 +1,9 @@ # -*- cmake -*- -project(llimage) +add_library (llimage STATIC) -include(00-Common) -include(LLCommon) -include(LLImage) -include(JPEG) -include(LLKDU) -include(ZLIBNG) -include(LLAddBuildTest) -include(bugsplat) -include(Tut) - -set(llimage_SOURCE_FILES +target_sources(llimage + PRIVATE llimagebmp.cpp llimage.cpp llimagedimensionsinfo.cpp @@ -26,9 +17,10 @@ set(llimage_SOURCE_FILES llpngwrapper.cpp ) -set(llimage_HEADER_FILES - CMakeLists.txt - +target_sources(llimage + PUBLIC + FILE_SET HEADERS + FILES llimage.h llimagebmp.h llimagedimensionsinfo.h @@ -43,37 +35,33 @@ set(llimage_HEADER_FILES llpngwrapper.h ) -list(APPEND llimage_SOURCE_FILES ${llimage_HEADER_FILES}) - -add_library (llimage ${llimage_SOURCE_FILES}) target_include_directories( llimage INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level if (USE_KDU) - target_link_libraries(llimage llkdu) -else (USE_KDU) - target_link_libraries(llimage llimagej2coj) -endif (USE_KDU) + target_link_libraries(llimage PUBLIC llkdu) +else () + target_link_libraries(llimage PUBLIC llimagej2coj) +endif () target_link_libraries(llimage - llfilesystem - llmath - llcommon - ll::libpng - ll::libjpeg + PUBLIC + llfilesystem + llmath + llcommon + ll::libpng + ll::libjpeg ) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llimage REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llimage REUSE_FROM llprecompiled) # Add tests -if (LL_TESTS) +if (BUILD_TESTING) SET(llimage_TEST_SOURCE_FILES llimageworker.cpp ) LL_ADD_PROJECT_UNIT_TESTS(llimage "${llimage_TEST_SOURCE_FILES}") -endif (LL_TESTS) +endif () diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp index bfcb1f76de2..1c7cd974f75 100644 --- a/indra/llimage/llimagefilter.cpp +++ b/indra/llimage/llimagefilter.cpp @@ -665,7 +665,7 @@ void LLImageFilter::computeHistograms() void LLImageFilter::filterGrayScale() { LLMatrix3 gray_scale; - LLVector3 luminosity(0.2125, 0.7154, 0.0721); + LLVector3 luminosity(0.2125f, 0.7154f, 0.0721f); gray_scale.setRows(luminosity, luminosity, luminosity); gray_scale.transpose(); colorTransform(gray_scale); @@ -674,9 +674,9 @@ void LLImageFilter::filterGrayScale() void LLImageFilter::filterSepia() { LLMatrix3 sepia; - sepia.setRows(LLVector3(0.3588, 0.7044, 0.1368), - LLVector3(0.2990, 0.5870, 0.1140), - LLVector3(0.2392, 0.4696, 0.0912)); + sepia.setRows(LLVector3(0.3588f, 0.7044f, 0.1368f), + LLVector3(0.2990f, 0.5870f, 0.1140f), + LLVector3(0.2392f, 0.4696f, 0.0912f)); sepia.transpose(); colorTransform(sepia); } @@ -688,15 +688,15 @@ void LLImageFilter::filterSaturate(F32 saturation) LLMatrix3 r_b; // 45 degre rotation around z - r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0), - LLVector3(-OO_SQRT2, OO_SQRT2, 0.0), - LLVector3( 0.0, 0.0, 1.0)); + r_a.setRows(LLVector3( OO_SQRT2, OO_SQRT2, 0.0f), + LLVector3(-OO_SQRT2, OO_SQRT2, 0.0f), + LLVector3( 0.0f, 0.0f, 1.0f)); // 54.73 degre rotation around y float oo_sqrt3 = 1.0f / F_SQRT3; float sin_54 = F_SQRT2 * oo_sqrt3; - r_b.setRows(LLVector3(oo_sqrt3, 0.0, -sin_54), - LLVector3(0.0, 1.0, 0.0), - LLVector3(sin_54, 0.0, oo_sqrt3)); + r_b.setRows(LLVector3(oo_sqrt3, 0.0f, -sin_54), + LLVector3(0.0f, 1.0f, 0.0f), + LLVector3(sin_54, 0.0f, oo_sqrt3)); // Coordinate conversion LLMatrix3 Lij = r_b * r_a; diff --git a/indra/llimage/llimagejpeg.h b/indra/llimage/llimagejpeg.h index ee0a8815e8d..ceadda41349 100644 --- a/indra/llimage/llimagejpeg.h +++ b/indra/llimage/llimagejpeg.h @@ -32,13 +32,8 @@ #include "llimage.h" extern "C" { -#ifdef LL_USESYSTEMLIBS # include # include -#else -# include "jpeglib/jpeglib.h" -# include "jpeglib/jerror.h" -#endif } class LLImageJPEG : public LLImageFormatted diff --git a/indra/llimagej2coj/CMakeLists.txt b/indra/llimagej2coj/CMakeLists.txt index b7ef696b201..d3314bfeb92 100644 --- a/indra/llimagej2coj/CMakeLists.txt +++ b/indra/llimagej2coj/CMakeLists.txt @@ -1,32 +1,22 @@ # -*- cmake -*- -project(llimagej2coj) +add_library(llimagej2coj STATIC) -include(00-Common) -include(LLCommon) -include(LLImage) -include(OpenJPEG) - -set(llimagej2coj_SOURCE_FILES +target_sources(llimagej2coj + PRIVATE llimagej2coj.cpp - ) - -set(llimagej2coj_HEADER_FILES - CMakeLists.txt + PUBLIC + FILE_SET HEADERS + FILES llimagej2coj.h ) -list(APPEND llimagej2coj_SOURCE_FILES ${llimagej2coj_HEADER_FILES}) - -add_library (llimagej2coj ${llimagej2coj_SOURCE_FILES}) - -target_link_libraries( llimagej2coj - llcommon +target_link_libraries(llimagej2coj + PUBLIC llimage + llcommon ll::openjpeg ) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llimagej2coj REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llimagej2coj REUSE_FROM llprecompiled) diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt index e8f76eaa7d8..729d84432cb 100644 --- a/indra/llinventory/CMakeLists.txt +++ b/indra/llinventory/CMakeLists.txt @@ -1,12 +1,9 @@ # -*- cmake -*- -project(llinventory) +add_library(llinventory STATIC) -include(00-Common) -include(LLCommon) -include(LLCoreHttp) - -set(llinventory_SOURCE_FILES +target_sources(llinventory + PRIVATE llcategory.cpp llfoldertype.cpp llinventory.cpp @@ -25,10 +22,11 @@ set(llinventory_SOURCE_FILES lltransactionflags.cpp lluserrelations.cpp ) - -set(llinventory_HEADER_FILES - CMakeLists.txt +target_sources(llinventory + PUBLIC + FILE_SET HEADERS + FILES llcategory.h llfoldertype.h llinventory.h @@ -52,19 +50,12 @@ set(llinventory_HEADER_FILES lluserrelations.h ) -list(APPEND llinventory_SOURCE_FILES ${llinventory_HEADER_FILES}) - -add_library (llinventory ${llinventory_SOURCE_FILES}) - -target_link_libraries( llinventory llcommon llmath llmessage llxml ) +target_link_libraries(llinventory PUBLIC llcommon llmath llmessage llxml) target_include_directories( llinventory INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +target_precompile_headers(llinventory REUSE_FROM llprecompiled) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llinventory REUSE_FROM llprecompiled) -endif () - -#add unit tests -if (LL_TESTS) +# add unit tests +if (BUILD_TESTING) INCLUDE(LLAddBuildTest) SET(llinventory_TEST_SOURCE_FILES # no real unit tests yet! @@ -73,9 +64,10 @@ if (LL_TESTS) #set(TEST_DEBUG on) set(test_libs llinventory llmath llcorehttp llfilesystem ) - LL_ADD_INTEGRATION_TEST(inventorymisc "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llparcel "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llpermissions "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llsaleinfo "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lluserrelations "" "${test_libs}") -endif (LL_TESTS) + set(test_project llinventory) + LL_ADD_INTEGRATION_TEST(inventorymisc "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llparcel "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llpermissions "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llsaleinfo "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(lluserrelations "" "${test_libs}" "${test_project}") +endif () diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index fd3e49041cf..bb849182208 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -897,9 +897,9 @@ LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position) moonquat = convert_azimuth_and_altitude_to_quat(altitude + (F_PI * 0.125f), azimuth + (F_PI * 0.125f)); // Magic constants copied form dfltsetting.xml - dfltsetting[SETTING_CLOUD_COLOR] = LLColor4(0.4099, 0.4099, 0.4099, 0.0).getValue(); - dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue(); - dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000, 0.5260, 1.0000, 0.0).getValue(); + dfltsetting[SETTING_CLOUD_COLOR] = LLColor4(0.4099f, 0.4099f, 0.4099f, 0.0f).getValue(); + dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000f, 0.5260f, 1.0000f, 0.0f).getValue(); + dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000f, 0.5260f, 1.0000f, 0.0f).getValue(); dfltsetting[SETTING_CLOUD_SCALE] = LLSD::Real(0.4199); dfltsetting[SETTING_CLOUD_SCROLL_RATE] = llsd::array(0.2, 0.01); dfltsetting[SETTING_CLOUD_SHADOW] = LLSD::Real(0.2699); @@ -908,14 +908,14 @@ LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position) dfltsetting[SETTING_DOME_OFFSET] = LLSD::Real(0.96f); dfltsetting[SETTING_DOME_RADIUS] = LLSD::Real(15000.f); dfltsetting[SETTING_GAMMA] = LLSD::Real(1.0); - dfltsetting[SETTING_GLOW] = LLColor4(5.000, 0.0010, -0.4799, 1.0).getValue(); + dfltsetting[SETTING_GLOW] = LLColor4(5.000f, 0.0010f, -0.4799f, 1.0f).getValue(); dfltsetting[SETTING_MAX_Y] = LLSD::Real(1605); dfltsetting[SETTING_MOON_ROTATION] = moonquat.getValue(); dfltsetting[SETTING_MOON_BRIGHTNESS] = LLSD::Real(0.5f); dfltsetting[SETTING_STAR_BRIGHTNESS] = LLSD::Real(250.0000); - dfltsetting[SETTING_SUNLIGHT_COLOR] = LLColor4(0.7342, 0.7815, 0.8999, 0.0).getValue(); + dfltsetting[SETTING_SUNLIGHT_COLOR] = LLColor4(0.7342f, 0.7815f, 0.8999f, 0.0f).getValue(); dfltsetting[SETTING_SUN_ROTATION] = sunquat.getValue(); dfltsetting[SETTING_BLOOM_TEXTUREID] = GetDefaultBloomTextureId(); @@ -1748,7 +1748,7 @@ void LLSettingsSky::calculateLightSettings() const F32 moon_brightness = getIsMoonUp() ? getMoonBrightness() : 0.001f; LLColor3 moonlight = getMoonlightColor(); - LLColor3 moonlight_b(0.66, 0.66, 1.2); // scotopic ambient value + LLColor3 moonlight_b(0.66f, 0.66f, 1.2f); // scotopic ambient value componentMultBy(moonlight, componentExp((light_atten * -1.f) * lighty)); diff --git a/indra/llkdu/CMakeLists.txt b/indra/llkdu/CMakeLists.txt index 411fff34ae0..4067c6b75b1 100644 --- a/indra/llkdu/CMakeLists.txt +++ b/indra/llkdu/CMakeLists.txt @@ -1,42 +1,26 @@ # -*- cmake -*- -project(llkdu) - -# Visual Studio 2005 has a dumb bug that causes it to fail compilation -# of KDU if building with both optimisation and /WS (treat warnings as -# errors), even when the specific warnings that make it croak are -# disabled. - -#set(VS_DISABLE_FATAL_WARNINGS ON) +if (USE_KDU) + add_library (llkdu STATIC) -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLKDU) -set(llkdu_SOURCE_FILES +target_sources(llkdu + PRIVATE llimagej2ckdu.cpp llkdumem.cpp - ) -set(llkdu_HEADER_FILES - CMakeLists.txt + PUBLIC + FILE_SET HEADERS + FILES llimagej2ckdu.h llkdumem.h ) -list(APPEND llkdu_SOURCE_FILES ${llkdu_HEADER_FILES}) - -if (USE_KDU) - add_library (llkdu ${llkdu_SOURCE_FILES}) - - target_link_libraries(llkdu ll::kdu llimage llcommon) - target_include_directories( llkdu INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(llkdu PUBLIC ll::kdu llimage llcommon) + target_include_directories(llkdu INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) # Add tests - if (LL_TESTS) - include(LLAddBuildTest) - include(Tut) + if (BUILD_TESTING) SET(llkdu_TEST_SOURCE_FILES llimagej2ckdu.cpp ) @@ -46,11 +30,10 @@ if (USE_KDU) lltut.h ) - get_property( llimage_include_dir TARGET llimage PROPERTY INTERFACE_INCLUDE_DIRECTORIES ) - set_property( SOURCE ${llkdu_TEST_SOURCE_FILES} PROPERTY LL_TEST_ADDITIONAL_LIBRARIES ll::kdu llcommon) - set_property( SOURCE ${llkdu_TEST_SOURCE_FILES} PROPERTY LL_TEST_ADDITIONAL_INCLUDE_DIRS ${llimage_include_dir}) + get_property(llimage_include_dir TARGET llimage PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + set_property(SOURCE ${llkdu_TEST_SOURCE_FILES} PROPERTY LL_TEST_ADDITIONAL_LIBRARIES ll::kdu llcommon) + set_property(SOURCE ${llkdu_TEST_SOURCE_FILES} PROPERTY LL_TEST_ADDITIONAL_INCLUDE_DIRS ${llimage_include_dir}) LL_ADD_PROJECT_UNIT_TESTS(llkdu "${llkdu_TEST_SOURCE_FILES}") - endif (LL_TESTS) - -endif (USE_KDU) + endif () +endif () diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index f97e4a5bb67..e885c9f06bb 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -1,14 +1,9 @@ # -*- cmake -*- -project(llmath) +add_library(llmath STATIC) -include(00-Common) -include(LLCommon) -include(bugsplat) -include(Boost) -include(SSE2NEON) - -set(llmath_SOURCE_FILES +target_sources(llmath + PRIVATE llbbox.cpp llbboxlocal.cpp llcalc.cpp @@ -18,6 +13,7 @@ set(llmath_SOURCE_FILES llline.cpp llmatrix3a.cpp llmatrix4a.cpp + llmeshoptimizer.cpp llmodularmath.cpp lloctree.cpp llperlin.cpp @@ -42,9 +38,10 @@ set(llmath_SOURCE_FILES xform.cpp ) -set(llmath_HEADER_FILES - CMakeLists.txt - +target_sources(llmath + PUBLIC + FILE_SET HEADERS + FILES llbbox.h llbboxlocal.h llcalc.h @@ -58,6 +55,7 @@ set(llmath_HEADER_FILES llmatrix3a.h llmatrix3a.inl llmatrix4a.h + llmeshoptimizer.h llmodularmath.h lloctree.h llperlin.h @@ -93,20 +91,12 @@ set(llmath_HEADER_FILES xform.h ) -list(APPEND llmath_SOURCE_FILES ${llmath_HEADER_FILES}) - -add_library(llmath ${llmath_SOURCE_FILES}) - -target_link_libraries(llmath llcommon llmeshoptimizer ll::sse2neon) +target_link_libraries(llmath PUBLIC llcommon ll::mikktspace ll::sse2neon ll::meshoptimizer) target_include_directories(llmath INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llmath REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llmath REUSE_FROM llprecompiled) # Add tests -if (LL_TESTS) - include(LLAddBuildTest) +if (BUILD_TESTING) # UNIT TESTS SET(llmath_TEST_SOURCE_FILES llbboxlocal.cpp @@ -122,14 +112,15 @@ if (LL_TESTS) # INTEGRATION TESTS set(test_libs llmath llcommon) + set(test_project llmath) # TODO: Some of these need refactoring to be proper Unit tests rather than Integration tests. - LL_ADD_INTEGRATION_TEST(alignment "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(llbbox llbbox.cpp "${test_libs}") - LL_ADD_INTEGRATION_TEST(llquaternion llquaternion.cpp "${test_libs}") - LL_ADD_INTEGRATION_TEST(mathmisc "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(m3math "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(v3dmath v3dmath.cpp "${test_libs}") - LL_ADD_INTEGRATION_TEST(v3math v3math.cpp "${test_libs}") - LL_ADD_INTEGRATION_TEST(v4math v4math.cpp "${test_libs}") - LL_ADD_INTEGRATION_TEST(xform xform.cpp "${test_libs}") -endif (LL_TESTS) + LL_ADD_INTEGRATION_TEST(alignment "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llbbox llbbox.cpp "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llquaternion llquaternion.cpp "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(mathmisc "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(m3math "" "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(v3dmath v3dmath.cpp "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(v3math v3math.cpp "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(v4math v4math.cpp "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(xform xform.cpp "${test_libs}" "${test_project}") +endif () diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index 891f0ffc4c1..c2f221aa78e 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -27,6 +27,8 @@ #ifndef LLMATH_H #define LLMATH_H +#include "llpreprocessor.h" + #include #include #include diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmath/llmeshoptimizer.cpp similarity index 99% rename from indra/llmeshoptimizer/llmeshoptimizer.cpp rename to indra/llmath/llmeshoptimizer.cpp index 76d51fdad0e..bee9d71e1a7 100644 --- a/indra/llmeshoptimizer/llmeshoptimizer.cpp +++ b/indra/llmath/llmeshoptimizer.cpp @@ -24,9 +24,11 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "llmeshoptimizer.h" -#include "meshoptimizer.h" +#include #include "llmath.h" #include "v2math.h" diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmath/llmeshoptimizer.h similarity index 100% rename from indra/llmeshoptimizer/llmeshoptimizer.h rename to indra/llmath/llmeshoptimizer.h diff --git a/indra/llmath/llsimdmath.h b/indra/llmath/llsimdmath.h index b27b034cf3c..0fc04c33c70 100644 --- a/indra/llmath/llsimdmath.h +++ b/indra/llmath/llsimdmath.h @@ -46,10 +46,38 @@ #endif #if defined(__arm64__) || defined(__aarch64__) -#include "sse2neon.h" + #include "sse2neon/sse2neon.h" + + #ifndef GLM_FORCE_NEON + #define GLM_FORCE_NEON 1 + #endif #else -#include -#include + #include + #include + + #ifdef LL_DARWIN + #ifndef GLM_FORCE_SSE42 + #define GLM_FORCE_SSE42 1 + #endif // GLM_FORCE_SSE42 + #else + #if defined(__AVX2__) + #include + + #ifndef GLM_FORCE_AVX2 + #define GLM_FORCE_AVX2 1 + #endif // GLM_FORCE_AVX2 + #elif defined(__AVX__) + #include + + #ifndef GLM_FORCE_AVX + #define GLM_FORCE_AVX 1 + #endif // GLM_FORCE_AVX + #else + #ifndef GLM_FORCE_SSE2 + #define GLM_FORCE_SSE2 1 + #endif // GLM_FORCE_SSE2 + #endif // AVX2 vs AVX + #endif // LL_DARWIN #endif #include "llmemory.h" diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl index b6e2a4fce57..e186559c511 100644 --- a/indra/llmath/llvector4a.inl +++ b/indra/llmath/llvector4a.inl @@ -272,7 +272,7 @@ inline void LLVector4a::setCross3(const LLVector4a& a, const LLVector4a& b) // Set all elements to the dot product of the x, y, and z elements in a and b inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b) { -#if (defined(__arm64__) || defined(__aarch64__)) +#if (defined(__AVX__) || defined(__AVX2__) || defined(__arm64__) || defined(__aarch64__)) mQ = _mm_dp_ps(a.mQ, b.mQ, 0x7f); #else // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] } @@ -293,7 +293,7 @@ inline void LLVector4a::setAllDot3(const LLVector4a& a, const LLVector4a& b) // Set all elements to the dot product of the x, y, z, and w elements in a and b inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b) { -#if (defined(__arm64__) || defined(__aarch64__)) +#if (defined(__AVX__) || defined(__AVX2__) || defined(__arm64__) || defined(__aarch64__)) mQ = _mm_dp_ps(a.mQ, b.mQ, 0xff); #else // ab = { a[W]*b[W], a[Z]*b[Z], a[Y]*b[Y], a[X]*b[X] } @@ -314,7 +314,7 @@ inline void LLVector4a::setAllDot4(const LLVector4a& a, const LLVector4a& b) // Return the 3D dot product of this vector and b inline LLSimdScalar LLVector4a::dot3(const LLVector4a& b) const { -#if (defined(__arm64__) || defined(__aarch64__)) +#if (defined(__AVX__) || defined(__AVX2__) || defined(__arm64__) || defined(__aarch64__)) return _mm_dp_ps(mQ, b.mQ, 0x7f); #else const LLQuad ab = _mm_mul_ps( mQ, b.mQ ); @@ -328,7 +328,7 @@ inline LLSimdScalar LLVector4a::dot3(const LLVector4a& b) const // Return the 4D dot product of this vector and b inline LLSimdScalar LLVector4a::dot4(const LLVector4a& b) const { -#if (defined(__arm64__) || defined(__aarch64__)) +#if (defined(__AVX__) || defined(__AVX2__) || defined(__arm64__) || defined(__aarch64__)) return _mm_dp_ps(mQ, b.mQ, 0xff); #else // ab = { w, z, y, x } diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 082ab85e512..00920061cf4 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -55,7 +55,7 @@ #include "mikktspace/mikktspace.hh" -#include "meshoptimizer/meshoptimizer.h" +#include #define DEBUG_SILHOUETTE_BINORMALS 0 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette @@ -2032,7 +2032,6 @@ bool LLVolume::generate() { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - LL_CHECK_MEMORY llassert_always(mProfilep); //Added 10.03.05 Dave Parks @@ -2135,11 +2134,10 @@ bool LLVolume::generate() LLFaceID id = iter->mFaceID; mFaceMask |= id; } - LL_CHECK_MEMORY + return true; } - LL_CHECK_MEMORY return false; } @@ -5103,17 +5101,14 @@ bool LLVolumeFace::create(LLVolume* volume, bool partial_build) //tree for this face is no longer valid destroyOctree(); - LL_CHECK_MEMORY bool ret = false ; if (mTypeMask & CAP_MASK) { ret = createCap(volume, partial_build); - LL_CHECK_MEMORY } else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) { ret = createSide(volume, partial_build); - LL_CHECK_MEMORY } else { @@ -5965,8 +5960,6 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0, bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build) { - LL_CHECK_MEMORY - const LLAlignedArray& mesh = volume->getMesh(); const LLAlignedArray& profile = volume->getProfile().mProfile; S32 max_s = volume->getProfile().getTotal(); @@ -6097,7 +6090,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build) } } - LL_CHECK_MEMORY return true; } @@ -6141,8 +6133,6 @@ bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) } } - LL_CHECK_MEMORY; - S32 max_s = volume->getProfile().getTotal(); S32 max_t = volume->getPath().mPath.size(); @@ -6236,8 +6226,6 @@ bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) } } - LL_CHECK_MEMORY - mCenter->setAdd(min, max); mCenter->mul(0.5f); @@ -6255,8 +6243,6 @@ bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) num_vertices++; } - LL_CHECK_MEMORY - //if (partial_build) //{ // return true; @@ -6503,9 +6489,6 @@ bool LLVolumeFace::createCap(LLVolume* volume, bool partial_build) } LLVector4a d0,d1; - LL_CHECK_MEMORY - - d0.setSub(mPositions[mIndices[1]], mPositions[mIndices[0]]); d1.setSub(mPositions[mIndices[2]], mPositions[mIndices[0]]); @@ -6760,7 +6743,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; - LL_CHECK_MEMORY bool flat = mTypeMask & FLAT_MASK; U8 sculpt_type = volume->getParams().getSculptType(); @@ -6791,8 +6773,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) resizeIndices(num_indices); } - LL_CHECK_MEMORY - LLVector4a* pos = (LLVector4a*) mPositions; LLVector2* tc = (LLVector2*) mTexCoords; F32 begin_stex = floorf(profile[mBeginS][2]); @@ -6889,7 +6869,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) } } } - LL_CHECK_MEMORY mCenter->clear(); @@ -6962,8 +6941,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) } } - LL_CHECK_MEMORY - //clear normals F32* dst = (F32*) mNormals; F32* end = (F32*) (mNormals+mNumVertices); @@ -6975,8 +6952,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) dst += 4; } - LL_CHECK_MEMORY - //generate normals U32 count = mNumIndices/3; @@ -7081,8 +7056,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) n2.store4a((F32*) n2p); } - LL_CHECK_MEMORY - // adjust normals based on wrapping and stitching LLVector4a top; @@ -7214,8 +7187,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) } - LL_CHECK_MEMORY - return true; } diff --git a/indra/llmath/tests/alignment_test.cpp b/indra/llmath/tests/alignment_test.cpp index f41ebe82aac..046b23232d7 100644 --- a/indra/llmath/tests/alignment_test.cpp +++ b/indra/llmath/tests/alignment_test.cpp @@ -77,10 +77,6 @@ class alignas(16) MyVector4a template<> template<> void alignment_test_object_t::test<1>() { -# ifdef LL_DEBUG -// skip("This test fails on Windows when compiled in debug mode."); -# endif - const int num_tests = 7; void *align_ptr; for (int i=0; i() template<> template<> void alignment_test_object_t::test<3>() { -# ifdef LL_DEBUG -// skip("This test fails on Windows when compiled in debug mode."); -# endif - const int ARR_SIZE = 7; for(int i=0; i 0); + //llassert(mNumBufferedPackets > 0); + S32 packet_size = 0; S16 ring_size = (S16)(mPacketRing.size()); @@ -204,7 +205,7 @@ S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop) mNumBufferedBytes -= packet_size; if (mNumBufferedPackets == 0) { - assert(mNumBufferedBytes == 0); + //llassert(mNumBufferedBytes == 0); } if (!drop) @@ -215,7 +216,7 @@ S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop) } else { - assert(false); + //llassert(false); assertion disabled due to 0 size packets from server???? } } else diff --git a/indra/llmessage/tests/lldatapacker_test.cpp b/indra/llmessage/tests/lldatapacker_test.cpp index 5823980d43d..93e34df00c0 100644 --- a/indra/llmessage/tests/lldatapacker_test.cpp +++ b/indra/llmessage/tests/lldatapacker_test.cpp @@ -479,15 +479,15 @@ namespace tut lldp1.unpackFixed(f_unpkval, "linden_lab", FALSE, 8, 8); - ensure_approximately_equals("LLDataPackerAsciiFile::packFixed (iostring) failed", f_val, f_unpkval, 8); + ensure_approximately_equals("LLDataPackerAsciiFile::packFixed (iostring) failed", f_unpkval, f_val, 8); } template<> template<> void datapacker_test_object_t::test<14>() { - char str[] = "SecondLife is virtual World\0"; - char strBinary[] = "SecondLife is virtual World"; - char strBinaryFixed[] = "Fixed Data"; + const char str[] = "SecondLife is virtual World"; + const char strBinary[] = "SecondLife is virtual World"; + const char strBinaryFixed[] = "Fixed Data"; S32 sizeBinaryFixed = sizeof(strBinaryFixed); U8 valU8 = 'C'; U16 valU16 = 0xFFFF; diff --git a/indra/llphysicsextensionsos/CMakeLists.txt b/indra/llphysicsextensionsos/CMakeLists.txt index ff1b703dc77..3b53761dc42 100644 --- a/indra/llphysicsextensionsos/CMakeLists.txt +++ b/indra/llphysicsextensionsos/CMakeLists.txt @@ -1,13 +1,9 @@ # -*- cmake -*- -project(llphysicsextensionsos) +add_library(llphysicsextensionsos STATIC) -include(00-Common) -include(LLCommon) -include(LLMath) -include(VHACD) - -set(llphysicsextensionsos_SOURCE_FILES +target_sources(llphysicsextensionsos + PRIVATE llconvexdecomposition.cpp llconvexdecompositionvhacd.cpp llpathinglib.cpp @@ -16,8 +12,10 @@ set(llphysicsextensionsos_SOURCE_FILES LLPhysicsExtensionsStubImpl.cpp ) -set(llphysicsextensionsos_HEADER_FILES - CMakeLists.txt +target_sources(llphysicsextensionsos + PUBLIC + FILE_SET HEADERS + FILES llconvexdecomposition.h llconvexdecompositionvhacd.h llpathinglib.h @@ -26,26 +24,18 @@ set(llphysicsextensionsos_HEADER_FILES LLPhysicsExtensionsStubImpl.h ) -set_source_files_properties(${llphysicsextensionsos_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND llphysicsextensionsos_SOURCE_FILES ${llphysicsextensionsos_HEADER_FILES}) - -add_library (llphysicsextensionsos ${llphysicsextensionsos_SOURCE_FILES}) target_include_directories(llphysicsextensionsos INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - target_link_libraries(llphysicsextensionsos - llcommon + PUBLIC llmath + llcommon ll::vhacd) +target_precompile_headers(llphysicsextensionsos REUSE_FROM llprecompiled) + if(WINDOWS) target_compile_options(llphysicsextensionsos PRIVATE /bigobj) endif() -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llphysicsextensionsos REUSE_FROM llprecompiled) -endif () - # Add tests diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index f67975365a4..49f19a54dbf 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -1,14 +1,9 @@ # -*- cmake -*- -project(llplugin) +add_library (llplugin STATIC) -include(00-Common) -include(CURL) -include(LLCommon) -include(LLImage) -include(LLWindow) - -set(llplugin_SOURCE_FILES +target_sources(llplugin + PRIVATE llpluginclassmedia.cpp llplugininstance.cpp llpluginmessage.cpp @@ -16,10 +11,10 @@ set(llplugin_SOURCE_FILES llpluginprocesschild.cpp llpluginprocessparent.cpp llpluginsharedmemory.cpp - ) -set(llplugin_HEADER_FILES - CMakeLists.txt + PUBLIC + FILE_SET HEADERS + FILES llpluginclassmedia.h llpluginclassmediaowner.h llplugininstance.h @@ -31,15 +26,9 @@ set(llplugin_HEADER_FILES llpluginsharedmemory.h ) -list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES}) - -add_library (llplugin ${llplugin_SOURCE_FILES}) -target_include_directories( llplugin INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries( llplugin llcommon llmath llmessage llxml ) - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llplugin REUSE_FROM llprecompiled) -endif () +target_link_libraries(llplugin PUBLIC llcommon llmath llmessage llxml) +target_include_directories(llplugin INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +target_precompile_headers(llplugin REUSE_FROM llprecompiled) add_subdirectory(slplugin) diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt index f746160ada1..84656f1a5dd 100644 --- a/indra/llplugin/slplugin/CMakeLists.txt +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -1,21 +1,26 @@ -project(SLPlugin) -include(00-Common) -include(LLCommon) -include(Linking) include(PluginAPI) ### SLPlugin -set(SLPlugin_SOURCE_FILES +add_executable(SLPlugin + WIN32 + MACOSX_BUNDLE + ) + +target_sources(SLPlugin + PRIVATE slplugin.cpp ) if (DARWIN) - list(APPEND SLPlugin_SOURCE_FILES + target_sources(SLPlugin + PRIVATE slplugin-objc.mm - ) - list(APPEND SLPlugin_HEADER_FILES + + PUBLIC + FILE_SET HEADERS + FILES slplugin-objc.h ) @@ -26,16 +31,6 @@ if (DARWIN) ) endif (DARWIN) -if (SLPlugin_HEADER_FILES) - list(APPEND SLPlugin_SOURCE_FILES ${SLPlugin_HEADER_FILES}) -endif (SLPlugin_HEADER_FILES) - -add_executable(SLPlugin - WIN32 - MACOSX_BUNDLE - ${SLPlugin_SOURCE_FILES} - ) - target_link_libraries(SLPlugin llplugin llmessage @@ -43,15 +38,13 @@ target_link_libraries(SLPlugin ll::pluginlibraries ) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(SLPlugin REUSE_FROM llprecompiled) -endif () +target_precompile_headers(SLPlugin REUSE_FROM llprecompiled_exe) -if (WINDOWS) +if(WINDOWS) set_target_properties(SLPlugin PROPERTIES - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\"" - ) + RUNTIME_OUTPUT_DIRECTORY ${VIEWER_STAGING_DIR} + ) elseif (DARWIN) set_target_properties(SLPlugin PROPERTIES @@ -60,17 +53,4 @@ elseif (DARWIN) MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" ) - - # Make sure the app bundle has a Resources directory (it will get populated by viewer-manifest.py later) - add_custom_command( - TARGET SLPlugin POST_BUILD - COMMAND mkdir - ARGS - -p - ${CMAKE_CURRENT_BINARY_DIR}/$,$,>/SLPlugin.app/Contents/Resources - ) endif () - -if (LL_TESTS) - ll_deploy_sharedlibs_command(SLPlugin) -endif (LL_TESTS) diff --git a/indra/llprecompiled/CMakeLists.txt b/indra/llprecompiled/CMakeLists.txt index ea230f4a982..f3303cb8c1e 100644 --- a/indra/llprecompiled/CMakeLists.txt +++ b/indra/llprecompiled/CMakeLists.txt @@ -1,26 +1,13 @@ # -*- cmake -*- -project(llprecompiled) - -include(00-Common) -include(APR) -include(bugsplat) -include(Linking) -include(Boost) -include(LLSharedLibs) -include(ZLIBNG) -include(Tracy) -include(EXPAT) -include(SSE2NEON) - set(llprecompiled_SOURCE_FILES cmake_dummy.cpp ) -add_library (llprecompiled ${llprecompiled_SOURCE_FILES}) +add_library (llprecompiled STATIC ${llprecompiled_SOURCE_FILES}) target_include_directories(llprecompiled PRIVATE - ${CMAKE_SOURCE_DIR}/${LIBS_OPEN_PREFIX}llmath + ${INDRA_SOURCE_DIR}/llmath ) target_link_libraries(llprecompiled @@ -51,3 +38,38 @@ target_precompile_headers(llprecompiled PRIVATE ) + +add_executable(llprecompiled_exe ${llprecompiled_SOURCE_FILES}) + +target_include_directories(llprecompiled_exe PRIVATE + ${INDRA_SOURCE_DIR}/llmath + ) + +target_link_libraries(llprecompiled_exe + llcommon + ll::apr + ll::expat + ll::zlib-ng + ll::boost + ll::oslibraries + ll::tracy + ll::sse2neon + ) + +target_precompile_headers(llprecompiled_exe PRIVATE + [["linden_common.h"]] + [["llwin32headers.h"]] + [["llprofiler.h"]] + [["llmath.h"]] + + + + + + + + + + + + ) diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index f05be03034f..49e04a0c410 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -1,16 +1,9 @@ # -*- cmake -*- -project(llprimitive) +add_library (llprimitive STATIC) -include(00-Common) -include(LLCommon) -include(LLCoreHttp) -include(LLPhysicsExtensions) -include(LLPrimitive) -include(GLM) -include(TinyGLTF) - -set(llprimitive_SOURCE_FILES +target_sources(llprimitive + PRIVATE lldaeloader.cpp llgltfmaterial.cpp llmaterialid.cpp @@ -26,10 +19,10 @@ set(llprimitive_SOURCE_FILES lltreeparams.cpp llvolumemessage.cpp material_codes.cpp - ) -set(llprimitive_HEADER_FILES - CMakeLists.txt + PUBLIC + FILE_SET HEADERS + FILES lldaeloader.h llgltfmaterial.h llgltfmaterial_templates.h @@ -52,39 +45,36 @@ set(llprimitive_HEADER_FILES object_flags.h ) -list(APPEND llprimitive_SOURCE_FILES ${llprimitive_HEADER_FILES}) - -add_library (llprimitive ${llprimitive_SOURCE_FILES}) target_include_directories( llprimitive INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(llprimitive - llcommon - llmath + PUBLIC + llcharacter + llrender llmessage llcorehttp llxml - llcharacter - llrender + llcommon + llmath ll::colladadom ll::glm + ll::tinygltf ) if (HAVOK OR HAVOK_TPV) - target_link_libraries(llprimitive + target_link_libraries(llprimitive PUBLIC llphysicsextensions_impl ) else() - target_link_libraries(llprimitive + target_link_libraries(llprimitive PUBLIC llphysicsextensionsos ) endif () -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llprimitive REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llprimitive REUSE_FROM llprecompiled) -#add unit tests -if (LL_TESTS) +# add unit tests +if (BUILD_TESTING) INCLUDE(LLAddBuildTest) SET(llprimitive_TEST_SOURCE_FILES llmediaentry.cpp @@ -94,4 +84,4 @@ if (LL_TESTS) set_property(SOURCE llprimitive.cpp PROPERTY LL_TEST_ADDITIONAL_LIBRARIES llmessage) LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}") -endif (LL_TESTS) +endif () diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index b2cd1dc5978..41f28c9791e 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -32,7 +32,7 @@ #include "llsdserialize.h" // NOTE -- this should be the one and only place tiny_gltf.h is included -#include "tinygltf/tiny_gltf.h" +#include #include "llgltfmaterial_templates.h" const char* const LLGLTFMaterial::ASSET_VERSION = "1.1"; diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 8055bffd32a..9b4f7348a57 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -33,11 +33,7 @@ #include "llvector4a.h" #include "hbxxh.h" -#ifdef LL_USESYSTEMLIBS -# include -#else -# include "zlib-ng/zlib.h" -#endif +#include std::string model_names[] = { diff --git a/indra/llprimitive/tests/llgltfmaterial_test.cpp b/indra/llprimitive/tests/llgltfmaterial_test.cpp index 4f2de82386a..69552452b3b 100644 --- a/indra/llprimitive/tests/llgltfmaterial_test.cpp +++ b/indra/llprimitive/tests/llgltfmaterial_test.cpp @@ -50,7 +50,7 @@ // implementation to be defined in order for llprimitive to link correctly. #define TINYGLTF_NO_EXTERNAL_IMAGE 1 -#include "tinygltf/tiny_gltf.h" +#include namespace tut { @@ -62,9 +62,9 @@ namespace tut tut::llgltfmaterial_t tut_llgltfmaterial("llgltfmaterial"); // A positive 32-bit float with a long string representation - constexpr F32 test_fraction = 1.09045365e-32; + constexpr F32 test_fraction = 1.09045365e-32f; // A larger positive 32-bit float for values that get zeroed if below a threshold - constexpr F32 test_fraction_big = 0.109045; + constexpr F32 test_fraction_big = 0.109045f; void apply_test_material_texture_ids(LLGLTFMaterial& material) { @@ -143,10 +143,16 @@ namespace tut { #if ADDRESS_SIZE != 32 #if LL_WINDOWS +#ifdef _DEBUG // Only when building against debug MSVC libs + // If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial) + // This test result will vary between compilers, so only test a single platform + ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 240); +#else // If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial) // This test result will vary between compilers, so only test a single platform ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 232); #endif +#endif #endif ensure_equals("LLGLTFMaterial texture info count", (U32)LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, 4); } @@ -408,6 +414,8 @@ namespace tut template<> template<> void llgltfmaterial_object_t::test<12>() { + skip("Test is unreliable due to material structure hashing fragility"); + // *NOTE: Due to direct manipulation of the fields of materials // throughout this test, the resulting modified materials may not be // compliant or properly serializable. diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 82ffa5dde46..d892bd9d304 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -1,14 +1,5 @@ # -*- cmake -*- -project(llrender) - -include(00-Common) -include(OpenGL) -include(FreeType) -include(LLCommon) -include(LLImage) -include(LLWindow) - set(llrender_SOURCE_FILES llcubemap.cpp llcubemaparray.cpp @@ -34,10 +25,8 @@ set(llrender_SOURCE_FILES llvertexbuffer.cpp llglcommonfunc.cpp ) - -set(llrender_HEADER_FILES - CMakeLists.txt +set(llrender_HEADER_FILES llcubemap.h llcubemaparray.h llfontgl.h @@ -69,7 +58,7 @@ set(llrender_HEADER_FILES list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES}) if (BUILD_HEADLESS) - add_library (llrenderheadless + add_library (llrenderheadless STATIC ${llrender_SOURCE_FILES} ) target_include_directories(llrenderheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) @@ -82,15 +71,15 @@ if (BUILD_HEADLESS) llfilesystem llwindowheadless ll::freetype + ll::nanosvg + ll::glext OpenGL::GL ) - if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llrenderheadless REUSE_FROM llprecompiled) - endif() + target_precompile_headers(llrenderheadless REUSE_FROM llprecompiled) endif (BUILD_HEADLESS) -add_library (llrender ${llrender_SOURCE_FILES}) +add_library (llrender STATIC ${llrender_SOURCE_FILES}) target_include_directories(llrender INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) # Libraries on which this library depends, needed for Linux builds @@ -103,15 +92,13 @@ target_link_libraries(llrender llxml llwindow ll::freetype + ll::glext ) -if (NOT USE_SDL_WINDOW) -target_link_libraries(llrender - OpenGL::GL - ) +target_precompile_headers(llrender REUSE_FROM llprecompiled) +if (NOT USE_SDL_WINDOW) + target_link_libraries(llrender + OpenGL::GL + ) endif() - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llrender REUSE_FROM llprecompiled) -endif () diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index d37b16ce0ca..6b98ca0b90b 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -31,15 +31,9 @@ // Freetype stuff #include -#ifdef LL_WINDOWS -#include -#endif +#include FT_SYSTEM_H #include "llfontfreetypesvg.h" - -// For some reason, this won't work if it's not wrapped in the ifdef -#ifdef FT_FREETYPE_H #include FT_FREETYPE_H -#endif #include "lldir.h" #include "llerror.h" diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index a268ea07bb4..94047d6337b 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -667,7 +667,7 @@ bool LLGLSLShader::mapAttributes() } mAttribute.clear(); -#if LL_RELEASE_WITH_DEBUG_INFO +#if LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size(), { -1, NULL }); #else mAttribute.resize(LLShaderMgr::instance()->mReservedAttribs.size(), -1); @@ -685,7 +685,7 @@ bool LLGLSLShader::mapAttributes() S32 index = glGetAttribLocation(mProgramObject, (const GLchar*)name); if (index != -1) { -#if LL_RELEASE_WITH_DEBUG_INFO +#if LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO mAttribute[i] = { index, name }; #else mAttribute[i] = index; diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 272a99aaa58..71f4c3221f5 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -289,7 +289,7 @@ class LLGLSLShader U32 mLightHash; GLuint mProgramObject; -#if LL_RELEASE_WITH_DEBUG_INFO +#if LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO struct attr_name { GLint loc; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index d59ddd0fecb..a0ba398eb8b 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -325,8 +325,8 @@ class LLVBOPool { public: virtual ~LLVBOPool() = default; - virtual void allocate(GLenum type, U32 size, GLuint& name, U8*& data) = 0; - virtual void free(GLenum type, U32 size, GLuint name, U8* data) = 0; + virtual void allocateVBO(GLenum type, U32 size, GLuint& name, U8*& data) = 0; + virtual void freeVBO(GLenum type, U32 size, GLuint name, U8* data) = 0; virtual U64 getVramBytesUsed() = 0; }; @@ -342,7 +342,7 @@ class LLAppleVBOPool final: public LLVBOPool return mAllocated; } - void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override + void allocateVBO(GLenum type, U32 size, GLuint& name, U8*& data) override { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; STOP_GLERROR; @@ -362,7 +362,7 @@ class LLAppleVBOPool final: public LLVBOPool } } - void free(GLenum type, U32 size, GLuint name, U8* data) override + void freeVBO(GLenum type, U32 size, GLuint name, U8* data) override { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); @@ -429,7 +429,7 @@ class LLDefaultVBOPool final : public LLVBOPool size += block_size - (size % block_size); } - void allocate(GLenum type, U32 size, GLuint& name, U8*& data) override + void allocateVBO(GLenum type, U32 size, GLuint& name, U8*& data) override { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); @@ -485,7 +485,7 @@ class LLDefaultVBOPool final : public LLVBOPool clean(); } - void free(GLenum type, U32 size, GLuint name, U8* data) override + void freeVBO(GLenum type, U32 size, GLuint name, U8* data) override { LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER); @@ -1101,7 +1101,7 @@ void LLVertexBuffer::genBuffer(U32 size) llassert(mMappedData == nullptr); mSize = size; - sVBOPool->allocate(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData); + sVBOPool->allocateVBO(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData); } } @@ -1116,7 +1116,7 @@ void LLVertexBuffer::genIndices(U32 size) llassert(mGLIndices == 0); llassert(mMappedIndexData == nullptr); mIndicesSize = size; - sVBOPool->allocate(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData); + sVBOPool->allocateVBO(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData); } } @@ -1174,7 +1174,7 @@ void LLVertexBuffer::destroyGLBuffer() //llassert(sVBOPool); if (sVBOPool) { - sVBOPool->free(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData); + sVBOPool->freeVBO(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData); } mSize = 0; @@ -1191,7 +1191,7 @@ void LLVertexBuffer::destroyGLIndices() //llassert(sVBOPool); if (sVBOPool) { - sVBOPool->free(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData); + sVBOPool->freeVBO(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData); } mIndicesSize = 0; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index a71b1e747f5..ee453c394a0 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -1,16 +1,9 @@ # -*- cmake -*- -project(llui) +add_library (llui STATIC) -include(00-Common) -include(Hunspell) -include(LLCommon) -include(LLImage) -include(LLCoreHttp) -include(LLWindow) -include(LLCoreHttp) - -set(llui_SOURCE_FILES +target_sources(llui + PRIVATE llaccordionctrl.cpp llaccordionctrltab.cpp llbadge.cpp @@ -39,7 +32,7 @@ set(llui_SOURCE_FILES llfloater.cpp llfloaterreg.cpp llfloaterreglistener.cpp - llflyoutbutton.cpp + llflyoutbutton.cpp llfocusmgr.cpp llfolderview.cpp llfolderviewitem.cpp @@ -53,7 +46,7 @@ set(llui_SOURCE_FILES llmenubutton.cpp llmenugl.cpp llmodaldialog.cpp - llmultifloater.cpp + llmultifloater.cpp llmultislider.cpp llmultisliderctrl.cpp llnotifications.cpp @@ -117,11 +110,10 @@ set(llui_SOURCE_FILES llwindowshade.cpp llxuiparser.cpp llxyvector.cpp - ) - -set(llui_HEADER_FILES - CMakeLists.txt + PUBLIC + FILE_SET HEADERS + FILES llaccordionctrl.h llaccordionctrltab.h llbadge.h @@ -146,13 +138,13 @@ set(llui_HEADER_FILES llemojidictionary.h llemojihelper.h llf32uictrl.h - llfiltereditor.h + llfiltereditor.h llflashtimer.h llflatlistview.h llfloater.h llfloaterreg.h llfloaterreglistener.h - llflyoutbutton.h + llflyoutbutton.h llfocusmgr.h llfolderview.h llfolderviewitem.h @@ -169,7 +161,7 @@ set(llui_HEADER_FILES llmenubutton.h llmenugl.h llmodaldialog.h - llmultifloater.h + llmultifloater.h llmultisliderctrl.h llmultislider.h llnotificationptr.h @@ -186,7 +178,7 @@ set(llui_HEADER_FILES llresmgr.h llrngwriter.h llsearchablecontrol.h - llsearcheditor.h + llsearcheditor.h llscrollbar.h llscrollcontainer.h llscrollingpanellist.h @@ -252,13 +244,11 @@ set_source_files_properties(llurlentry.cpp "${llurlentry_TEST_DEPENDENCIES}" ) -list(APPEND llui_SOURCE_FILES ${llui_HEADER_FILES}) - -add_library (llui ${llui_SOURCE_FILES}) target_include_directories( llui INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level target_link_libraries(llui + PUBLIC llrender llwindow llimage @@ -268,17 +258,14 @@ target_link_libraries(llui llfilesystem llxml llmath - ll::hunspell llcommon + ll::hunspell ) -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llui REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llui REUSE_FROM llprecompiled) # Add tests -if(LL_TESTS) - include(LLAddBuildTest) +if(BUILD_TESTING) set(test_libs llmessage llcorehttp llxml llrender llcommon ll::hunspell) SET(llui_TEST_SOURCE_FILES @@ -288,6 +275,7 @@ if(LL_TESTS) LL_ADD_PROJECT_UNIT_TESTS(llui "${llui_TEST_SOURCE_FILES}") # INTEGRATION TESTS - set(test_libs llui llmessage llcorehttp llxml llrender llcommon ll::hunspell ) - LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}") -endif(LL_TESTS) + set(test_libs llui llmessage llcorehttp llxml llrender llcommon ll::hunspell) + set(test_project llui) + LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}" "${test_project}") +endif() diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp index 34eb1ea3fc6..266701fce55 100644 --- a/indra/llui/llflatlistview.cpp +++ b/indra/llui/llflatlistview.cpp @@ -121,36 +121,47 @@ bool LLFlatListView::addItemPairs(pairs_list_t panel_list, bool rearrange /*= tr panel_list.sort(ComparatorAdaptor(*mItemComparator)); pairs_const_iterator_t new_pair_it = panel_list.begin(); - item_pair_t* new_pair = *new_pair_it; - pairs_iterator_t pair_it = mItemPairs.begin(); - item_pair_t* item_pair = *pair_it; - - // sort panel_list into mItemPars - while (new_pair_it != panel_list.end() && pair_it != mItemPairs.end()) + if (!mItemPairs.empty()) { - if (!new_pair->first || new_pair->first->getParent() == mItemsPanel) - { - // iterator already used or we are reusing existing panel - new_pair_it++; - new_pair = *new_pair_it; - } - else if (mItemComparator->compare(new_pair->first, item_pair->first)) + item_pair_t* new_pair = *new_pair_it; + pairs_iterator_t pair_it = mItemPairs.begin(); + item_pair_t* item_pair = *pair_it; + + // sort panel_list into mItemPars + while (new_pair_it != panel_list.end() && pair_it != mItemPairs.end()) { - LLPanel* panel = new_pair->first; + if (!new_pair->first || new_pair->first->getParent() == mItemsPanel) + { + // iterator already used or we are reusing existing panel + new_pair_it++; - mItemPairs.insert(pair_it, new_pair); - mItemsPanel->addChild(panel); + // End of new panels, bail out + if (new_pair_it == panel_list.end()) + break; - //_4 is for MASK - panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); - panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); - // Children don't accept the focus - panel->setTabStop(false); - } - else - { - pair_it++; - item_pair = *pair_it; + new_pair = *new_pair_it; + } + else if (mItemComparator->compare(new_pair->first, item_pair->first)) + { + LLPanel* panel = new_pair->first; + + mItemPairs.insert(pair_it, new_pair); + mItemsPanel->addChild(panel); + + //_4 is for MASK + panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + // Children don't accept the focus + panel->setTabStop(false); + } + else + { + pair_it++; + // End of existing panels, bail out + if (pair_it == mItemPairs.end()) + break; + item_pair = *pair_it; + } } } diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 2bea8fb4ed2..5b58e23f220 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -803,9 +803,9 @@ void LLKeywords::dump() void LLKeywordToken::dump() { LL_INFOS() << "[" << - mColor.mV[VRED] << ", " << - mColor.mV[VGREEN] << ", " << - mColor.mV[VBLUE] << "] [" << + mColor().mV[VRED] << ", " << + mColor().mV[VGREEN] << ", " << + mColor().mV[VBLUE] << "] [" << wstring_to_utf8str(mToken) << "]" << LL_ENDL; } diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index f4ef6f79f1e..2365d0fe23e 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -30,11 +30,8 @@ #include "llxmlnode.h" #include "llfasttimer.h" -#ifdef LL_USESYSTEMLIBS + #include -#else -#include "expat/expat.h" -#endif #include #include diff --git a/indra/llwebrtc/CMakeLists.txt b/indra/llwebrtc/CMakeLists.txt index eb10f4eee49..310bb525a09 100644 --- a/indra/llwebrtc/CMakeLists.txt +++ b/indra/llwebrtc/CMakeLists.txt @@ -1,38 +1,28 @@ # -*- cmake -*- -# some webrtc headers require C++ 20 -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -include(00-Common) -include(Linking) -include(WebRTC) - -project(llwebrtc) - set(llwebrtc_SOURCE_FILES llwebrtc.cpp ) set(llwebrtc_HEADER_FILES - CMakeLists.txt llwebrtc.h llwebrtc_impl.h ) list(APPEND llwebrtc_SOURCE_FILES ${llwebrtc_HEADER_FILES}) -add_library (llwebrtc SHARED ${llwebrtc_SOURCE_FILES}) - +add_library(llwebrtc SHARED ${llwebrtc_SOURCE_FILES}) set_target_properties(llwebrtc PROPERTIES PUBLIC_HEADER llwebrtc.h) if (WINDOWS) - cmake_policy(SET CMP0091 NEW) set_target_properties(llwebrtc PROPERTIES - LINK_FLAGS "/debug /LARGEADDRESSAWARE" + LINK_FLAGS "/debug /LARGEADDRESSAWARE /NODEFAULTLIB:\"LIBCMTD;MSVCRT;MSVCRTD\" /MANIFEST:NO" # Intentionally override all link flags for llwebrtc + MSVC_RUNTIME_LIBRARY "MultiThreaded" + EXCLUDE_FROM_DEFAULT_BUILD_DEBUG ON + RUNTIME_OUTPUT_DIRECTORY "${VIEWER_STAGING_DIR}" ) - target_link_libraries(llwebrtc PRIVATE ll::webrtc + target_link_libraries(llwebrtc PRIVATE ll::webrtc secur32 winmm dmoguids @@ -41,34 +31,31 @@ if (WINDOWS) strmiids iphlpapi libcmt) - # as the webrtc libraries are release, build this binary as release as well. - target_compile_options(llwebrtc PRIVATE "/MT" "/Zc:wchar_t") + if (USE_BUGSPLAT) set_target_properties(llwebrtc PROPERTIES PDB_OUTPUT_DIRECTORY "${SYMBOLS_STAGING_DIR}") endif (USE_BUGSPLAT) -elseif (DARWIN) +elseif(DARWIN) target_link_libraries(llwebrtc PRIVATE ll::webrtc) + target_compile_options(llwebrtc PRIVATE -Wno-deprecated-declarations) # webrtc::CreateAudioDeviceWithDataObserver is deprecated + if (USE_BUGSPLAT) set_target_properties(llwebrtc PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" XCODE_ATTRIBUTE_DWARF_DSYM_FOLDER_PATH "${SYMBOLS_STAGING_DIR}/dSYMs") + if(NOT XCODE) + find_program(DSYMUTIL dsymutil REQUIRED) + add_custom_command(TARGET llwebrtc POST_BUILD + COMMAND dsymutil $ + COMMENT "Generating llwebrtc.dSYM") + endif() endif (USE_BUGSPLAT) -elseif (LINUX) - target_link_libraries(llwebrtc PRIVATE ll::webrtc) -endif (WINDOWS) - -target_include_directories( llwebrtc INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -if (WINDOWS) - set_property(TARGET llwebrtc PROPERTY - MSVC_RUNTIME_LIBRARY "MultiThreadedDebug") else() + target_link_libraries(llwebrtc PRIVATE ll::webrtc) target_compile_options(llwebrtc PRIVATE -Wno-deprecated-declarations) # webrtc::CreateAudioDeviceWithDataObserver is deprecated endif (WINDOWS) -ADD_CUSTOM_COMMAND(TARGET llwebrtc POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ - ${SHARED_LIB_STAGING_DIR}) +target_include_directories(llwebrtc INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + # Add tests -if (LL_TESTS) -endif (LL_TESTS) +if (BUILD_TESTING) +endif () diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h index 7d06b7d2b40..414a557fafc 100644 --- a/indra/llwebrtc/llwebrtc.h +++ b/indra/llwebrtc/llwebrtc.h @@ -44,10 +44,8 @@ #ifdef LL_MAKEDLL #ifdef WEBRTC_WIN #define LLSYMEXPORT __declspec(dllexport) -#elif WEBRTC_LINUX -#define LLSYMEXPORT __attribute__((visibility("default"))) #else -#define LLSYMEXPORT /**/ +#define LLSYMEXPORT __attribute__((visibility("default"))) #endif #else #define LLSYMEXPORT /**/ diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index aacaef9257b..d654c2a9e94 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -8,99 +8,84 @@ # Unfortunately, the affected code is a rat's nest of #ifdefs, so it's # easier to play compilation tricks than to actually fix the problem. -project(llwindow) - -include(00-Common) -include(DragDrop) -include(Linking) -include(LLCommon) -include(LLImage) -include(LLWindow) include(UI) -include(ViewerMiscLibs) -include(GLM) -include(SDL3) - -set(llwindow_SOURCE_FILES - llcursortypes.cpp - llkeyboard.cpp - llkeyboardheadless.cpp - llwindowheadless.cpp - llwindowcallbacks.cpp - llwindow.cpp - ) - -set(llwindow_HEADER_FILES - CMakeLists.txt - - llcursortypes.h - llkeyboard.h - llkeyboardheadless.h - llwindowheadless.h - llwindowcallbacks.h - ) - -set(viewer_SOURCE_FILES - llmousehandler.cpp - ) - -set(viewer_HEADER_FILES - llwindow.h + +set(llwindow_BASE_SOURCE_FILES + llcursortypes.cpp + llkeyboard.cpp + llkeyboardheadless.cpp + llmousehandler.cpp + llwindow.cpp + llwindowheadless.cpp + llwindowcallbacks.cpp +) + +set(llwindow_BASE_HEADER_FILES + llcursortypes.h + llkeyboard.h + llkeyboardheadless.h + llmousehandler.h + llwindow.h + llwindowheadless.h + llwindowcallbacks.h +) + +set(llwindow_BASE_LINK_LIBRARIES + llcommon + llimage + llmath + llfilesystem + llxml + ll::glm +) + +add_library(llwindow STATIC) + +target_sources(llwindow + PRIVATE + ${llwindow_BASE_SOURCE_FILES} + PUBLIC + ${llwindow_BASE_HEADER_FILES} llpreeditor.h - llmousehandler.h - ) - -set(llwindow_LINK_LIBRARIES - llcommon - llimage - llmath - llrender - llfilesystem - llxml - ll::glm - ll::glext - ll::uilibraries - ) - -if (USE_SDL_WINDOW) - list(APPEND viewer_SOURCE_FILES - llsdl.cpp - llkeyboardsdl.cpp - llwindowsdl.cpp - ) - list(APPEND viewer_HEADER_FILES - llsdl.h - llkeyboardsdl.h - llwindowsdl.h - ) - - list(APPEND llwindow_LINK_LIBRARIES - ll::SDL3 - ) -endif () - -if (DARWIN) - list(APPEND llwindow_SOURCE_FILES - llkeyboardmacosx.cpp - llwindowmacosx.cpp - llwindowmacosx-objc.mm - llopenglview-objc.mm - ) - list(APPEND llwindow_HEADER_FILES - llkeyboardmacosx.h - llwindowmacosx.h - llwindowmacosx-objc.h - llopenglview-objc.h - llappdelegate-objc.h - ) - - # We use a bunch of deprecated system APIs. - set_source_files_properties( +) + +target_link_libraries(llwindow llrender ${llwindow_BASE_LINK_LIBRARIES} ll::uilibraries) +target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) +target_precompile_headers(llwindow REUSE_FROM llprecompiled) + +if(USE_SDL_WINDOW) + target_sources(llwindow + PRIVATE + llsdl.cpp + llkeyboardsdl.cpp + llwindowsdl.cpp + PUBLIC + llsdl.h + llkeyboardsdl.h + llwindowsdl.h + ) + + target_compile_definitions(llwindow PUBLIC LL_SDL_WINDOW=1) + + target_link_libraries(llwindow + ll::SDL3 + ) +endif() + +if(DARWIN) + target_sources(llwindow + PRIVATE llkeyboardmacosx.cpp llwindowmacosx.cpp - PROPERTIES - COMPILE_FLAGS "-fpascal-strings" - ) + llwindowmacosx-objc.mm + llopenglview-objc.mm + PUBLIC + llkeyboardmacosx.h + llwindowmacosx.h + llwindowmacosx-objc.h + llopenglview-objc.h + llappdelegate-objc.h + ) set_source_files_properties( llwindowmacosx-objc.mm @@ -108,103 +93,43 @@ if (DARWIN) PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE ) -endif (DARWIN) - - -if (WINDOWS) - list(APPEND llwindow_SOURCE_FILES - llwindowwin32.cpp - lldxhardware.cpp - llkeyboardwin32.cpp - lldragdropwin32.cpp - ) - list(APPEND llwindow_HEADER_FILES - llwindowwin32.h - lldxhardware.h - llkeyboardwin32.h - lldragdropwin32.h - ) - list(APPEND llwindow_LINK_LIBRARIES - comdlg32 # Common Dialogs for ChooseColor - ole32 - dxgi - d3d9 - ) -endif (WINDOWS) - - -if (BUILD_HEADLESS) - set(llwindowheadless_SOURCE_FILES - llcursortypes.cpp - llkeyboard.cpp - llkeyboardheadless.cpp - llwindowheadless.cpp - llwindowcallbacks.cpp - llwindow.cpp +endif(DARWIN) + +if(WINDOWS) + target_sources(llwindow + PRIVATE + llwindowwin32.cpp + lldxhardware.cpp + llkeyboardwin32.cpp + lldragdropwin32.cpp + PUBLIC + llwindowwin32.h + lldxhardware.h + llkeyboardwin32.h + lldragdropwin32.h + ) +endif(WINDOWS) + +if(BUILD_HEADLESS) + add_library(llwindowheadless STATIC) + + target_sources(llwindowheadless + PRIVATE + ${llwindow_BASE_SOURCE_FILES} llwindowmesaheadless.cpp - llmousehandler.cpp - ) - - set(llwindowheadless_HEADER_FILES - llcursortypes.h - llkeyboard.h - llkeyboardheadless.h - llwindowheadless.h - llwindowcallbacks.h + PUBLIC + ${llwindow_BASE_HEADER_FILES} llwindowmesaheadless.h - llmousehandler.h - ) - - add_library (llwindowheadless - ${llwindowheadless_SOURCE_FILES} - ${llwindowheadless_HEADER_FILES} - ) + ) - target_compile_definitions( llwindowheadless PUBLIC LL_MESA_HEADLESS=1 ) + target_compile_definitions(llwindowheadless PUBLIC LL_MESA_HEADLESS=1) - target_link_libraries (llwindowheadless - llcommon - llimage - llmath - llrenderheadless - llfilesystem - llxml - ll::glm - ll::glext - ll::zlib-ng - PkgConfig::OSMESA - fontconfig - dl + target_link_libraries(llwindowheadless + llrenderheadless + ${llwindow_BASE_LINK_LIBRARIES} + PkgConfig::OSMESA + dl ) target_include_directories(llwindowheadless INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - - if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llwindowheadless REUSE_FROM llprecompiled) - endif () -endif (BUILD_HEADLESS) - -if (llwindow_HEADER_FILES) - list(APPEND llwindow_SOURCE_FILES ${llwindow_HEADER_FILES}) -endif (llwindow_HEADER_FILES) - - list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) - - add_library (llwindow - ${llwindow_SOURCE_FILES} - ${viewer_SOURCE_FILES} - ) - -target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) -target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -if (USE_SDL_WINDOW) - target_compile_definitions( llwindow PUBLIC LL_SDL_WINDOW=1 ) -endif() - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llwindow REUSE_FROM llprecompiled) -endif () - -if (DARWIN) - target_link_libraries(llwindow ${CARBON_LIBRARY}) -endif (DARWIN) + target_precompile_headers(llwindowheadless REUSE_FROM llprecompiled) +endif(BUILD_HEADLESS) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index f8920318d31..0c9c2fa0c30 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -2379,7 +2379,7 @@ bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, io_iterator_t io_iter = 0; // create an IO object iterator - result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); + result = IOServiceGetMatchingServices( kIOMainPortDefault, device_dict_ref, &io_iter ); if ( kIOReturnSuccess != result ) { LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 2d8a74c7822..9b39a5f5d4f 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -264,7 +264,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, true); SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, mFullscreen); - SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIDDEN_BOOLEAN, true); SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, gHiDPISupport); mWindow = SDL_CreateWindowWithProperties(props); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 252482a96e6..e34b39827f8 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1092,7 +1092,7 @@ bool LLWindowWin32::maximize() bool success = false; if (!mWindowHandle) return success; - mWindowThread->post([=] + mWindowThread->post([=, this] { WINDOWPLACEMENT placement; placement.length = sizeof(WINDOWPLACEMENT); @@ -1156,7 +1156,7 @@ bool LLWindowWin32::setSizeImpl(const LLCoordScreen size) return false; } - mWindowThread->post([=]() + mWindowThread->post([=, this]() { WINDOWPLACEMENT placement; placement.length = sizeof(WINDOWPLACEMENT); @@ -1771,7 +1771,7 @@ const S32 max_format = (S32)num_formats - 1; // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 - mWindowThread->post([=]() + mWindowThread->post([=, this]() { mWindowThread->glReady(); }); @@ -2004,7 +2004,7 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre // THIS CAUSES DEV-15484 and DEV-15949 //ShowWindow(mWindowHandle, SW_RESTORE); // NOW we can call MoveWindow - mWindowThread->post([=]() + mWindowThread->post([=, this]() { MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); }); @@ -2014,7 +2014,7 @@ void LLWindowWin32::setTitle(const std::string title) { // TODO: Do we need to use the wide string version of this call // to support non-ascii usernames (and region names?) - mWindowThread->post([=]() + mWindowThread->post([=, this]() { SetWindowText(mWindowHandle, ll_convert(title).c_str()); }); @@ -3119,7 +3119,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { // received a URL PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT)l_param; - void* data = new U8[myCDS->cbData]; + U8* data = new U8[myCDS->cbData]; memcpy(data, myCDS->lpData, myCDS->cbData); auto myType = myCDS->dwData; @@ -3502,7 +3502,7 @@ bool LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) void LLWindowWin32::flashIcon(F32 seconds) { - mWindowThread->post([=]() + mWindowThread->post([=, this]() { FLASHWINFO flash_info; @@ -3983,7 +3983,7 @@ void *LLWindowWin32::getPlatformWindow() void LLWindowWin32::bringToFront() { - mWindowThread->post([=]() + mWindowThread->post([=, this]() { BringWindowToTop(mWindowHandle); }); @@ -3992,7 +3992,7 @@ void LLWindowWin32::bringToFront() // set (OS) window focus back to the client void LLWindowWin32::focusClient() { - mWindowThread->post([=]() + mWindowThread->post([=, this]() { SetFocus(mWindowHandle); }); @@ -4030,7 +4030,7 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, bool b) if (sLanguageTextInputAllowed) { - mWindowThread->post([=]() + mWindowThread->post([=, this]() { // Allowing: Restore the previous IME status, so that the user has a feeling that the previous // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps @@ -4046,7 +4046,7 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, bool b) } else { - mWindowThread->post([=]() + mWindowThread->post([=, this]() { // Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly. // However, do it after saving the current IME status. We need to restore the status when @@ -4101,8 +4101,7 @@ void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) LLCoordWindow win_pos; convertCoords( position, &win_pos ); - if ( win_pos.mX >= 0 && win_pos.mY >= 0 && - (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) + if ( win_pos.mX >= 0 && win_pos.mY >= 0 && ((win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY))) { COMPOSITIONFORM ime_form; memset( &ime_form, 0, sizeof(ime_form) ); @@ -5112,7 +5111,7 @@ void LLWindowWin32::updateWindowRect() if (GetWindowRect(mWindowHandle, &rect) && GetClientRect(mWindowHandle, &client_rect)) { - post([=] + post([=, this] { mRect = rect; mClientRect = client_rect; @@ -5175,7 +5174,7 @@ void LLWindowWin32::setCustomIcon() { HICON hDefaultIcon = LoadIcon(mhInstance, mIconResource); HICON hSmallIcon = LoadIcon(mhInstance, mIconSmallResource); - mWindowThread->post([=]() + mWindowThread->post([=, this]() { SendMessage(mWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hDefaultIcon); SendMessage(mWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon); diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index bc79e2ef195..2090e829adb 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -1,48 +1,40 @@ # -*- cmake -*- -project(llxml) +add_library(llxml STATIC) -include(00-Common) -include(LLCommon) - -set(llxml_SOURCE_FILES +target_sources(llxml + PRIVATE llcontrol.cpp llxmlnode.cpp llxmlparser.cpp llxmltree.cpp ) -set(llxml_HEADER_FILES - CMakeLists.txt - +target_sources(llxml + PUBLIC + FILE_SET HEADERS + FILES llcontrol.h llxmlnode.h llxmlparser.h llxmltree.h ) -list(APPEND llxml_SOURCE_FILES ${llxml_HEADER_FILES}) - -add_library (llxml ${llxml_SOURCE_FILES}) # Libraries on which this library depends, needed for Linux builds # Sort by high-level to low-level -target_link_libraries( llxml - llfilesystem - llmath - llcommon - ll::expat +target_link_libraries(llxml + PUBLIC + llfilesystem + llmath + llcommon + ll::expat ) target_include_directories( llxml INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -if (USE_PRECOMPILED_HEADERS) - target_precompile_headers(llxml REUSE_FROM llprecompiled) -endif () +target_precompile_headers(llxml REUSE_FROM llprecompiled) # tests - -if (LL_TESTS) +if (BUILD_TESTING) # unit tests - SET(llxml_TEST_SOURCE_FILES # none yet! ) @@ -50,12 +42,13 @@ if (LL_TESTS) # integration tests - # set(TEST_DEBUG on) + # set(TEST_DEBUG on) set(test_libs llxml llmath llcommon ) + set(test_project llxml) - LL_ADD_INTEGRATION_TEST(llcontrol "" "${test_libs}") -endif (LL_TESTS) + LL_ADD_INTEGRATION_TEST(llcontrol "" "${test_libs}" "${test_project}") +endif () diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index df6be2546dd..b4d37355b7d 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -48,7 +48,7 @@ #include "lltimer.h" #include "lldir.h" -#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG +#ifdef SHOW_ASSERT #define CONTROL_ERRS LL_ERRS("ControlErrors") #else #define CONTROL_ERRS LL_WARNS("ControlErrors") diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp index 6bdc886319a..fe3c32b4641 100644 --- a/indra/llxml/llxmlnode.cpp +++ b/indra/llxml/llxmlnode.cpp @@ -1234,11 +1234,14 @@ bool LLXMLNode::getAttribute(const char* name, LLXMLNodePtr& node, bool use_defa bool LLXMLNode::getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, bool use_default_if_missing) { - LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); - if (child_itr != mAttributes.end()) + if (name) { - node = (*child_itr).second; - return true; + LLXMLAttribList::const_iterator child_itr = mAttributes.find(name); + if (child_itr != mAttributes.end()) + { + node = (*child_itr).second; + return true; + } } if (use_default_if_missing && !mDefault.isNull()) { diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index 09c7c4fdad9..57b7dc58117 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -27,14 +27,7 @@ #ifndef LL_LLXMLNODE_H #define LL_LLXMLNODE_H -#ifndef XML_STATIC -#define XML_STATIC -#endif -#ifdef LL_USESYSTEMLIBS #include -#else -#include "expat/expat.h" -#endif #include #include "indra_constants.h" diff --git a/indra/llxml/llxmlparser.h b/indra/llxml/llxmlparser.h index 0f64def6dfc..1255f0bca68 100644 --- a/indra/llxml/llxmlparser.h +++ b/indra/llxml/llxmlparser.h @@ -27,14 +27,7 @@ #ifndef LL_LLXMLPARSER_H #define LL_LLXMLPARSER_H -#ifndef XML_STATIC -#define XML_STATIC -#endif -#ifdef LL_USESYSTEMLIBS #include -#else -#include "expat/expat.h" -#endif class LLXmlParser { diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt index 600db532d26..acc821b9027 100644 --- a/indra/media_plugins/CMakeLists.txt +++ b/indra/media_plugins/CMakeLists.txt @@ -1,10 +1,19 @@ # -*- cmake -*- add_subdirectory(base) -add_subdirectory(cef) -add_subdirectory(libvlc) -add_subdirectory(example) -if (LINUX) +if (BUILD_EXAMPLE_PLUGIN) + add_subdirectory(example) +endif() + +if (BUILD_CEF_PLUGIN) + add_subdirectory(cef) +endif() + +if (BUILD_VLC_PLUGIN) + add_subdirectory(libvlc) +endif() + +if (BUILD_GSTREAMER_PLUGIN) add_subdirectory(gstreamer10) -endif (LINUX) +endif () diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/media_plugins/base/CMakeLists.txt index b6748abd476..7bba98bc4c4 100644 --- a/indra/media_plugins/base/CMakeLists.txt +++ b/indra/media_plugins/base/CMakeLists.txt @@ -1,29 +1,16 @@ # -*- cmake -*- - -project(media_plugin_base) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLWindow) -include(Linking) include(PluginAPI) - ### media_plugin_base - - set(media_plugin_base_SOURCE_FILES media_plugin_base.cpp ) set(media_plugin_base_HEADER_FILES - CMakeLists.txt - media_plugin_base.h ) -add_library(media_plugin_base +add_library(media_plugin_base STATIC ${media_plugin_base_SOURCE_FILES} ) diff --git a/indra/media_plugins/base/media_plugin_base.exp b/indra/media_plugins/base/media_plugin_base.exp deleted file mode 100644 index d8c7bb712a7..00000000000 --- a/indra/media_plugins/base/media_plugin_base.exp +++ /dev/null @@ -1,2 +0,0 @@ -_LLPluginInitEntryPoint - diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 3a91e398d5d..0a48d6bf651 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -1,14 +1,5 @@ # -*- cmake -*- - -project(media_plugin_cef) - -include(Boost) -include(00-Common) -include(LLCommon) -include(LLWindow) -include(Linking) include(PluginAPI) - include(CEFPlugin) include(GLIB) @@ -70,11 +61,37 @@ target_link_libraries(media_plugin_cef ) if (WINDOWS) - set_target_properties( - media_plugin_cef + set_target_properties(media_plugin_cef PROPERTIES - LINK_FLAGS "/MANIFEST:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099" - ) + EXCLUDE_FROM_DEFAULT_BUILD_DEBUG ON + RUNTIME_OUTPUT_DIRECTORY "${VIEWER_STAGING_DIR}/llplugin" + ) + target_link_options(media_plugin_cef PRIVATE /MANIFEST:NO /IGNORE:4099) + + # Copy plugin files to packaging directory + set(DULLAHAN_DIR "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/dullahan-bin") + add_custom_command( + TARGET media_plugin_cef POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${DULLAHAN_DIR}/bin" "${VIEWER_STAGING_DIR}/llplugin" + ) + + set(CEF_RESOURCE_FILES + "${DULLAHAN_DIR}/resources/chrome_100_percent.pak" + "${DULLAHAN_DIR}/resources/chrome_200_percent.pak" + "${DULLAHAN_DIR}/resources/resources.pak" + "${DULLAHAN_DIR}/resources/icudtl.dat" + ) + add_custom_command( + TARGET media_plugin_cef POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CEF_RESOURCE_FILES} "${VIEWER_STAGING_DIR}/llplugin" + COMMAND_EXPAND_LISTS + ) + + add_custom_command( + TARGET media_plugin_cef POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/dullahan-bin/resources/locales" "${VIEWER_STAGING_DIR}/llplugin/locales" + ) + elseif (DARWIN) find_library(CORESERVICES_LIBRARY CoreServices) find_library(AUDIOUNIT_LIBRARY AudioUnit) @@ -91,7 +108,6 @@ elseif (DARWIN) PREFIX "" BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@executable_path/../Frameworks" - LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) elseif (LINUX) diff --git a/indra/media_plugins/example/CMakeLists.txt b/indra/media_plugins/example/CMakeLists.txt index be8ffe5a40a..a9dcc0c1eb4 100644 --- a/indra/media_plugins/example/CMakeLists.txt +++ b/indra/media_plugins/example/CMakeLists.txt @@ -1,16 +1,7 @@ # -*- cmake -*- -project(media_plugin_example) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLWindow) -include(Linking) include(PluginAPI) -include(ExamplePlugin) - ### media_plugin_example set(media_plugin_example_SOURCE_FILES @@ -25,14 +16,12 @@ add_library(media_plugin_example target_link_libraries(media_plugin_example media_plugin_base ) if (WINDOWS) - set_target_properties( - media_plugin_example + set_target_properties(media_plugin_example PROPERTIES - LINK_FLAGS "/MANIFEST:NO /NODEFAULTLIB:LIBCMT" + RUNTIME_OUTPUT_DIRECTORY "${VIEWER_STAGING_DIR}/llplugin" ) -endif (WINDOWS) - -if (DARWIN) + target_link_options(media_plugin_example PRIVATE /MANIFEST:NO) +elseif (DARWIN) # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name set_target_properties( media_plugin_example @@ -40,7 +29,6 @@ if (DARWIN) PREFIX "" BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@executable_path/../Frameworks" - LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) -endif (DARWIN) +endif () diff --git a/indra/media_plugins/gstreamer10/CMakeLists.txt b/indra/media_plugins/gstreamer10/CMakeLists.txt index 279e07b2260..2dc8eaf8c2c 100644 --- a/indra/media_plugins/gstreamer10/CMakeLists.txt +++ b/indra/media_plugins/gstreamer10/CMakeLists.txt @@ -1,15 +1,6 @@ # -*- cmake -*- -project(media_plugin_gstreamer10) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLMath) -include(LLWindow) -include(Linking) include(PluginAPI) -include(OpenGL) include(GLIB) include(GStreamer10Plugin) diff --git a/indra/media_plugins/libvlc/CMakeLists.txt b/indra/media_plugins/libvlc/CMakeLists.txt index d2b2a616487..1c5be0a8394 100644 --- a/indra/media_plugins/libvlc/CMakeLists.txt +++ b/indra/media_plugins/libvlc/CMakeLists.txt @@ -1,14 +1,6 @@ # -*- cmake -*- -project(media_plugin_libvlc) - -include(00-Common) -include(LLCommon) -include(LLImage) -include(LLWindow) -include(Linking) include(PluginAPI) - include(LibVLCPlugin) ### media_plugin_libvlc @@ -29,14 +21,19 @@ target_link_libraries(media_plugin_libvlc ) if (WINDOWS) - set_target_properties( - media_plugin_libvlc + set_target_properties(media_plugin_libvlc PROPERTIES - LINK_FLAGS "/MANIFEST:NO /NODEFAULTLIB:LIBCMT" + EXCLUDE_FROM_DEFAULT_BUILD_DEBUG ON + RUNTIME_OUTPUT_DIRECTORY "${VIEWER_STAGING_DIR}/llplugin" ) -endif (WINDOWS) + target_link_options(media_plugin_libvlc PRIVATE /MANIFEST:NO) -if (DARWIN) + # Copy plugin dlls to packaging directory + add_custom_command( + TARGET media_plugin_libvlc POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/plugins/vlc-bin/plugins" "${VIEWER_STAGING_DIR}/llplugin/plugins" + ) +elseif (DARWIN) # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name set_target_properties( media_plugin_libvlc @@ -44,7 +41,6 @@ if (DARWIN) PREFIX "" BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@executable_path/../Frameworks" - LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) -endif (DARWIN) +endif () diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c76145fab3d..e7eab62075b 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1,52 +1,45 @@ # -*- cmake -*- -project(viewer) - -include(00-Common) -# DON'T move Linking.cmake to its place in the alphabetized list below: it -# sets variables on which the 3p .cmake files depend. -include(Linking) - -include(Boost) -include(bugsplat) include(BuildPackagesInfo) include(BuildVersion) include(CMakeCopyIfDifferent) -include(CubemapToEquirectangularJS) -include(DragDrop) -if (USE_DISCORD) - include(Discord) -endif () -include(EXPAT) -include(Hunspell) -include(JPEGEncoderBasic) -include(LLAppearance) -include(LLAudio) -include(LLCA) -include(LLCommon) -include(LLCoreHttp) -include(LLImage) -include(LLKDU) -include(LLPhysicsExtensions) -include(LLPrimitive) -include(LLWindow) -include(NDOF) -include(NVAPI) -include(OPENAL) -include(OpenGL) -include(OpenSSL) -include(OpenXR) -include(PNG) include(TemplateCheck) -include(TinyEXR) -include(ThreeJS) -include(Tracy) -include(UI) -include(ViewerMiscLibs) -include(ViewerManager) -include(VisualLeakDetector) -include(ZLIBNG) -include(LLPrimitive) + +set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING + "The name of the viewer executable to create.") + +# Generate version vars header +configure_file(llversioninfovars.h.in llversioninfovars.h @ONLY) + +if (BUILD_VIEWER) + +# Javascript files for 3D snapshot functionality +configure_file("${INDRA_SOURCE_DIR}/externals/js/CubemapToEquirectangular.js" "${CMAKE_CURRENT_SOURCE_DIR}/skins/default/html/common/equirectangular/js/CubemapToEquirectangular.js" COPYONLY) +configure_file("${INDRA_SOURCE_DIR}/externals/js/jpeg_encoder_basic.js" "${CMAKE_CURRENT_SOURCE_DIR}/skins/default/html/common/equirectangular/js/jpeg_encoder_basic.js" COPYONLY) +configure_file("${INDRA_SOURCE_DIR}/externals/js/three.min.js" "${CMAKE_CURRENT_SOURCE_DIR}/skins/default/html/common/equirectangular/js/three.min.js" COPYONLY) +configure_file("${INDRA_SOURCE_DIR}/externals/js/OrbitControls.js" "${CMAKE_CURRENT_SOURCE_DIR}/skins/default/html/common/equirectangular/js/OrbitControls.js" COPYONLY) + +message(STATUS "Copying fonts") +file(GLOB FONT_FILE_GLOB_LIST + "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/secondlife-fonts/fonts/*" +) +file(COPY ${FONT_FILE_GLOB_LIST} DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/fonts") + +# Copy over the Emoji/shortcodes mapping XML files (and create dependency +# if they are changed, CMake will run again and copy over new versions) +message(STATUS "Copying Emoji/shortcode mappings") +set(emoji_mapping_src_folder ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/secondlife-emoji-shortcodes/xui) +set(emoji_mapping_dst_folder ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui) + +# Note Turkey is missing from this set (not available in Emoji package yet) +set(country_codes "da;de;en;es;fr;it;ja;pl;pt;ru;zh") +foreach(elem ${country_codes}) + set(emoji_mapping_src_file + "${emoji_mapping_src_folder}/${elem}/emoji_characters.xml") + set(emoji_mapping_dst_file + "${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml") + configure_file(${emoji_mapping_src_file} ${emoji_mapping_dst_file} COPYONLY) +endforeach() if (HAVOK) # When using HAVOK_TPV, the library is precompiled, so no need for this @@ -76,8 +69,6 @@ if (HAVOK) endif() endif () -configure_file(llversioninfovars.h.in llversioninfovars.h @ONLY) - set(viewer_SOURCE_FILES gltfscenemanager.cpp gltf/asset.cpp @@ -727,6 +718,7 @@ set(viewer_SOURCE_FILES llvoiceclient.cpp llvoicevisualizer.cpp llvoicevivox.cpp + llvoicewebrtc.cpp llvoinventorylistener.cpp llvopartgroup.cpp llvosky.cpp @@ -753,11 +745,7 @@ set(viewer_SOURCE_FILES pipeline.cpp ) -set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING - "The name of the viewer executable to create.") - set(viewer_HEADER_FILES - CMakeLists.txt ViewerInstall.cmake gltfscenemanager.h groupchatlistener.h @@ -1403,6 +1391,7 @@ set(viewer_HEADER_FILES llvoiceclient.h llvoicevisualizer.h llvoicevivox.h + llvoicewebrtc.h llvoinventorylistener.h llvopartgroup.h llvosky.h @@ -1437,11 +1426,6 @@ source_group("CMake Rules" FILES ViewerInstall.cmake) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n") -if (NOT DISABLE_WEBRTC) - LIST(APPEND viewer_SOURCE_FILES llvoicewebrtc.cpp) - LIST(APPEND viewer_HEADER_FILES llvoicewebrtc.h) -endif() - if (DARWIN) LIST(APPEND viewer_SOURCE_FILES llappviewermacosx.cpp) LIST(APPEND viewer_SOURCE_FILES llappviewermacosx-objc.mm) @@ -1608,20 +1592,6 @@ if (WINDOWS) list(APPEND viewer_SOURCE_FILES ${viewer_RESOURCE_FILES}) - find_library(INTEL_MEMOPS_LIBRARY - NAMES ll_intel_memops - PATHS - optimized ${ARCH_PREBUILT_DIRS_RELEASE} - debug ${ARCH_PREBUILT_DIRS_DEBUG} - ) - mark_as_advanced(INTEL_MEMOPS_LIBRARY) - - - if (INTEL_MEMOPS_LIBRARY) - add_library( ll::intel_memops INTERFACE IMPORTED ) - target_link_libraries( ll::intel_memops ${INTEL_MEMOPS_LIBRARY} ) - endif (INTEL_MEMOPS_LIBRARY) - if (ADDRESS_SIZE EQUAL 64) # We deliberately omit this from the 32bit build because it declares that # the viewer is compatible with Windows 10; we need that to properly detect @@ -1650,7 +1620,6 @@ set_source_files_properties(${viewer_SHADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND viewer_SOURCE_FILES ${viewer_SHADER_FILES}) - set(viewer_APPSETTINGS_FILES app_settings/anim.ini app_settings/autoreplace.xml @@ -1672,8 +1641,7 @@ set(viewer_APPSETTINGS_FILES app_settings/trees.xml app_settings/viewerart.xml app_settings/message.xml - ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg - packages-info.txt + ${SCRIPTS_DIR}/messages/message_template.msg featuretable.txt featuretable_mac.txt featuretable_linux.txt @@ -1728,266 +1696,11 @@ add_executable(${VIEWER_BINARY_NAME} ${viewer_SOURCE_FILES} ) -target_include_directories(${VIEWER_BINARY_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) - -# add package files -file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST - ${CMAKE_CURRENT_SOURCE_DIR}/../viewer_components/*.py) -list(APPEND EVENT_HOST_SCRIPTS ${EVENT_HOST_SCRIPT_GLOB_LIST}) - -set(PACKAGE ON CACHE BOOL - "Add a package target that builds an installer package.") - -if(USE_PRECOMPILED_HEADERS) - target_precompile_headers( ${VIEWER_BINARY_NAME} PRIVATE llviewerprecompiledheaders.h ) -endif(USE_PRECOMPILED_HEADERS) - -if (WINDOWS) - set_target_properties(${VIEWER_BINARY_NAME} - PROPERTIES - # *TODO -reenable this once we get server usage sorted out - LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /LARGEADDRESSAWARE" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO /LARGEADDRESSAWARE" - LINK_FLAGS_RELEASE "/FORCE:MULTIPLE /MAP\"secondlife-bin.MAP\" /OPT:REF /LARGEADDRESSAWARE" - ) - target_compile_options(${VIEWER_BINARY_NAME} PRIVATE /bigobj) - - # If adding a file to viewer_manifest.py in the WindowsManifest.construct() method, be sure to add the dependency - # here. - # *NOTE:Mani - This is a crappy hack to have important dependencies for the viewer_manifest copy action - # be met. I'm looking forward to a source-code split-up project next year that will address this kind of thing. - # In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py - # and have the build deps get tracked *please* tell me about it. - # nat: https://cmake.org/cmake/help/v3.14/command/file.html - # "For example, the code - # file(STRINGS myfile.txt myfile) - # stores a list in the variable myfile in which each item is a line from the input file." - # And of course it's straightforward to read a text file in Python. - - set(COPY_INPUT_DEPENDENCIES - # The following commented dependencies are determined variably at build time. Can't do this here. - app_settings/message.xml - ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg - ${SHARED_LIB_STAGING_DIR}/openjp2.dll - ${SHARED_LIB_STAGING_DIR}/llwebrtc.dll - #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe - #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/libsndfile-1.dll - #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/vivoxoal.dll - ${AUTOBUILD_INSTALL_DIR}/ca-bundle.crt - ${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt - ${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt - ${viewer_APPSETTINGS_FILES} - SLPlugin - media_plugin_cef - media_plugin_libvlc - media_plugin_example - ) - - if (ADDRESS_SIZE EQUAL 64) - list(APPEND COPY_INPUT_DEPENDENCIES - ${SHARED_LIB_STAGING_DIR}/vivoxsdk_x64.dll - ${SHARED_LIB_STAGING_DIR}/ortp_x64.dll - ) - else (ADDRESS_SIZE EQUAL 64) - list(APPEND COPY_INPUT_DEPENDENCIES - ${SHARED_LIB_STAGING_DIR}/vivoxsdk.dll - ${SHARED_LIB_STAGING_DIR}/ortp.dll - ) - endif (ADDRESS_SIZE EQUAL 64) - - if (TARGET ll::discord_sdk) - list(APPEND COPY_INPUT_DEPENDENCIES - ${SHARED_LIB_STAGING_DIR}/discord_partner_sdk.dll - ) - endif () - - if (TARGET ll::openal) - list(APPEND COPY_INPUT_DEPENDENCIES - ${SHARED_LIB_STAGING_DIR}/OpenAL32.dll - ${SHARED_LIB_STAGING_DIR}/alut.dll - ) - endif () - - add_custom_command( - OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --actions=copy - --arch=${ARCH} - --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" - "--discord=${USE_DISCORD}" - "--openal=${USE_OPENAL}" - "--tracy=${USE_TRACY}" - --build=${CMAKE_CURRENT_BINARY_DIR} - --buildtype=$ - "--channel=${VIEWER_CHANNEL}" - --configuration=${CMAKE_CFG_INTDIR} - --dest=${CMAKE_CURRENT_BINARY_DIR}/$,$,> - --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} - --touch=${CMAKE_CURRENT_BINARY_DIR}/$,$,>/copy_touched.bat - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - stage_third_party_libs - llwebrtc - ${COPY_INPUT_DEPENDENCIES} - COMMENT "Performing viewer_manifest copy" - ) - - add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${CMAKE_CFG_INTDIR}/copy_touched.bat) - - add_dependencies(${VIEWER_BINARY_NAME} stage_third_party_libs llcommon llwebrtc copy_w_viewer_manifest) - - # Useful for remote debugging or profiling if set to target a shared drive. for example, brad sets it to "dist/secondlife" to deploy under - # the build tree (and then I share that directory) or "f:/dist/secondlife" to deploy to a network mounted drive (although this can be slow). - # this will also create an "unpacked" tarball at build-/newview/unpacked__7_1_11_.tar - set(LOCAL_DIST_DIR "" CACHE PATH "Path for 'local' unpacked copy of viewer distribution to be deployed to.") - set(product SecondLife-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}) - if(IS_DIRECTORY ${LOCAL_DIST_DIR}) - add_custom_command( - OUTPUT ${LOCAL_DIST_DIR}/.${product}.copy_touched - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - "--actions=\"copy package unpacked\"" - --arch=${ARCH} - --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" - "--discord=${USE_DISCORD}" - "--openal=${USE_OPENAL}" - "--tracy=${USE_TRACY}" - --build=${CMAKE_CURRENT_BINARY_DIR} - --buildtype=$,$,${CMAKE_BUILD_TYPE}> - "--channel=${VIEWER_CHANNEL}" - --configuration=$ - --dest=${LOCAL_DIST_DIR} - --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - --touch=${LOCAL_DIST_DIR}/.${product}.copy_touched - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - stage_third_party_libs - llwebrtc - ${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - ${COPY_INPUT_DEPENDENCIES} - ${VIEWER_BINARY_NAME} - COMMENT "Performing viewer_manifest local dist copy" - ) - - add_custom_target(copy_local_dist_viewer_manifest ALL DEPENDS ${LOCAL_DIST_DIR}/.${product}.copy_touched) - elseif (NOT LOCAL_DIST_DIR STREQUAL "") - message(FATAL_ERROR "LOCAL_DIST_DIR ${LOCAL_DIST_DIR} specified but is not valid target directory to copy viewer distribution into. Please create the directory and try again") - endif () # IS_DIRECTORY ${LOCAL_DIST_DIR} - - if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) - add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts) - endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) - - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin) - - # sets the 'working directory' for debugging from visual studio. - # Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865) - if (NOT UNATTENDED) - set_property( - TARGET ${VIEWER_BINARY_NAME} - PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" - ) - endif (NOT UNATTENDED) - - if (PACKAGE) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py - ${CMAKE_CURRENT_SOURCE_DIR}/.. - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CFG_INTDIR} - DEPENDS - lleventhost - ${EVENT_HOST_SCRIPTS} - ${CMAKE_CURRENT_SOURCE_DIR}/event_host_manifest.py - ) - - add_custom_command( - OUTPUT ${CMAKE_CFG_INTDIR}/touched.bat - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --arch=${ARCH} - --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" - "--discord=${USE_DISCORD}" - "--openal=${USE_OPENAL}" - "--tracy=${USE_TRACY}" - --build=${CMAKE_CURRENT_BINARY_DIR} - --buildtype=$ - "--channel=${VIEWER_CHANNEL}" - --configuration=${CMAKE_CFG_INTDIR} - --dest=${CMAKE_CURRENT_BINARY_DIR}/$,$,> - --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} - --touch=${CMAKE_CURRENT_BINARY_DIR}/$,$,>/touched.bat - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - DEPENDS - ${VIEWER_BINARY_NAME} - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - ${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - ${COPY_INPUT_DEPENDENCIES} - ) +check_message_template(${VIEWER_BINARY_NAME}) - add_custom_target(llpackage ALL DEPENDS - ${CMAKE_CFG_INTDIR}/touched.bat - ) - # temporarily disable packaging of event_host until hg subrepos get - # sorted out on the parabuild cluster... - #${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.xz) +target_include_directories(${VIEWER_BINARY_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) - endif (PACKAGE) -elseif (DARWIN) - set_target_properties(${VIEWER_BINARY_NAME} - PROPERTIES - RESOURCE SecondLife.xib - LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -Xlinker -dead_strip" - ) - if(HAVOK) - set_target_properties(${VIEWER_BINARY_NAME} - PROPERTIES - # arch specific flags for universal builds: https://stackoverflow.com/a/77942065 - XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=x86_64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_FULL -DLL_HAVOK=1" - XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=arm64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_STUB" - # only generate the .MAP file for llphysicsextensions_tpv on x86_64 - XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensions/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensions -Xlinker -map -Xlinker ${CMAKE_CURRENT_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP" - XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${CMAKE_BINARY_DIR}/llphysicsextensionsos/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensionsos" - ) - add_dependencies(${VIEWER_BINARY_NAME} llphysicsextensionsos) - elseif(HAVOK_TPV) - set_target_properties(${VIEWER_BINARY_NAME} - PROPERTIES - # arch specific flags for universal builds: https://stackoverflow.com/a/77942065 - XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=x86_64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_FULL -DLL_HAVOK=1" - XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=arm64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_STUB" - # only generate the .MAP file for llphysicsextensions_tpv on x86_64 - XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${ARCH_PREBUILT_DIRS}/ -lllphysicsextensions_tpv" - XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${CMAKE_BINARY_DIR}/llphysicsextensionsos/$,$,${CMAKE_CFG_INTDIR}>/ -lllphysicsextensionsos" - ) - add_dependencies(${VIEWER_BINARY_NAME} llphysicsextensionsos) - else() - target_link_libraries(${VIEWER_BINARY_NAME} llphysicsextensionsos) - endif() -else (WINDOWS) - if (HAVOK OR HAVOK_TPV) - # Linux - set_target_properties(${VIEWER_BINARY_NAME} - PROPERTIES - LINK_FLAGS_RELEASE "${LINK_FLAGS_RELEASE} -no-pie -Wl,--Map=${VIEWER_BINARY_NAME}.MAP" - ) - endif () -endif (WINDOWS) +target_precompile_headers(${VIEWER_BINARY_NAME} PRIVATE llviewerprecompiledheaders.h) # *NOTE: - this list is very sensitive to ordering, test carefully on all # platforms if you change the relative order of the entries here. @@ -2033,7 +1746,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} llmath llcorehttp llcommon - llmeshoptimizer lllogin llprimitive llappearance @@ -2042,132 +1754,72 @@ target_link_libraries(${VIEWER_BINARY_NAME} ll::ndof ll::tracy ll::openxr + ll::discord_sdk + ll::nvapi + ll::tinygltf + ll::tinyexr ) if (NOT DISABLE_WEBRTC) - target_link_libraries(${VIEWER_BINARY_NAME} llwebrtc ) -endif() - -if (USE_DISCORD) - target_link_libraries(${VIEWER_BINARY_NAME} ll::discord_sdk ) -endif () - -if( TARGET ll::intel_memops ) - target_link_libraries(${VIEWER_BINARY_NAME} ll::intel_memops ) + if(WINDOWS) + target_link_libraries(${VIEWER_BINARY_NAME} $<$:llwebrtc>) + else() + target_link_libraries(${VIEWER_BINARY_NAME} llwebrtc) + endif() endif() -if( TARGET ll::nvapi ) - target_link_libraries(${VIEWER_BINARY_NAME} ll::nvapi ) +# These are the generated targets that are copied for packaging that we do not directly link to +# We special case for windows due to targets incompatible with Debug builds +if (WINDOWS) + add_custom_target(copy_input_dependencies + DEPENDS + stage_third_party_libs + SLPlugin + $<$:$> + $ + $<$:$> + $ + ) +else() + add_custom_target(copy_input_dependencies + DEPENDS + stage_third_party_libs + SLPlugin + $ + $ + $ + $ + ) endif() - -if ( TARGET llconvexdecomposition ) - target_link_libraries(${VIEWER_BINARY_NAME} llconvexdecomposition ) -endif () +add_dependencies(${VIEWER_BINARY_NAME} copy_input_dependencies) set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Path to artwork files.") -message("Copying fonts") -file(GLOB FONT_FILE_GLOB_LIST - "${AUTOBUILD_INSTALL_DIR}/fonts/*" -) -file(COPY ${FONT_FILE_GLOB_LIST} DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/fonts") - -# Copy over the Emoji/shortcodes mapping XML files (and create dependency -# if they are changed, CMake will run again and copy over new versions) -message("Copying Emoji/shortcode mappings") -set(emoji_mapping_src_folder ${AUTOBUILD_INSTALL_DIR}/xui) -set(emoji_mapping_dst_folder ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui) - -# Note Turkey is missing from this set (not available in Emoji package yet) -set(country_codes "da;de;en;es;fr;it;ja;pl;pt;ru;zh") -foreach(elem ${country_codes}) - set(emoji_mapping_src_file - "${emoji_mapping_src_folder}/${elem}/emoji_characters.xml") - set(emoji_mapping_dst_file - "${emoji_mapping_dst_folder}/${elem}/emoji_characters.xml") - configure_file(${emoji_mapping_src_file} ${emoji_mapping_dst_file} COPYONLY) -endforeach() - -if (LINUX) - set(product SecondLife-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}) +set(PACKAGE ON CACHE BOOL + "Add a package target that builds an installer package.") - # These are the generated targets that are copied to package/ - set(COPY_INPUT_DEPENDENCIES - ${VIEWER_BINARY_NAME} - SLPlugin - media_plugin_cef - media_plugin_gstreamer10 - media_plugin_libvlc - media_plugin_example - llwebrtc - ) +set(VIEWER_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}$,/$,>) - add_custom_command( - OUTPUT ${product}.tar.xz - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --arch=${ARCH} - --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" - "--discord=${USE_DISCORD}" - "--openal=${USE_OPENAL}" - "--tracy=${USE_TRACY}" - --build=${CMAKE_CURRENT_BINARY_DIR} - --buildtype=${CMAKE_BUILD_TYPE} - "--channel=${VIEWER_CHANNEL}" - --configuration=${CMAKE_CFG_INTDIR} - --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged - --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} - --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - ${COPY_INPUT_DEPENDENCIES} +if (WINDOWS) + set_target_properties(${VIEWER_BINARY_NAME} + PROPERTIES + PDB_NAME ${VIEWER_BINARY_NAME} + PDB_OUTPUT_DIRECTORY ${SYMBOLS_STAGING_DIR} + RUNTIME_OUTPUT_NAME "SecondLifeViewer" + RUNTIME_OUTPUT_DIRECTORY ${VIEWER_STAGING_DIR} + ENABLE_EXPORTS OFF + VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" # Sets VS debugger working directory ) + target_compile_options(${VIEWER_BINARY_NAME} PRIVATE /bigobj) + if(HAVOK) + target_link_options(${VIEWER_BINARY_NAME} PRIVATE "/MAP\"secondlife-bin.MAP\"") # generate symbol map for havok_tpv scripts + endif() - if (PACKAGE) - endif (PACKAGE) - - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --actions=copy - --arch=${ARCH} - --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" - "--discord=${USE_DISCORD}" - "--openal=${USE_OPENAL}" - "--tracy=${USE_TRACY}" - --build=${CMAKE_CURRENT_BINARY_DIR} - --buildtype=${CMAKE_BUILD_TYPE} - "--channel=${VIEWER_CHANNEL}" - --configuration=${CMAKE_CFG_INTDIR} - --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged - --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - ${COPY_INPUT_DEPENDENCIES} - COMMENT "Performing viewer_manifest copy" - ) - - add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) - - if (PACKAGE) - add_custom_target(llpackage ALL DEPENDS ${product}.tar.xz) - # Make sure we don't run two instances of viewer_manifest.py at the same time. - add_dependencies(llpackage copy_l_viewer_manifest) - check_message_template(llpackage) - endif (PACKAGE) -endif (LINUX) - -if (DARWIN) + set(product SecondLife-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}) + set(MANIFEST_DEST_DIR ${VIEWER_STAGING_DIR}) + set(MANIFEST_PACKAGE_OUT_FILE "${VIEWER_BINARY_DIR}/touched.bat") +elseif(DARWIN) # These all get set with PROPERTIES. It's not that the property names are # magically known to CMake -- it's that these names are referenced in the # Info-SecondLife.plist file in the configure_file() directive below. @@ -2191,6 +1843,7 @@ if (DARWIN) ${VIEWER_BINARY_NAME} PROPERTIES OUTPUT_NAME "${product}" + RUNTIME_OUTPUT_DIRECTORY ${VIEWER_STAGING_DIR} # From Contents/MacOS/SecondLife, look in Contents/Frameworks BUILD_WITH_INSTALL_RPATH 1 INSTALL_RPATH "@executable_path/../Frameworks" @@ -2198,20 +1851,129 @@ if (DARWIN) XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "${MACOSX_BUNDLE_GUI_IDENTIFIER}" ) - set(VIEWER_APP_BUNDLE "${CMAKE_CURRENT_BINARY_DIR}/$,$,>/${product}.app") - set(VIEWER_APP_EXE "${VIEWER_APP_BUNDLE}/Contents/MacOS/${product}") + # Support generating nib and dsym for non-xcode generators + if(XCODE) + set_target_properties( + ${VIEWER_BINARY_NAME} + PROPERTIES + RESOURCE "SecondLife.xib" + ) + else() + if(USE_BUGSPLAT) + set(VIEWER_DEBUG_BUNDLE "${SYMBOLS_STAGING_DIR}/dSYMs/${product}.dSYM") + find_program(DSYMUTIL_PROGRAM dsymutil REQUIRED) + add_custom_command(TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${DSYMUTIL_PROGRAM} -o ${VIEWER_DEBUG_BUNDLE} $ + COMMENT "Generating SecondLife.dSYM") + endif() + + find_program(IBTOOL_PROGRAM ibtool REQUIRED) + add_custom_command(TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E env MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} ${IBTOOL_PROGRAM} --compile $/Contents/Resources/SecondLife.nib ${CMAKE_CURRENT_SOURCE_DIR}/SecondLife.xib + COMMENT "Compiling SecondLife.nib") + endif() - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" - "${VIEWER_APP_BUNDLE}/Contents/Info.plist" + if(HAVOK) + set_target_properties(${VIEWER_BINARY_NAME} + PROPERTIES + # arch specific flags for universal builds: https://stackoverflow.com/a/77942065 + XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=x86_64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_FULL -DLL_HAVOK=1" + XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=arm64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_STUB" + # only generate the .MAP file for llphysicsextensions_tpv on x86_64 + XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${CMAKE_CURRENT_BINARY_DIR}/llphysicsextensions/$,$,>/ -lllphysicsextensions -Xlinker -map -Xlinker ${VIEWER_BINARY_DIR}/${VIEWER_BINARY_NAME}.MAP" + XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${INDRA_BINARY_DIR}/llphysicsextensionsos/$,$,>/ -lllphysicsextensionsos" + ) + add_dependencies(${VIEWER_BINARY_NAME} llphysicsextensionsos) + elseif(HAVOK_TPV) + set_target_properties(${VIEWER_BINARY_NAME} + PROPERTIES + # arch specific flags for universal builds: https://stackoverflow.com/a/77942065 + XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=x86_64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_FULL -DLL_HAVOK=1" + XCODE_ATTRIBUTE_OTHER_CFLAGS[arch=arm64] "$(inherited) -DLLPHYSICSEXTENSIONS_USE_STUB" + # only generate the .MAP file for llphysicsextensions_tpv on x86_64 + XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=x86_64] "$(inherited) -L${ARCH_PREBUILT_DIRS}/ -lllphysicsextensions_tpv" + XCODE_ATTRIBUTE_OTHER_LDFLAGS[arch=arm64] "$(inherited) -L${INDRA_BINARY_DIR}/llphysicsextensionsos/$,$,>/ -lllphysicsextensionsos" + ) + add_dependencies(${VIEWER_BINARY_NAME} llphysicsextensionsos) + else() + target_link_libraries(${VIEWER_BINARY_NAME} llphysicsextensionsos) + endif() + + set(MANIFEST_DEST_DIR $) + set(MANIFEST_PACKAGE_OUT_FILE "${VIEWER_BINARY_DIR}/touched.bat") + if (ENABLE_SIGNING) + set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}") + else (ENABLE_SIGNING) + set(SIGNING_SETTING "") + endif (ENABLE_SIGNING) +elseif(LINUX) + set_target_properties( + ${VIEWER_BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${VIEWER_STAGING_DIR}/bin/ ) + if (HAVOK OR HAVOK_TPV) + # Linux + target_link_options(${VIEWER_BINARY_NAME} PRIVATE -no-pie "LINKER:--Map=${VIEWER_BINARY_NAME}.MAP") + endif () + + if(USE_BUGSPLAT) + find_program(OBJCOPY_PROGRAM objcopy REQUIRED) + set(DEBUG_BINARY_TARGET $) + set(DEBUG_FILE_NAME "${SYMBOLS_STAGING_DIR}/$.debug") + add_custom_command(TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${SYMBOLS_STAGING_DIR} + COMMAND ${OBJCOPY_PROGRAM} --only-keep-debug --compress-debug-sections=zlib ${DEBUG_BINARY_TARGET} ${DEBUG_FILE_NAME} + COMMAND ${OBJCOPY_PROGRAM} --strip-debug --strip-unneeded ${DEBUG_BINARY_TARGET} + COMMAND ${OBJCOPY_PROGRAM} --add-gnu-debuglink=${DEBUG_FILE_NAME} ${DEBUG_BINARY_TARGET} + COMMENT "Generating ${DEBUG_FILE_NAME}") + endif() + + set(product SecondLife-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}) + set(MANIFEST_DEST_DIR ${VIEWER_STAGING_DIR}) + set(MANIFEST_PACKAGE_OUT_FILE ${product}.tar.xz) +endif() + +# Viewer Manifest Copy +add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${Python3_EXECUTABLE} + ARGS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --actions=copy + --arch=${ARCH} + --artwork=${ARTWORK_DIR} + "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" + "--openal=${USE_OPENAL}" + "--tracy=${USE_TRACY}" + --build=${CMAKE_CURRENT_BINARY_DIR} + --buildtype=$ + --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} # Harmless to other platforms + "--channel=${VIEWER_CHANNEL}" + --configuration=$,$,> + --dest=${MANIFEST_DEST_DIR} + "--generator=${CMAKE_GENERATOR}" + --grid=${GRID} + --source=${CMAKE_CURRENT_SOURCE_DIR} + --touch=${VIEWER_BINARY_DIR}/copy_touched.bat + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --vcpkg_dir=${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET} + COMMENT "Performing viewer_manifest copy" + ) + +# Useful for remote debugging or profiling if set to target a shared drive. for example, brad sets it to "dist/secondlife" to deploy under +# the build tree (and then I share that directory) or "f:/dist/secondlife" to deploy to a network mounted drive (although this can be slow). +# this will also create an "unpacked" tarball at build-/newview/unpacked__7_1_11_.tar +set(LOCAL_DIST_DIR "" CACHE PATH "Path for 'local' unpacked copy of viewer distribution to be deployed to.") +if(IS_DIRECTORY ${LOCAL_DIST_DIR}) add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${PYTHON_EXECUTABLE} - ARGS + OUTPUT ${LOCAL_DIST_DIR}/.${product}.copy_touched + COMMAND ${Python3_EXECUTABLE} + ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --actions=copy + "--actions=\"copy package unpacked\"" --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" @@ -2220,61 +1982,75 @@ if (DARWIN) "--tracy=${USE_TRACY}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=$ - --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} + --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} # Harmless to other platforms "--channel=${VIEWER_CHANNEL}" - --configuration=${CMAKE_CFG_INTDIR} - --dest=${VIEWER_APP_BUNDLE} + --configuration=$,$,> + --dest=${LOCAL_DIST_DIR} + "--generator=${CMAKE_GENERATOR}" --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - ) - - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef) + --touch=${LOCAL_DIST_DIR}/.${product}.copy_touched + --vcpkg_dir=${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET} + ${SIGNING_SETTING} + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + ${VIEWER_BINARY_NAME} + COMMENT "Performing viewer_manifest local dist copy" + ) - if (ENABLE_SIGNING) - set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}") - else (ENABLE_SIGNING) - set(SIGNING_SETTING "") - endif (ENABLE_SIGNING) + add_custom_target(copy_local_dist_viewer_manifest ALL DEPENDS ${LOCAL_DIST_DIR}/.${product}.copy_touched) +elseif (NOT LOCAL_DIST_DIR STREQUAL "") + message(FATAL_ERROR "LOCAL_DIST_DIR ${LOCAL_DIST_DIR} specified but is not valid target directory to copy viewer distribution into. Please create the directory and try again") +endif () # IS_DIRECTORY ${LOCAL_DIST_DIR} - if (PACKAGE) - add_custom_target(llpackage ALL DEPENDS ${VIEWER_BINARY_NAME}) +if (PACKAGE) + add_custom_command( + OUTPUT ${MANIFEST_PACKAGE_OUT_FILE} + COMMAND ${Python3_EXECUTABLE} + ARGS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --arch=${ARCH} + --artwork=${ARTWORK_DIR} + "--bugsplat=${BUGSPLAT_DB}" + "--discord=${USE_DISCORD}" + "--openal=${USE_OPENAL}" + "--tracy=${USE_TRACY}" + --build=${CMAKE_CURRENT_BINARY_DIR} + --buildtype=$ + --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} # Harmless to other platforms + "--channel=${VIEWER_CHANNEL}" + --configuration=$,$,> + --dest=${MANIFEST_DEST_DIR} + "--generator=${CMAKE_GENERATOR}" + --grid=${GRID} + --source=${CMAKE_CURRENT_SOURCE_DIR} + --touch=${VIEWER_BINARY_DIR}/touched.bat # Intentionally left as touched.bat + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --vcpkg_dir=${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET} + ${SIGNING_SETTING} + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + ${VIEWER_BINARY_NAME} # Prevents two copies of manifest from running at the same time + COMMENT "Performing viewer_manifest package" + ) - add_custom_command( - TARGET llpackage POST_BUILD - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --arch=${ARCH} - --artwork=${ARTWORK_DIR} - "--bugsplat=${BUGSPLAT_DB}" - "--discord=${USE_DISCORD}" - "--openal=${USE_OPENAL}" - "--tracy=${USE_TRACY}" - --build=${CMAKE_CURRENT_BINARY_DIR} - --buildtype=$ - "--channel=${VIEWER_CHANNEL}" - --configuration=${CMAKE_CFG_INTDIR} - --dest=${VIEWER_APP_BUNDLE} - --grid=${GRID} - --source=${CMAKE_CURRENT_SOURCE_DIR} - --touch=${CMAKE_CURRENT_BINARY_DIR}/$,$,>/.${product}.bat - --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt - ${SIGNING_SETTING} - ) - endif (PACKAGE) -endif (DARWIN) + add_custom_target(llpackage ALL DEPENDS + ${MANIFEST_PACKAGE_OUT_FILE} + ) +endif (PACKAGE) if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) -if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE) +if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING)) if (USE_BUGSPLAT) # BugSplat symbol-file generation if (WINDOWS) set(VIEWER_APP_SYMBOLS_ARCHIVE "${SYMBOLS_STAGING_DIR}.sym.tar.xz") - set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES PDB_OUTPUT_DIRECTORY "${SYMBOLS_STAGING_DIR}") # Just pack up a tarball containing only the .pdb files for the # executables. @@ -2284,12 +2060,12 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE "cJf" "${VIEWER_CHANNEL}.sym.tar.xz" "${VIEWER_CHANNEL}" - DEPENDS "${VIEWER_BINARY_NAME}" llwebrtc + DEPENDS "${VIEWER_BINARY_NAME}" WORKING_DIRECTORY "${SYMBOLS_STAGING_DIR}/.." COMMENT "Packing viewer PDBs into ${VIEWER_APP_SYMBOLS_ARCHIVE}" ) add_custom_target(generate_symbols DEPENDS "${VIEWER_APP_SYMBOLS_ARCHIVE}") - add_dependencies(generate_symbols ${VIEWER_BINARY_NAME} llwebrtc) + add_dependencies(generate_symbols ${VIEWER_BINARY_NAME}) endif (WINDOWS) if (DARWIN) @@ -2308,7 +2084,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE "${VIEWER_APP_XCARCHIVE}" "${VIEWER_CHANNEL}" WORKING_DIRECTORY "${SYMBOLS_STAGING_DIR}/.." - DEPENDS "${VIEWER_BINARY_NAME}" llwebrtc + DEPENDS "${VIEWER_BINARY_NAME}" COMMENT "Generating ${VIEWER_APP_XCARCHIVE} for upload to BugSplat" ) add_custom_target(generate_symbols DEPENDS @@ -2323,10 +2099,21 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE endif (USE_BUGSPLAT) endif () -if (LL_TESTS) +add_custom_target(viewer) +add_dependencies(viewer ${VIEWER_BINARY_NAME}) + +elseif(BUILD_TESTING) + +# Create a dummy executable for test projects to generate against when viewer build is disabled +add_executable(${VIEWER_BINARY_NAME} cmake_dummy.cpp) +target_include_directories(${VIEWER_BINARY_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) + +endif(BUILD_VIEWER) + +if (BUILD_TESTING) # To add a viewer unit test, just add the test .cpp file below # This creates a separate test project per file listed. - include(LLAddBuildTest) + SET(viewer_TEST_SOURCE_FILES llagentaccess.cpp lldateutil.cpp @@ -2362,18 +2149,18 @@ if (LL_TESTS) llcommon llmessage llcorehttp - llxml - llui llplugin llappearance llprimitive lllogin ) + set(test_project ${VIEWER_BINARY_NAME}) + set_property(SOURCE ${viewer_TEST_SOURCE_FILES} PROPERTY - LL_TEST_ADDITIONAL_LIBRARIES + LL_TEST_ADDITIONAL_LIBRARIES ${test_libs} ) @@ -2398,16 +2185,19 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(cppfeatures "" "${test_libs}" + "${test_project}" ) LL_ADD_INTEGRATION_TEST(llsechandler_basic llsechandler_basic.cpp "${test_libs}" + "${test_project}" ) LL_ADD_INTEGRATION_TEST(llsecapi llsecapi.cpp "${test_libs}" + "${test_project}" ) set(llslurl_test_sources @@ -2418,6 +2208,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llslurl "${llslurl_test_sources}" "${test_libs}" + "${test_project}" ) set(llviewercontrollistener_test_sources @@ -2431,19 +2222,22 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llviewercontrollistener "${llviewercontrollistener_test_sources}" "${test_libs}" + "${test_project}" ) LL_ADD_INTEGRATION_TEST(llviewernetwork llviewernetwork.cpp "${test_libs}" + "${test_project}" ) LL_ADD_INTEGRATION_TEST(llviewerassetstats llviewerassetstats.cpp "${test_libs}" + "${test_project}" ) - LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llhttpretrypolicy "llhttpretrypolicy.cpp" "${test_libs}" "${test_project}") set(lltextureinfo_test_sources lltextureinfo.cpp @@ -2452,9 +2246,6 @@ if (LL_TESTS) ../llxml/llxmlparser.cpp ../llcommon/commoncontrol.cpp ) - LL_ADD_INTEGRATION_TEST(lltextureinfo "${lltextureinfo_test_sources}" "${test_libs}") - #LL_ADD_INTEGRATION_TEST(lltextureinfodetails "" "${test_libs}") test cases currently empty -endif (LL_TESTS) - -check_message_template(${VIEWER_BINARY_NAME}) - + LL_ADD_INTEGRATION_TEST(lltextureinfo "${lltextureinfo_test_sources}" "${test_libs}" "${test_project}") + #LL_ADD_INTEGRATION_TEST(lltextureinfodetails "" "${test_libs}" "${test_project}") test cases currently empty +endif () diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index 09b0e1ec1bf..cfe9d991c5a 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -11,7 +11,7 @@ CFBundleIconFile ${MACOSX_BUNDLE_ICON_FILE} CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) + ${MACOSX_BUNDLE_GUI_IDENTIFIER} CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString diff --git a/indra/newview/SecondLife.xib b/indra/newview/SecondLife.xib index 781a3906731..8393d7b75b7 100644 --- a/indra/newview/SecondLife.xib +++ b/indra/newview/SecondLife.xib @@ -1,8 +1,8 @@ - + - - + + diff --git a/indra/newview/ViewerInstall.cmake b/indra/newview/ViewerInstall.cmake index ac2247c8156..7e2867ce014 100644 --- a/indra/newview/ViewerInstall.cmake +++ b/indra/newview/ViewerInstall.cmake @@ -8,7 +8,7 @@ install(DIRECTORY skins app_settings linux_tools ) find_file(IS_ARTWORK_PRESENT NAMES have_artwork_bundle.marker - PATHS ${VIEWER_DIR}/newview/res) + PATHS ${INDRA_SOURCE_DIR}/newview/res) if (IS_ARTWORK_PRESENT) install(DIRECTORY res res-sdl character diff --git a/indra/newview/cmake_dummy.cpp b/indra/newview/cmake_dummy.cpp new file mode 100644 index 00000000000..d8611fa21c4 --- /dev/null +++ b/indra/newview/cmake_dummy.cpp @@ -0,0 +1,30 @@ +/** + * @file cmake_dummy.cpp + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Dummy main function for empty project + int main() + { + return 0; + } diff --git a/indra/newview/gltf/llgltfloader.cpp b/indra/newview/gltf/llgltfloader.cpp index 66aa29d86b3..1a949175e9e 100644 --- a/indra/newview/gltf/llgltfloader.cpp +++ b/indra/newview/gltf/llgltfloader.cpp @@ -25,7 +25,8 @@ */ #include "llgltfloader.h" -#include "meshoptimizer.h" + +#include #include // Import & define single-header gltf import/export lib @@ -45,7 +46,7 @@ // Additionally, disable inclusion of STB header files entirely with // TINYGLTF_NO_INCLUDE_STB_IMAGE // TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE -#include "tinygltf/tiny_gltf.h" +#include // TODO: includes inherited from dae loader. Validate / prune diff --git a/indra/newview/gltf/llgltfloader.h b/indra/newview/gltf/llgltfloader.h index a847e567a62..58140c0da6b 100644 --- a/indra/newview/gltf/llgltfloader.h +++ b/indra/newview/gltf/llgltfloader.h @@ -27,7 +27,7 @@ #ifndef LL_LLGLTFLoader_H #define LL_LLGLTFLoader_H -#include "tinygltf/tiny_gltf.h" +#include #include "asset.h" diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index 81caff8ab2e..388a6eee010 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -32,7 +32,7 @@ #include "mikktspace/mikktspace.hh" -#include "meshoptimizer/meshoptimizer.h" +#include using namespace LL::GLTF; diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index 7e7a9a5e49c..0bca9b30ad6 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -17,7 +17,7 @@ export mesa_glthread=true ## in the bin directory will be stripped: you should replace it with ## an unstripped binary before you run. #export LL_WRAPPER='gdb --args' -#export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp --suppressions=secondlife-i686.supp' +#export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp' #export ASAN_OPTIONS="halt_on_error=0 detect_leaks=1 symbolize=1" #export UBSAN_OPTIONS="print_stacktrace=1 print_summary=1 halt_on_error=0" @@ -56,7 +56,7 @@ done # Don't quote $LL_WRAPPER because, if empty, it should simply vanish from the # command line. But DO quote "${ARGS[@]}": preserve separate args as # individually quoted. -$LL_WRAPPER bin/do-not-directly-run-secondlife-bin "${ARGS[@]}" +$LL_WRAPPER bin/secondlife-bin "${ARGS[@]}" LL_RUN_ERR=$? # Handle any resulting errors diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index 23a4effd87c..9f6abd0ffb1 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -28,8 +28,6 @@ #if defined(LL_BUGSPLAT) #include #include -@import CrashReporter; -@import HockeySDK; @import BugSplatMac; // derived from BugsplatMac's BugsplatTester/AppDelegate.m @interface LLAppDelegate () diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ab4a0fbc28a..930db393283 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2987,6 +2987,8 @@ bool LLAppViewer::initConfiguration() gWindowTitle = LLTrans::getString("APP_NAME"); #if LL_DEBUG gWindowTitle += std::string(" [DEBUG]"); +#elif LL_RELEASE_WITH_DEBUG_INFO + gWindowTitle += std::string(" [ASSERT]"); #endif if (!gArgs.empty()) { diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index b074c40c175..91e274a93fd 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -409,7 +409,7 @@ std::string LLAppViewerMacOSX::generateSerialNumber() // JC: Sample code from http://developer.apple.com/technotes/tn/tn1103.html CFStringRef serialNumber = NULL; - io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, + io_service_t platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice")); if (platformExpert) { diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index d6ea462b890..b89c968674c 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -26,9 +26,6 @@ #include "llviewerprecompiledheaders.h" -#ifdef INCLUDE_VLD -#include "vld.h" -#endif #include "llwin32headers.h" #include "llwindowwin32.h" // *FIX: for setting gIconResource. @@ -76,7 +73,7 @@ // Bugsplat (http://bugsplat.com) crash reporting tool #ifdef LL_BUGSPLAT -#include "BugSplat.h" +#include "bugsplat/BugSplat.h" #include "boost/json.hpp" // Boost.Json #include "llagent.h" // for agent location #include "llstartup.h" @@ -437,7 +434,7 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, LLWindowWin32::setDPIAwareness(); -#if WINDOWS_CRT_MEM_CHECKS && !INCLUDE_VLD +#if WINDOWS_CRT_MEM_CHECKS _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); // dump memory leaks on exit #elif 0 // Experimental - enable the low fragmentation heap diff --git a/indra/newview/llavatarrendernotifier.cpp b/indra/newview/llavatarrendernotifier.cpp index b40bcadabfb..983e6d85d8d 100644 --- a/indra/newview/llavatarrendernotifier.cpp +++ b/indra/newview/llavatarrendernotifier.cpp @@ -48,7 +48,7 @@ #include "llavatarrendernotifier.h" // when change exceeds this ration, notification is shown -static const F32 RENDER_ALLOWED_CHANGE_PCT = 0.1; +static const F32 RENDER_ALLOWED_CHANGE_PCT = 0.1f; // wait seconds before processing over limit updates after last complexity change static const U32 OVER_LIMIT_UPDATE_DELAY = 70; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index cce6eeb19dd..61cdb26d78c 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -1014,7 +1014,7 @@ void LLFastTimerView::drawLineGraph() LLLocalClipRect clip(mGraphRect); //normalize based on last frame's maximum - static F32Seconds max_time(0.000001); + static F32Seconds max_time(0.000001f); static U32 max_calls = 0; static F32 alpha_interp = 0.f; diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index 7262d18483e..2b45ebfb1c9 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -29,6 +29,9 @@ #include #include "llfilepicker_mac.h" +// For setAllowedFileTypes deprecation +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + NSOpenPanel *init_panel(const std::vector* allowed_types, unsigned int flags) { int i; diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 8897ad55e0e..faa5e4d26b2 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -696,7 +696,6 @@ void LLVolumeImplFlexible::doFlexibleUpdate() LLVector4(z_axis, 0.f), LLVector4(delta_pos, 1.f)); - LL_CHECK_MEMORY for (i=0; i<=num_render_sections; ++i) { new_point = &path->mPath[i]; @@ -715,7 +714,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate() new_point->mScale.set(newSection[i].mScale.mV[0], newSection[i].mScale.mV[1], 0,1); new_point->mTexT = ((F32)i)/(num_render_sections); } - LL_CHECK_MEMORY + mLastSegmentRotation = parentSegmentRotation; } diff --git a/indra/newview/llfloaterregionrestarting.cpp b/indra/newview/llfloaterregionrestarting.cpp index 6b795e5bc51..7fda94b01e4 100644 --- a/indra/newview/llfloaterregionrestarting.cpp +++ b/indra/newview/llfloaterregionrestarting.cpp @@ -100,10 +100,10 @@ void LLFloaterRegionRestarting::draw() { LLFloater::draw(); - const F32 SHAKE_INTERVAL = 0.025; - const F32 SHAKE_TOTAL_DURATION = 1.8; // the length of the default alert tone for this - const F32 SHAKE_INITIAL_MAGNITUDE = 1.5; - const F32 SHAKE_HORIZONTAL_BIAS = 0.25; + const F32 SHAKE_INTERVAL = 0.025f; + const F32 SHAKE_TOTAL_DURATION = 1.8f; // the length of the default alert tone for this + const F32 SHAKE_INITIAL_MAGNITUDE = 1.5f; + const F32 SHAKE_HORIZONTAL_BIAS = 0.25f; F32 time_shaking; if(SHAKE_START == sShakeState) diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index b7844197807..deedabc8a25 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -44,7 +44,7 @@ #include "llvocache.h" #include "llworld.h" -#include "tinygltf/tiny_gltf.h" +#include #include #include diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index e9d68723d37..b1414ccc4a7 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -63,7 +63,7 @@ const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login const F32 LOGIN_SRV_TIMEOUT_MIN = 10; const F32 LOGIN_SRV_TIMEOUT_MAX = 180; -const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9; // make DNS wait shorter then retry time +const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9f; // make DNS wait shorter then retry time class LLLoginInstance::Disposable { public: diff --git a/indra/newview/llmachineid.cpp b/indra/newview/llmachineid.cpp index 0a90cf0699e..eed650fcce8 100644 --- a/indra/newview/llmachineid.cpp +++ b/indra/newview/llmachineid.cpp @@ -350,7 +350,7 @@ bool LLWMIMethods::getGenericSerialNumber(const BSTR &select, const LPCWSTR &var bool getSerialNumber(unsigned char *unique_id, size_t len) { CFStringRef serial_cf_str = NULL; - io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, + io_service_t platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice")); if (platformExpert) { diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 4e14f416e9b..1cce55a5af1 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -61,7 +61,7 @@ #include "llviewertexturelist.h" #include "llfloaterperms.h" -#include "tinygltf/tiny_gltf.h" +#include #include "lltinygltfhelper.h" #include diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index bc9ca466728..8592268ae95 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -525,7 +525,7 @@ void LLModelPreview::rebuildUploadData() { LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(LLMatrix4(high_lod_model->mSkinInfo.mBindShapeMatrix)); LLQuaternion identity; - if (!bind_rot.isEqualEps(identity, 0.01)) + if (!bind_rot.isEqualEps(identity, 0.01f)) { // Bind shape matrix is not in standard X-forward orientation. // Might be good idea to only show this once. It can be spammy. diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 92ac2d1fafa..aa25c79f97c 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -38,15 +38,6 @@ class LLJoint; class LLVOAvatar; class LLTextBox; class LLVertexBuffer; -class DAE; -class daeElement; -class domProfile_COMMON; -class domInstance_geometry; -class domNode; -class domTranslate; -class domController; -class domSkin; -class domMesh; // const strings needed by classes that use model preivew static const std::string lod_name[NUM_LOD + 1] = diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index b65fd61fccf..6ec4fdf9f3d 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -35,6 +35,11 @@ class LLViewerObject; class LLMessageSystem; class LLMuteListObserver; +#if LL_GNUC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfree-nonheap-object" // False positive in LLMuteList::compare_by_name +#endif + // An entry in the mute list. class LLMute { @@ -213,5 +218,8 @@ class LLRenderMuteList : public LLSingleton observer_set_t mObservers; }; +#if LL_GNUC +#pragma GCC diagnostic pop +#endif #endif //LL_MUTELIST_H diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 8bcb6e9ec37..59e47c6a65c 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1367,7 +1367,7 @@ void LLPanelEditWearable::toggleTypeSpecificControls(LLWearableType::EType type) void LLPanelEditWearable::updateTypeSpecificControls(LLWearableType::EType type) { const F32 ONE_METER = 1.0; - const F32 ONE_FOOT = 0.3048 * ONE_METER; // in meters + const F32 ONE_FOOT = 0.3048f * ONE_METER; // in meters // Update controls specific to shape editing panel. if (type == LLWearableType::WT_SHAPE) { diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index c6fa64753c3..4b9ff1fabb0 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -46,9 +46,9 @@ #pragma warning (disable : 4702) // compiler complains unreachable code #endif #define TINYEXR_USE_MINIZ 0 -#include "zlib.h" +#include #define TINYEXR_IMPLEMENTATION -#include "tinyexr/tinyexr.h" +#include #if LL_WINDOWS #pragma warning (pop) #endif diff --git a/indra/newview/llsecapi.cpp b/indra/newview/llsecapi.cpp index 85c7451d8a4..645dc69ef0d 100644 --- a/indra/newview/llsecapi.cpp +++ b/indra/newview/llsecapi.cpp @@ -33,21 +33,33 @@ #include "stringize.h" #include #include +#include #include std::map > gHandlerMap; LLPointer gSecAPIHandler; +OSSL_PROVIDER* gOSSLLegacyProvider = nullptr; void initializeSecHandler() { +#if LL_WINDOWS + // We dynamiclly link openssl on windows + OSSL_PROVIDER_set_default_search_path(nullptr, gDirUtilp->getExecutableDir().c_str()); +#endif + /* Load Legacy provider into the default (nullptr) library context */ + gOSSLLegacyProvider = OSSL_PROVIDER_try_load(nullptr, "legacy", 1); + if (!gOSSLLegacyProvider) + { + LL_WARNS() << "Failed to load OpenSSL legacy provider, expect problems." << LL_ENDL; + } + ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); gHandlerMap[BASIC_SECHANDLER] = new LLSecAPIBasicHandler(); - // Currently, we only have the Basic handler, so we can point the main sechandler // pointer to the basic handler. Later, we'll create a wrapper handler that // selects the appropriate sechandler as needed, for instance choosing the @@ -64,7 +76,7 @@ void initializeSecHandler() { handler->init(); } - catch (LLProtectedDataException& e) + catch (const LLProtectedDataException& e) { exception_msg = e.what(); } @@ -78,9 +90,15 @@ void initializeSecHandler() void clearSecHandler() { - gSecAPIHandler = NULL; + gSecAPIHandler = nullptr; gHandlerMap.clear(); + if (gOSSLLegacyProvider) + { + OSSL_PROVIDER_unload(gOSSLLegacyProvider); + gOSSLLegacyProvider = nullptr; + } } + // start using a given security api handler. If the string is empty // the default is used LLPointer getSecHandler(const std::string& handler_type) diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 223fc2a8f5e..8606f97fe04 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -186,7 +186,7 @@ void LLSkinningUtil::initSkinningMatrixPalette( void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) { #if DEBUG_SKINNING - const S32 max_joints = skin->mJointNames.size(); + const S32 max_joints = narrow(skin->mJointNames.size()); for (U32 j=0; j 0) + { + mReadData = (U8*)ll_aligned_malloc_16(mDataSize); + } if (mReadData) { diff --git a/indra/newview/lltinygltfhelper.h b/indra/newview/lltinygltfhelper.h index a259609404d..73cdd6130d7 100644 --- a/indra/newview/lltinygltfhelper.h +++ b/indra/newview/lltinygltfhelper.h @@ -29,7 +29,7 @@ #include "llgltfmaterial.h" #include "llgltfmateriallist.h" #include "llpointer.h" -#include "tinygltf/tiny_gltf.h" +#include class LLImageRaw; class LLViewerFetchedTexture; diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 0fb18c28aeb..046b5c05b8d 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -169,7 +169,9 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() const std::string LLVersionInfo::getBuildConfig() const { -#if LL_DEBUG +#if LL_OPTDEBUG + return "OptDebug"; +#elif LL_DEBUG return "Debug"; #elif LL_RELEASE_WITH_DEBUG_INFO return "RelWithDebInfo"; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 30b2dafb8f7..bf80468ea4f 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -724,7 +724,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg) static LLCachedControl inworld_audio_enabled(gSavedSettings, "AudioStreamingMusic", true); static LLCachedControl max_normal(gSavedSettings, "PluginInstancesNormal", 2); static LLCachedControl max_low(gSavedSettings, "PluginInstancesLow", 4); - static LLCachedControl max_cpu(gSavedSettings, "PluginInstancesCPULimit", 0.9); + static LLCachedControl max_cpu(gSavedSettings, "PluginInstancesCPULimit", 0.9f); // Setting max_cpu to 0.0 disables CPU usage checking. bool check_cpu_usage = (max_cpu != 0.0f); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 5799e23ca5f..6d0af4423f7 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -26,10 +26,6 @@ #include "llviewerprecompiledheaders.h" -#ifdef INCLUDE_VLD -#include "vld.h" -#endif - #include "llviewermenu.h" // linden library includes @@ -239,7 +235,6 @@ void handle_buy_contents(LLSaleInfo sale_info); void near_sit_down_point(bool success, void*); // Debug menu -void handle_visual_leak_detector_toggle(); void handle_rebake_textures(); bool check_admin_override(); void handle_admin_override_toggle(); @@ -2537,15 +2532,6 @@ class LLAdvancedToggleViewAdminOptions : public view_listener_t } }; -class LLAdvancedToggleVisualLeakDetector : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_visual_leak_detector_toggle(); - return true; - } -}; - class LLAdvancedCheckViewAdminOptions : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -4341,35 +4327,6 @@ void handle_admin_override_toggle() show_debug_menus(); } -void handle_visual_leak_detector_toggle() -{ - static bool vld_enabled = false; - - if ( vld_enabled ) - { -#ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) -#ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDDisable(); -#endif // _DEBUG -#endif // INCLUDE_VLD - vld_enabled = false; - } - else - { -#ifdef INCLUDE_VLD - // only works for debug builds (hard coded into vld.h) - #ifdef _DEBUG - // start with Visual Leak Detector turned off - VLDEnable(); - #endif // _DEBUG -#endif // INCLUDE_VLD - - vld_enabled = true; - }; -} - void handle_god_mode() { gAgent.requestEnterGodMode(); @@ -10089,7 +10046,6 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleVisualLeakDetector(), "Advanced.ToggleVisualLeakDetector"); view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 34e5cc9de82..117bdd68672 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -69,11 +69,7 @@ #include "u64.h" #include "llviewertexturelist.h" #include "lldatapacker.h" -#ifdef LL_USESYSTEMLIBS #include -#else -#include "zlib-ng/zlib.h" -#endif #include "object_flags.h" #include "llappviewer.h" diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index a183d7c8de8..ec8402b6119 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -41,7 +41,7 @@ LLViewerStatsRecorder::LLViewerStatsRecorder() : mLastSnapshotTime(0.0), mEnableStatsRecording(false), mEnableStatsLogging(false), - mInterval(0.2), + mInterval(0.2f), mMaxDuration(300.f), mSkipSaveIfZeros(false) { diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 14de3461c95..b0f4f21a097 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6311,11 +6311,11 @@ void LLVOAvatar::addDebugText(const std::string& text) // virtual std::string LLVOAvatar::getDebugName() const { -#if LL_RELEASE_WITH_DEBUG_INFO +#if LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO return getFullname(); #else return getID().asString(); -#endif // LL_RELEASE_WITH_DEBUG_INFO +#endif // LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO } //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 507154a2a3e..7d368d0aa2a 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -26,9 +26,7 @@ #include "llvoiceclient.h" #include "llvoicevivox.h" -#ifndef DISABLE_WEBRTC #include "llvoicewebrtc.h" -#endif #include "llviewernetwork.h" #include "llviewercontrol.h" #include "llcommandhandler.h" diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e58a6577f15..8f5ee9f2e3e 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -36,11 +36,7 @@ #include "llbufferstream.h" #include "llfile.h" #include "llmenugl.h" -#ifdef LL_USESYSTEMLIBS -# include "expat.h" -#else -# include "expat/expat.h" -#endif +#include #include "llcallbacklist.h" #include "llviewerregion.h" #include "llviewernetwork.h" // for gGridChoice diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 3167705528e..7973ed9aa90 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -41,11 +41,7 @@ class LLVivoxProtocolParser; #include "llcoros.h" #include -#ifdef LL_USESYSTEMLIBS -# include "expat.h" -#else -# include "expat/expat.h" -#endif +#include #include "llvoiceclient.h" class LLAvatarName; diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 481f9e35228..2c4d0c14de9 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -23,6 +23,9 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ + +#ifndef DISABLE_WEBRTC + #include #include "llvoicewebrtc.h" @@ -34,11 +37,7 @@ #include "llbufferstream.h" #include "llfile.h" #include "llmenugl.h" -#ifdef LL_USESYSTEMLIBS -# include "expat.h" -#else -# include "expat/expat.h" -#endif +#include #include "llcallbacklist.h" #include "llviewernetwork.h" // for gGridChoice #include "llbase64.h" @@ -92,7 +91,7 @@ namespace { const uint32_t MUTE_FADE_DELAY_MS = 500; // 20ms fade followed by 480ms silence gets rid of the click just after unmuting. // This is because the buffers and processing is cleared by the silence. - const F32 SPEAKING_AUDIO_LEVEL = 0.30; + const F32 SPEAKING_AUDIO_LEVEL = 0.30f; const uint32_t PEER_GAIN_CONVERSION_FACTOR = 220; @@ -3383,3 +3382,5 @@ void LLVoiceWebRTCAdHocConnection::requestVoiceConnection() } mOutstandingRequests--; } + +#endif // DISABLE_WEBRTC diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h index 2ce575852ab..b7914bb406d 100644 --- a/indra/newview/llvoicewebrtc.h +++ b/indra/newview/llvoicewebrtc.h @@ -26,6 +26,8 @@ #ifndef LL_VOICE_WEBRTC_H #define LL_VOICE_WEBRTC_H +#ifndef DISABLE_WEBRTC + class LLWebRTCProtocolParser; #include "lliopipe.h" @@ -43,11 +45,7 @@ class LLWebRTCProtocolParser; #include #include "boost/json.hpp" -#ifdef LL_USESYSTEMLIBS -# include "expat.h" -#else -# include "expat/expat.h" -#endif +#include #include "llvoiceclient.h" // WebRTC Includes @@ -756,5 +754,7 @@ class LLVoiceWebRTCAdHocConnection : public LLVoiceWebRTCConnection #define VOICE_ELAPSED LLVoiceTimer(__FUNCTION__); +#endif // DISABLE_WEBRTC + #endif //LL_WebRTC_VOICE_CLIENT_H diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 3b72e512da4..385140492b0 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -5333,25 +5333,11 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) break; case LLDrawPool::POOL_TREE: - #ifdef _DEBUG - { - bool found = mTreePools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mTreePools.erase( (uintptr_t)poolp->getTexture() ); - #endif + mTreePools.erase( (uintptr_t)poolp->getTexture() ); break; case LLDrawPool::POOL_TERRAIN: - #ifdef _DEBUG - { - bool found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); - llassert( found ); - } - #else - mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); - #endif + mTerrainPools.erase( (uintptr_t)poolp->getTexture() ); break; case LLDrawPool::POOL_BUMP: diff --git a/indra/newview/secondlife-i686.supp b/indra/newview/secondlife-i686.supp deleted file mode 100644 index 863c8364ab8..00000000000 --- a/indra/newview/secondlife-i686.supp +++ /dev/null @@ -1,193 +0,0 @@ -# @file secondlife-i686.supp -# @brief Valgrind suppressions for Linux i686 viewer. -# -# $LicenseInfo:firstyear=2000&license=viewerlgpl$ -# Second Life Viewer Source Code -# Copyright (C) 2010, Linden Research, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; -# version 2.1 of the License only. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -# $/LicenseInfo$ -# -# This is a Valgrind suppression file for use on the viewer. -# -# Hints for most successful use of valgrind: -# -# - If your distro comes with library packages that contain debug info -# (Fedora calls these debuginfo packages), install them. -# - Inside the SConstruct script, disable linking against tcmalloc. -# Valgrind and tcmalloc don't get along. -# - Delete the copy of libstdc++.so.6 that is bundled with the viewer -# (if you have one), so that the viewer will use the system's -# libstdc++. -# - After you build the viewer, replace the stripped -# do-not-directly-run-secondlife-bin binary with an unstripped copy. - -# Mozilla noise. - -{ - Cond:mozilla-runtime/*.so - Memcheck:Cond - obj:*/mozilla-runtime-*/*.so -} - -{ - Value4:mozilla-runtime/*.so - Memcheck:Value4 - obj:*/mozilla-runtime-*/*.so -} - -{ - Cond:mozilla-runtime/*/*.so - Memcheck:Cond - obj:*/mozilla-runtime-*/*/*.so -} - -{ - Value4:mozilla-runtime/*/*.so - Memcheck:Value4 - obj:*/mozilla-runtime-*/*/*.so -} - -{ - Cond:mozilla-runtime/libmozjs.so - Memcheck:Cond - obj:*/libmozjs.so -} - -{ - Cond:mozilla-runtime/libxul - Memcheck:Cond - obj:*/libxul.so -} - -{ - Value4:mozilla-runtime/libxul - Memcheck:Value4 - obj:*/libxul.so -} - -# libcurl badness. - -{ - Cond:libcurl/inflate/Curl_unencode_gzip_write - Memcheck:Cond - fun:inflate - fun:inflate_stream - fun:Curl_unencode_gzip_write -} -{ - Cond:libcurl/ares_mkquery/Curl_getaddrinfo - Memcheck:Cond - fun:ares_mkquery - fun:ares_query - fun:ares_search - fun:next_lookup - fun:Curl_getaddrinfo -} - -# libdl business. - -{ - Cond:libdl/_dl_relocate_object - Memcheck:Cond - fun:_dl_relocate_object -} - -# X11 fun. - -{ - Param:X11/_X11TransSocketWritev/writev/vector - Memcheck:Param - writev(vector[...]) - fun:writev - fun:_X11TransSocketWritev -} - -{ - Param:X11/_X11TransWrite/write/buf - Memcheck:Param - write(buf) - obj:/lib/libc-2.6.so - fun:_X11TransWrite -} - -# OpenSSL stuff. - -{ - Value4:libcrypto - Memcheck:Value4 - obj:*/libcrypto.so.0.9* -} - -{ - Cond:libcrypto - Memcheck:Cond - obj:*/libcrypto.so.0.9* -} - -{ - Value4:libssl - Memcheck:Value4 - obj:*/libssl.so.0.9* -} - -{ - Cond:libcrypto - Memcheck:Cond - obj:*/libssl.so.0.9* -} - -# NVIDIA driver brokenness. - -{ - Addr4:NVIDIA/libGL - Memcheck:Addr4 - obj:/usr/lib/libGL.so.1.0.* -} - -{ - Value4:NVIDIA/libGL - Memcheck:Value4 - obj:/usr/lib/libGL.so.1.0.* -} - -{ - Cond:NVIDIA/libGL - Memcheck:Cond - obj:/usr/lib/libGL.so.1.0.* -} - -{ - Value4:NVIDIA/libGLcore - Memcheck:Value4 - obj:/usr/lib/libGLcore.so.1.0.* -} - -{ - Cond:NVIDIA/libGLcore - Memcheck:Cond - obj:/usr/lib/libGLcore.so.1.0.* -} - -{ - Param:NVIDIA/ioctl - Memcheck:Param - ioctl(generic) - fun:ioctl - fun:_nv000130gl -} - diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index ba43e80edab..7c3fcfe832a 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -4311,13 +4311,6 @@ function="World.EnvPreset" - - - - #include #include +#include #include "../llmachineid.h" #define ensure_throws(str, exc_type, cert, func, ...) \ @@ -634,10 +635,24 @@ namespace tut { X509 *mX509TestCert, *mX509RootCert, *mX509IntermediateCert, *mX509ChildCert; LLSD mValidationDate; + OSSL_PROVIDER* mOSSLLegacyProvider = nullptr; sechandler_basic_test() { LLMachineID::init(); + +#if LL_WINDOWS + // We dynamiclly link openssl on windows + OSSL_PROVIDER_set_default_search_path(nullptr, gDirUtilp->getExecutableDir().c_str()); +#endif + + /* Load Legacy provider into the default (nullptr) library context */ + mOSSLLegacyProvider = OSSL_PROVIDER_try_load(nullptr, "legacy", 1); + if (!mOSSLLegacyProvider) + { + LL_WARNS() << "Failed to load OpenSSL legacy provider, expect problems." << LL_ENDL; + } + OpenSSL_add_all_algorithms(); OpenSSL_add_all_ciphers(); OpenSSL_add_all_digests(); @@ -680,6 +695,10 @@ namespace tut X509_free(mX509RootCert); X509_free(mX509IntermediateCert); X509_free(mX509ChildCert); + if (mOSSLLegacyProvider) + { + OSSL_PROVIDER_unload(mOSSLLegacyProvider); + } } }; diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index bcabc07c5af..b8d576f8943 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -62,7 +62,9 @@ def is_packaging_viewer(self): def construct(self): super(ViewerManifest, self).construct() - self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg") + self.path(src=os.path.join(self.args['source'], "..", "..", "scripts", "messages", "message_template.msg"), dst="app_settings/message_template.msg") + + os.environ["XZ_DEFAULTS"] = "-T0" if self.is_packaging_viewer(): with self.prefix(src_dst="app_settings"): @@ -88,12 +90,12 @@ def construct(self): self.path("filters") # ... and the included spell checking dictionaries - pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - with self.prefix(src=pkgdir): + dicts_dir = os.path.join(self.args['vcpkg_dir'], 'share', 'secondlife-dictionaries') + with self.prefix(src=dicts_dir): self.path("dictionaries") # include the extracted packages information (see BuildPackagesInfo.cmake) - self.path(src=os.path.join(self.args['build'],"packages-info.txt"), dst="packages-info.txt") + # self.path(src=os.path.join(self.args['build'],"packages-info.txt"), dst="packages-info.txt") # CHOP-955: If we have "sourceid" or "viewer_channel" in the # build process environment, generate it into # settings_install.xml. @@ -140,7 +142,8 @@ def construct(self): self.path("*.tga") # Include our fonts - with self.prefix(src="../packages/fonts",src_dst="fonts"): + fonts_dir = os.path.join(self.args['vcpkg_dir'], 'share', 'secondlife-fonts', 'fonts') + with self.prefix(src=fonts_dir,src_dst="fonts"): self.path("*.ttf") self.path("*.txt") @@ -451,67 +454,10 @@ def finish_build_data_dict(self, build_data_dict): build_data_dict['AppName'] = self.app_name() return build_data_dict - def test_msvcrt_and_copy_action(self, src, dst): - # This is used to test a dll manifest. - # It is used as a temporary override during the construct method - from test_win32_manifest import test_assembly_binding - # TODO: This is redundant with LLManifest.copy_action(). Why aren't we - # calling copy_action() in conjunction with test_assembly_binding()? - if src and (os.path.exists(src) or os.path.islink(src)): - # ensure that destination path exists - self.cmakedirs(os.path.dirname(dst)) - self.created_paths.append(dst) - if not os.path.isdir(src): - if(self.args['buildtype'].lower() == 'debug'): - test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "8.0.50727.4053") - else: - test_assembly_binding(src, "Microsoft.VC80.CRT", "8.0.50727.4053") - self.ccopy(src,dst) - else: - raise Exception("Directories are not supported by test_CRT_and_copy_action()") - else: - print("Doesn't exist:", src) - - def test_for_no_msvcrt_manifest_and_copy_action(self, src, dst): - # This is used to test that no manifest for the msvcrt exists. - # It is used as a temporary override during the construct method - from test_win32_manifest import test_assembly_binding - from test_win32_manifest import NoManifestException, NoMatchingAssemblyException - # TODO: This is redundant with LLManifest.copy_action(). Why aren't we - # calling copy_action() in conjunction with test_assembly_binding()? - if src and (os.path.exists(src) or os.path.islink(src)): - # ensure that destination path exists - self.cmakedirs(os.path.dirname(dst)) - self.created_paths.append(dst) - if not os.path.isdir(src): - try: - if(self.args['buildtype'].lower() == 'debug'): - test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "") - else: - test_assembly_binding(src, "Microsoft.VC80.CRT", "") - raise Exception("Unknown condition") - except NoManifestException as err: - pass - except NoMatchingAssemblyException as err: - pass - - self.ccopy(src,dst) - else: - raise Exception("Directories are not supported by test_CRT_and_copy_action()") - else: - print("Doesn't exist:", src) - def construct(self): super().construct() - pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - relpkgdir = os.path.join(pkgdir, "lib", "release") - debpkgdir = os.path.join(pkgdir, "lib", "debug") - if self.is_packaging_viewer(): - # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe. - self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe()) - GITHUB_OUTPUT = os.getenv('GITHUB_OUTPUT') if GITHUB_OUTPUT: # Emit the whole app image as one of the GitHub step outputs. We @@ -537,10 +483,13 @@ def construct(self): for pattern in ( 'secondlife-bin.*', '*_Setup.exe', - '*.bat', - '*.tar.xz'))) + '**/*.bat', + '**/*.pdb', + '**/*.lib', + '**/*.exp', + '**/*.tar.xz'))) - with self.prefix(src=os.path.join(pkgdir, "VMP")): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'viewer-manager')): # include the compiled launcher scripts so that it gets included in the file_list self.path('SLVersionChecker.exe') @@ -552,173 +501,43 @@ def construct(self): self.path("*.png") self.path("*.gif") - # Plugin host application - self.path2basename(os.path.join(os.pardir, - 'llplugin', 'slplugin', self.args['configuration']), - "slplugin.exe") - - # Get shared libs from the shared libs staging directory - with self.prefix(src=os.path.join(self.args['build'], os.pardir, - 'sharedlibs', self.args['buildtype'])): - # WebRTC libraries - for libfile in ( - 'llwebrtc.dll', - ): - self.path(libfile) - - if self.args['discord'] == 'ON': - self.path("discord_partner_sdk.dll") - - if self.args['openal'] == 'ON': - # Get openal dll - self.path("OpenAL32.dll") - self.path("alut.dll") - - # For textures - self.path("openjp2.dll") - - # These need to be installed as a SxS assembly, currently a 'private' assembly. - # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx - self.path("msvcp140.dll") - self.path_optional("msvcp140_1.dll") - self.path_optional("msvcp140_2.dll") - self.path_optional("msvcp140_atomic_wait.dll") - self.path_optional("msvcp140_codecvt_ids.dll") - self.path("vcruntime140.dll") - self.path_optional("vcruntime140_1.dll") - self.path_optional("vcruntime140_threads.dll") - - # SLVoice executable - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): - self.path("SLVoice.exe") - - # Vivox libraries - self.path("vivoxsdk_x64.dll") - self.path("ortp_x64.dll") - - # BugSplat - if self.args.get('bugsplat'): + # BugSplat + if self.args.get('bugsplat'): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'tools')): self.path("BsSndRpt64.exe") + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'bin')): self.path("BugSplat64.dll") self.path("BugSplatRc64.dll") - if self.args['tracy'] == 'ON': - with self.prefix(src=os.path.join(pkgdir, 'bin')): - self.path("tracy-profiler.exe") + # Touch files and directories copied by cmake or vcpkg for nsi generation + with self.prefix(src_dst=self.get_dst_prefix()): + self.path(self.final_exe()) + self.path("*.dll") + self.path("SLPlugin.exe") + self.path("SLVoice.exe") + + # Plugins are only built in non-debug builds on windows + if self.args['buildtype'].lower() != 'debug': + with self.prefix(src_dst=os.path.join(self.get_dst_prefix(), 'llplugin')): + # Plugin and dependency DLL files + self.path("*.dll") + # CEF files + self.path("*.exe") + self.path("*.pak") + self.path("*.bin") + self.path("*.json") + # VLC files + self.path("*.dat") + self.path("locales") + self.path("plugins") self.path(src="licenses-win32.txt", dst="licenses.txt") self.path("featuretable.txt") self.path("cube.dae") - with self.prefix(src=pkgdir): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'secondlife-certificates')): self.path("ca-bundle.crt") - # Media plugins - CEF - with self.prefix(dst="llplugin"): - with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins')): - with self.prefix(src=os.path.join('cef', self.args['configuration'])): - self.path("media_plugin_cef.dll") - - # Media plugins - LibVLC - with self.prefix(src=os.path.join('libvlc', self.args['configuration'])): - self.path("media_plugin_libvlc.dll") - - # Media plugins - Example (useful for debugging - not shipped with release viewer) - if self.channel_type() != 'release': - with self.prefix(src=os.path.join('example', self.args['configuration'])): - self.path("media_plugin_example.dll") - - # CEF runtime files - debug - # CEF runtime files - not debug (release, relwithdebinfo etc.) - config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release' - with self.prefix(src=os.path.join(pkgdir, 'bin', config)): - self.path("chrome_elf.dll") - self.path("d3dcompiler_47.dll") - self.path("dxcompiler.dll") - self.path("dxil.dll") - self.path("libcef.dll") - self.path("libEGL.dll") - self.path("libGLESv2.dll") - self.path("v8_context_snapshot.bin") - self.path("vk_swiftshader.dll") - self.path("vk_swiftshader_icd.json") - self.path("vulkan-1.dll") - self.path("dullahan_host.exe") - - # MSVC DLLs needed for CEF and have to be in same directory as plugin - with self.prefix(src=os.path.join(self.args['build'], os.pardir, - 'sharedlibs', self.args['buildtype'])): - self.path("msvcp140.dll") - self.path("vcruntime140.dll") - self.path_optional("vcruntime140_1.dll") - - # CEF files common to all configurations - with self.prefix(src=os.path.join(pkgdir, 'resources')): - self.path("chrome_100_percent.pak") - self.path("chrome_200_percent.pak") - self.path("resources.pak") - self.path("icudtl.dat") - - with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst='locales'): - self.path("am.pak") - self.path("ar.pak") - self.path("bg.pak") - self.path("bn.pak") - self.path("ca.pak") - self.path("cs.pak") - self.path("da.pak") - self.path("de.pak") - self.path("el.pak") - self.path("en-GB.pak") - self.path("en-US.pak") - self.path("es-419.pak") - self.path("es.pak") - self.path("et.pak") - self.path("fa.pak") - self.path("fi.pak") - self.path("fil.pak") - self.path("fr.pak") - self.path("gu.pak") - self.path("he.pak") - self.path("hi.pak") - self.path("hr.pak") - self.path("hu.pak") - self.path("id.pak") - self.path("it.pak") - self.path("ja.pak") - self.path("kn.pak") - self.path("ko.pak") - self.path("lt.pak") - self.path("lv.pak") - self.path("ml.pak") - self.path("mr.pak") - self.path("ms.pak") - self.path("nb.pak") - self.path("nl.pak") - self.path("pl.pak") - self.path("pt-BR.pak") - self.path("pt-PT.pak") - self.path("ro.pak") - self.path("ru.pak") - self.path("sk.pak") - self.path("sl.pak") - self.path("sr.pak") - self.path("sv.pak") - self.path("sw.pak") - self.path("ta.pak") - self.path("te.pak") - self.path("th.pak") - self.path("tr.pak") - self.path("uk.pak") - self.path("vi.pak") - self.path("zh-CN.pak") - self.path("zh-TW.pak") - - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): - self.path("libvlc.dll") - self.path("libvlccore.dll") - self.path("plugins/") - if not self.is_packaging_viewer(): self.package_file = "copied_deps" @@ -831,7 +650,7 @@ def package_finish(self): self.package_file = installer_file -class Darwin_x86_64_Manifest(ViewerManifest): +class DarwinManifest(ViewerManifest): build_data_json_platform = 'mac' address_size = 64 @@ -854,9 +673,7 @@ def construct(self): # script) self.path(os.path.join(self.args['configuration'], self.channel() + ".app"), dst="") - pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - relpkgdir = os.path.join(pkgdir, "lib", "release") - debpkgdir = os.path.join(pkgdir, "lib", "debug") + relpkgdir = os.path.join(self.args['vcpkg_dir'], "lib") with self.prefix(src="", dst="Contents"): # everything goes in Contents bugsplat_db = self.args.get('bugsplat') @@ -875,88 +692,25 @@ def construct(self): # CEF framework goes inside Contents/Frameworks. # Remember where we parked this car. with self.prefix(src=relpkgdir, dst="Frameworks"): - self.path("libndofdev.dylib") - - - if self.args.get('bugsplat'): - self.path2basename(relpkgdir, "BugsplatMac.framework") - self.path2basename(relpkgdir, "CrashReporter.framework") - self.path2basename(relpkgdir, "HockeySDK.framework") - - # OpenAL dylibs - if self.args['openal'] == 'ON': - for libfile in ( - "libopenal.dylib", - "libalut.dylib", - ): - self.path(libfile) - # WebRTC libraries with self.prefix(src=os.path.join(self.args['build'], os.pardir, - 'sharedlibs', self.args['buildtype'], 'Resources')): - for libfile in ( - 'libllwebrtc.dylib', - ): - self.path(libfile) + 'llwebrtc', self.args['configuration'])): + self.path('libllwebrtc.dylib') with self.prefix(dst="MacOS"): executable = self.dst_path_of(self.channel()) - if self.args.get('bugsplat'): - # According to Apple Technical Note TN2206: - # https://developer.apple.com/library/archive/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG207 - # "If an app uses @rpath or an absolute path to link to a - # dynamic library outside of the app, the app will be - # rejected by Gatekeeper. ... Neither the codesign nor the - # spctl tool will show the error." - # (Thanks, Apple. Maybe fix spctl to warn?) - # The BugsplatMac framework embeds @rpath, which is - # causing scary Gatekeeper popups at viewer start. Work - # around this by changing the reference baked into our - # viewer. The install_name_tool -change option needs the - # previous value. Instead of guessing -- which might - # silently be defeated by a BugSplat SDK update that - # changes their baked-in @rpath -- ask for the path - # stamped into the framework. - # Let exception, if any, propagate -- if this doesn't - # work, we need the build to noisily fail! - oldpath = subprocess.check_output( - ['objdump', '--macho', '--dylib-id', '--non-verbose', - os.path.join(relpkgdir, "HockeySDK.framework", "HockeySDK")], - text=True - ).splitlines()[-1] # take the last line of output - self.run_command( - ['install_name_tool', '-change', oldpath, - '@executable_path/../Frameworks/HockeySDK.framework/HockeySDK', - executable]) - oldpath = subprocess.check_output( - ['objdump', '--macho', '--dylib-id', '--non-verbose', - os.path.join(relpkgdir, "CrashReporter.framework", "CrashReporter")], - text=True - ).splitlines()[-1] # take the last line of output - self.run_command( - ['install_name_tool', '-change', oldpath, - '@executable_path/../Frameworks/CrashReporter.framework/CrashReporter', - executable]) - oldpath = subprocess.check_output( - ['objdump', '--macho', '--dylib-id', '--non-verbose', - os.path.join(relpkgdir, "BugsplatMac.framework", "BugsplatMac")], - text=True - ).splitlines()[-1] # take the last line of output - self.run_command( - ['install_name_tool', '-change', oldpath, - '@executable_path/../Frameworks/BugsplatMac.framework/BugsplatMac', - executable]) - - # NOTE: the -S argument to strip causes it to keep - # enough info for annotated backtraces (i.e. function - # names in the crash log). 'strip' with no arguments - # yields a slightly smaller binary but makes crash - # logs mostly useless. This may be desirable for the - # final release. Or not. - if ("package" in self.args['actions'] or - "unpacked" in self.args['actions']): - self.run_command( - ['strip', '-S', executable]) + # Xcode generator handles stripping as part of deploy processing + if self.args['buildtype'].lower() == 'release': + # NOTE: the -S argument to strip causes it to keep + # enough info for annotated backtraces (i.e. function + # names in the crash log). 'strip' with no arguments + # yields a slightly smaller binary but makes crash + # logs mostly useless. This may be desirable for the + # final release. Or not. + if ("package" in self.args['actions'] or + "unpacked" in self.args['actions']): + self.run_command( + ['strip', '-S', executable]) with self.prefix(dst="Resources"): # defer cross-platform file copies until we're in the @@ -968,7 +722,8 @@ def construct(self): self.path("secondlife.icns") # Copy in the updater script and helper modules - self.path(src=os.path.join(pkgdir, 'VMP'), dst="updater") + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'viewer-manager'), dst="updater"): + self.path("SLVersionChecker") with self.prefix(src="", dst=os.path.join("updater", "icons")): self.path2basename(self.icon_path(), "secondlife.ico") @@ -983,7 +738,7 @@ def construct(self): self.path("featuretable_mac.txt") self.path("cube.dae") - with self.prefix(src=pkgdir,dst=""): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'secondlife-certificates'),dst=""): self.path("ca-bundle.crt") # Translations @@ -1041,22 +796,13 @@ def path_optional(src, dst): libfile_parent = self.get_dst_prefix() dylibs=[] # SLVoice executable - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): - self.path("SLVoice") - - # Vivox libraries - for libfile in ( - 'libortp.dylib', - 'libvivoxsdk.dylib', - ): - self.path2basename(relpkgdir, libfile) - - # Discord social SDK - if self.args['discord'] == 'ON': + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'slvoice', 'darwin64')): for libfile in ( - "libdiscord_partner_sdk.dylib", - ): - self.path2basename(relpkgdir, libfile) + 'SLVoice', + 'libortp.dylib', + 'libvivoxsdk.dylib', + ): + self.path(libfile) # our apps executable_path = {} @@ -1075,26 +821,32 @@ def path_optional(src, dst): self.path2basename("../media_plugins/cef/" + self.args['configuration'], "media_plugin_cef.dylib") - # copy LibVLC plugin - self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], - "media_plugin_libvlc.dylib") - # CEF framework and vlc libraries goes inside Contents/Frameworks. - with self.prefix(src=os.path.join(pkgdir, 'lib', 'release')): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'lib')): self.path("Chromium Embedded Framework.framework") + + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'dullahan-bin', 'helpers')): self.path("DullahanHelper.app") self.path("DullahanHelper (Alerts).app") self.path("DullahanHelper (GPU).app") self.path("DullahanHelper (Renderer).app") self.path("DullahanHelper (Plugin).app") - # Copy libvlc + # copy LibVLC plugin + self.path2basename("../media_plugins/libvlc/" + self.args['configuration'], + "media_plugin_libvlc.dylib") + + # Copy libvlc + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'lib')): self.path( "libvlc*.dylib*" ) - # copy LibVLC plugins folder - with self.prefix(src='plugins', dst="plugins"): - self.path( "*.dylib" ) - self.path( "plugins.dat" ) + # copy LibVLC plugins folder + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'plugins', 'vlc-bin', 'plugins'), dst="plugins"): + self.path( "*.dylib" ) + self.path( "plugins.dat" ) + + # This will be overwritten in package_finish during the actual package step + self.package_file = "copied_deps" def package_finish(self): imagename = self.installer_base_name_mac() @@ -1116,9 +868,9 @@ def package_finish(self): # causes problems, especially with frameworks: a framework's top # level must contain symlinks into its Versions/Current, which # must itself be a symlink to some specific Versions subdir. - tarpath = os.path.join(RUNNER_TEMP, "viewer.tar.xz") + tarpath = os.path.join(RUNNER_TEMP, "viewer.tar") print(f'Creating {tarpath} from {self.get_dst_prefix()}') - with tarfile.open(tarpath, mode="w:xz") as tarball: + with tarfile.open(tarpath, mode="w") as tarball: # Store in the tarball as just 'Second Life Mumble.app' # instead of 'Users/someone/.../newview/Release/Second...' # It's at this point that we rename 'Second Life Release.app' @@ -1127,6 +879,11 @@ def package_finish(self): arcname=self.app_name() + ".app") self.set_github_output_path('viewer_app', tarpath) +class Darwin_x86_64_Manifest(DarwinManifest): + pass + +class Darwin_arm64_Manifest(DarwinManifest): + pass class LinuxManifest(ViewerManifest): build_data_json_platform = 'lnx' @@ -1134,13 +891,6 @@ class LinuxManifest(ViewerManifest): def construct(self): super(LinuxManifest, self).construct() - pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - if "package_dir" in self.args: - pkgdir = self.args['package_dir'] - - relpkgdir = os.path.join(pkgdir, "lib", "release") - debpkgdir = os.path.join(pkgdir, "lib", "debug") - self.path("licenses-linux.txt","licenses.txt") with self.prefix("linux_tools"): self.path("wrapper.sh","secondlife") @@ -1151,8 +901,8 @@ def construct(self): self.path("install.sh") with self.prefix(dst="bin"): - self.path("secondlife-bin","do-not-directly-run-secondlife-bin") - self.path2basename("../llplugin/slplugin", "SLPlugin") + with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'llplugin', 'slplugin', self.args['configuration'])): + self.path("SLPlugin") #this copies over the python wrapper script, associated utilities and required libraries, see SL-321, SL-322 and SL-323 #with self.prefix(src="../viewer_components/manager", dst=""): # self.path("*.py") @@ -1170,63 +920,66 @@ def construct(self): with self.prefix(dst="res-sdl") : self.path("secondlife_256.BMP","ll_icon.BMP") - with self.prefix(src=os.path.join(self.args['build'], os.pardir, "llwebrtc" ), dst="lib"): + with self.prefix(src=os.path.join(self.args['build'], os.pardir, "llwebrtc", self.args['configuration']), dst="lib"): self.path("libllwebrtc.so") # plugins with self.prefix(dst="bin/llplugin"): with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'media_plugins')): - with self.prefix(src='cef'): + with self.prefix(src=os.path.join('cef', self.args['configuration'])): self.path("libmedia_plugin_cef.so") # Media plugins - LibVLC - with self.prefix(src='libvlc'): + with self.prefix(src=os.path.join('libvlc', self.args['configuration'])): self.path("libmedia_plugin_libvlc.so") # GStreamer 1.0 Media Plugin - with self.prefix(src='gstreamer10'): + with self.prefix(src=os.path.join('gstreamer10', self.args['configuration'])): self.path("libmedia_plugin_gstreamer10.so") # Media plugins - Example (useful for debugging - not shipped with release viewer) if self.channel_type() != 'release': - with self.prefix(src='example'): + with self.prefix(src=os.path.join('example', self.args['configuration'])): self.path("libmedia_plugin_example.so") - with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="lib"): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'lib'), dst="lib"): self.path( "libcef.so" ) self.path( "libEGL*" ) self.path( "libvulkan*" ) self.path( "libvk_swiftshader*" ) self.path( "libGLESv2*" ) - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="bin"): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'bin'), dst="bin"): self.path( "chrome-sandbox" ) self.path( "dullahan_host" ) - with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="bin"): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'lib'), dst="bin"): self.path( "v8_context_snapshot.bin" ) self.path( "vk_swiftshader_icd.json") - with self.prefix(src=os.path.join(pkgdir, 'lib', 'release'), dst="lib"): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'lib'), dst="lib"): self.path( "v8_context_snapshot.bin" ) self.path( "vk_swiftshader_icd.json") - with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="lib"): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'dullahan-bin', 'resources'), dst="lib"): self.path( "chrome_100_percent.pak" ) self.path( "chrome_200_percent.pak" ) self.path( "resources.pak" ) self.path( "icudtl.dat" ) - with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('lib', 'locales')): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'dullahan-bin', 'resources', 'locales'), dst=os.path.join('lib', 'locales')): self.path("*.pak") self.path("featuretable_linux.txt") self.path("cube.dae") - with self.prefix(src=pkgdir, dst="bin"): + with self.prefix(src=os.path.join(self.args['vcpkg_dir'], 'share', 'secondlife-certificates'), dst="bin"): self.path("ca-bundle.crt") + if not self.is_packaging_viewer(): + self.package_file = "copied_deps" + def package_finish(self): installer_name = self.installer_base_name() @@ -1257,22 +1010,22 @@ def package_finish(self): if RUNNER_TEMP: tarName = os.path.join(RUNNER_TEMP, self.package_file) - self.run_command(["mv", realname, versionedName]) - - try: - # only create tarball if it's a release build. - if self.args['buildtype'].lower() == 'release': + # only create tarball if it's a release build. + if self.args['buildtype'].lower() == 'release': + try: + self.run_command(["mv", realname, versionedName]) # --numeric-owner hides the username of the builder for # security etc. self.run_command(['tar', '-C', self.get_build_prefix(), - '--numeric-owner', '-cJf', - tarName, installer_name]) + '--numeric-owner', '-cJf', + tarName, installer_name]) self.set_github_output_path('viewer_app', tarName) - else: - print("Skipping %s.tar.xz for non-Release build (%s)" % \ - (installer_name, self.args['buildtype'])) - finally: - self.run_command(["mv", versionedName, realname]) + finally: + self.run_command(["mv", versionedName, realname]) + else: + print("Skipping %s.tar.xz for non-Release build (%s)" % \ + (installer_name, self.args['buildtype'])) + def strip_binaries(self): if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer(): @@ -1297,32 +1050,22 @@ class Linux_x86_64_Manifest(LinuxManifest): def construct(self): super(Linux_x86_64_Manifest, self).construct() - pkgdir = os.path.join(self.args['build'], os.pardir, 'packages') - if "package_dir" in self.args: - pkgdir = self.args['package_dir'] - - relpkgdir = os.path.join(pkgdir, "lib", "release") - #debpkgdir = os.path.join(pkgdir, "lib", "debug") - - with self.prefix(src=relpkgdir, dst="lib"): - self.path("libSDL*.so.*") - - self.path("libalut.so*") - self.path("libopenal.so*") - + vcpkgdir = os.path.join(self.args['vcpkg_dir'], 'lib') + with self.prefix(src=vcpkgdir, dst="lib"): if self.args['discord'] == 'ON': self.path("libdiscord_partner_sdk.so*") # Vivox runtimes - with self.prefix(src=relpkgdir, dst="bin"): + vcpkg_voicedir = os.path.join(self.args['vcpkg_dir'], 'share', 'slvoice', 'linux') + with self.prefix(src=vcpkg_voicedir, dst="bin"): self.path("SLVoice") - with self.prefix(src=relpkgdir, dst="lib"): + with self.prefix(src=vcpkg_voicedir, dst="lib"): self.path("libortp.so") - self.path("libsndfile.so.1") - #self.path("libvivoxoal.so.1") # no - we'll re-use the viewer's own OpenAL lib + self.path("libsndfile.so.1*") + self.path("libvivoxoal.so.1*") # no - we'll re-use the viewer's own OpenAL lib + self.path("libvivoxplatform.so") self.path("libvivoxsdk.so") - self.strip_binaries() ################################################################ if __name__ == "__main__": diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index c1e63a7470d..4e371ac1c8b 100644 --- a/indra/test/CMakeLists.txt +++ b/indra/test/CMakeLists.txt @@ -1,23 +1,17 @@ # -*- cmake -*- -project (lltest) +add_library(lltut_runner_lib STATIC) -include(00-Common) -include(LLCommon) -include(LLCoreHttp) -include(Linking) -include(Tut) -include(LLAddBuildTest) -include(bugsplat) - -set(test_lib_SOURCE_FILES +target_sources(lltut_runner_lib + PRIVATE lltut.cpp test.cpp ) -set(test_lib_HEADER_FILES - CMakeLists.txt - +target_sources(lltut_runner_lib + PUBLIC + FILE_SET HEADERS + FILES catch_and_store_what_in.h chained_callback.h debug.h @@ -31,20 +25,9 @@ set(test_lib_HEADER_FILES test.h ) -list(APPEND test_lib_SOURCE_FILES ${test_lib_HEADER_FILES}) - -add_library(lltut_runner_lib ${test_lib_SOURCE_FILES}) - -target_link_libraries(lltut_runner_lib PRIVATE llcommon) +target_link_libraries(lltut_runner_lib PUBLIC llcommon ll::tut) set_target_properties(lltut_runner_lib PROPERTIES FOLDER "Tests" ) - -if (DARWIN) - set_target_properties(lltut_runner_lib - PROPERTIES - OSX_ARCHITECTURES ${LL_MACOS_TEST_ARCHITECTURE} - ) -endif () diff --git a/indra/vcpkg-configuration.json b/indra/vcpkg-configuration.json new file mode 100644 index 00000000000..afa5017d5a4 --- /dev/null +++ b/indra/vcpkg-configuration.json @@ -0,0 +1,19 @@ +{ + "registries": [ + { + "kind": "git", + "baseline": "b21b50b5f376596aa30b342cba1cb7d9b650ca7f", + "reference": "main", + "repository": "git@github.com:RyeMutt/secondlife-registry.git", + "packages": [ + "kdu" + ] + } + ], + "overlay-ports": [ + "vcpkg/ports" + ], + "overlay-triplets": [ + "vcpkg/triplets" + ] +} diff --git a/indra/vcpkg.json b/indra/vcpkg.json new file mode 100644 index 00000000000..258411ab767 --- /dev/null +++ b/indra/vcpkg.json @@ -0,0 +1,200 @@ +{ + "builtin-baseline": "66c0373dc7fca549e5803087b9487edfe3aca0a1", + "dependencies": [ + "apr", + "apr-util", + "boost-asio", + "boost-circular-buffer", + "boost-fiber", + "boost-graph", + "boost-iostreams", + "boost-json", + "boost-program-options", + "boost-random", + "boost-regex", + "boost-signals2", + "boost-spirit", + "boost-stacktrace", + "boost-url", + "collada-dom", + { + "name": "curl", + "features": [ + "http2", + "openssl" + ] + }, + "dullahan-bin", + "expat", + { + "name": "fontconfig", + "platform": "linux" + }, + { + "name": "fontconfig", + "platform": "linux" + }, + "freealut", + { + "name": "freetype", + "features": [ + "brotli", + "error-strings", + "png", + "subpixel-rendering", + "zlib" + ] + }, + "glm", + "hunspell", + { + "name": "libjpeg-turbo", + "features": [ + "jpeg8" + ] + }, + { + "name": "libndofdev", + "platform": "windows | osx" + }, + "libpng", + "libvorbis", + "meshoptimizer", + "minizip", + "nanosvg", + { + "name": "nvapi", + "platform": "windows & x64" + }, + { + "name": "open-libndofdev", + "platform": "linux" + }, + { + "name": "openal-soft", + "features": [ + { + "name": "pipewire", + "platform": "linux" + }, + { + "name": "pulseaudio", + "platform": "linux" + } + ] + }, + "opengl-registry", + "openjpeg", + { + "name": "openssl", + "features": [ + "weak-ssl-ciphers" + ] + }, + { + "name": "pkgconf", + "platform": "windows | osx" + }, + "secondlife-certificates", + "secondlife-dictionaries", + "secondlife-emoji-shortcodes", + "secondlife-fonts", + "slvoice", + { + "name": "sse2neon", + "platform": "osx" + }, + "tinyexr", + "tinygltf", + "v-hacd", + { + "name": "viewer-manager", + "platform": "windows | osx" + }, + { + "name": "vlc-bin", + "platform": "windows | osx" + }, + "webrtc-bin", + "xxhash", + "zlib" + ], + "default-features": [ + { + "name": "sdl3", + "platform": "linux" + } + ], + "features": { + "bugsplat": { + "description": "Build with support for Bugsplat crash reporting", + "dependencies": [ + { + "name": "bugsplat", + "platform": "windows & x64" + }, + { + "name": "bugsplat-apple", + "platform": "osx" + } + ] + }, + "kdu": { + "description": "Build with support for Kakadu JPEG2000", + "dependencies": [ + "kdu" + ] + }, + "openxr": { + "description": "Build with support for OpenXR(experimental)", + "dependencies": [ + "openxr-loader" + ] + }, + "sdl3": { + "description": "Build with platform independent SDL window backend", + "dependencies": [ + "sdl3" + ] + }, + "tracy": { + "description": "Build with Tracy profiler support", + "dependencies": [ + "tracy" + ] + }, + "tracy-gui": { + "description": "Build with Tracy profiler GUI support", + "dependencies": [ + { + "name": "tracy", + "features": [ + "gui-tools" + ] + } + ] + }, + "tracy-local": { + "description": "Build with Tracy profiler with localhost only", + "dependencies": [ + { + "name": "tracy", + "features": [ + "localhost" + ] + } + ] + }, + "tracy-on-demand": { + "description": "Build with Tracy profiler support", + "dependencies": [ + { + "name": "tracy", + "features": [ + "on-demand" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/indra/vcpkg/ports/apr/0100-add-host-tools-dir.diff b/indra/vcpkg/ports/apr/0100-add-host-tools-dir.diff new file mode 100644 index 00000000000..c38d8975f6d --- /dev/null +++ b/indra/vcpkg/ports/apr/0100-add-host-tools-dir.diff @@ -0,0 +1,23 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index d16eec6..92146f4 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -87,13 +87,17 @@ STRING(REGEX REPLACE ".*#define APR_PATCH_VERSION[ \t]+([0-9]+).*" "\\1" APR_PAT + + CONFIGURE_FILE(include/apr.hwc + ${PROJECT_BINARY_DIR}/apr.h) + + ADD_EXECUTABLE(gen_test_char tools/gen_test_char.c) + ++set(UNOFFICIAL_APR_HOST_TOOLS_DIR "$" CACHE STRING "") ++set(UNOFFICIAL_APR_HOST_EXECUTABLE_SUFFIX "$" CACHE STRING "") ++install(TARGETS gen_test_char) ++ + ADD_CUSTOM_COMMAND( + COMMENT "Generating character tables, apr_escape_test_char.h, for current locale" + DEPENDS gen_test_char +- COMMAND $ > ${PROJECT_BINARY_DIR}/apr_escape_test_char.h ++ COMMAND "${UNOFFICIAL_APR_HOST_TOOLS_DIR}/gen_test_char${UNOFFICIAL_APR_HOST_EXECUTABLE_SUFFIX}" > ${PROJECT_BINARY_DIR}/apr_escape_test_char.h + OUTPUT ${PROJECT_BINARY_DIR}/apr_escape_test_char.h + ) + ADD_CUSTOM_TARGET( diff --git a/indra/vcpkg/ports/apr/0200-linden-apr-features.diff b/indra/vcpkg/ports/apr/0200-linden-apr-features.diff new file mode 100644 index 00000000000..5eb12449ea6 --- /dev/null +++ b/indra/vcpkg/ports/apr/0200-linden-apr-features.diff @@ -0,0 +1,1718 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b8414fb..43af380 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -60,6 +60,8 @@ IF(NOT APR_BUILD_STATIC AND TEST_STATIC_LIBS) + MESSAGE(FATAL_ERROR "APR_BUILD_STATIC has been disabled, but TEST_STATIC_LIBS is enabled") + ENDIF() + ++add_compile_definitions(-D_UNICODE -DUNICODE) ++ + # create 1-or-0 representation of feature tests for apr.h + + SET(apr_have_ipv6_10 0) +@@ -204,6 +206,7 @@ SET(APR_SOURCES + misc/win32/charset.c + misc/win32/env.c + misc/win32/internal.c ++ misc/win32/log.c + misc/win32/misc.c + misc/win32/rand.c + misc/win32/start.c +diff --git a/atomic/win32/apr_atomic.c b/atomic/win32/apr_atomic.c +index 5c2a870..2764b5d 100644 +--- a/atomic/win32/apr_atomic.c ++++ b/atomic/win32/apr_atomic.c +@@ -16,6 +16,12 @@ + + #include "apr_arch_atomic.h" + ++#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) ++#define castptr(ptr) (ptr) ++#else ++#define castptr(ptr) ((long *)ptr) ++#endif ++ + APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) + { + return APR_SUCCESS; +@@ -23,11 +29,7 @@ APR_DECLARE(apr_status_t) apr_atomic_init(apr_pool_t *p) + + APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) +- return InterlockedExchangeAdd(mem, val); +-#else +- return InterlockedExchangeAdd((long *)mem, val); +-#endif ++ return InterlockedExchangeAdd(castptr(mem), val); + } + + /* Of course we want the 2's compliment of the unsigned value, val */ +@@ -37,39 +39,23 @@ APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint3 + + APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) +- InterlockedExchangeAdd(mem, -val); +-#else +- InterlockedExchangeAdd((long *)mem, -val); +-#endif ++ InterlockedExchangeAdd(castptr(mem), -val); + } + + APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem) + { + /* we return old value, win32 returns new value :( */ +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedIncrement(mem) - 1; +-#else +- return InterlockedIncrement((long *)mem) - 1; +-#endif ++ return InterlockedIncrement(castptr(mem)) - 1; + } + + APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedDecrement(mem); +-#else +- return InterlockedDecrement((long *)mem); +-#endif ++ return InterlockedDecrement(castptr(mem)); + } + + APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- InterlockedExchange(mem, val); +-#else +- InterlockedExchange((long*)mem, val); +-#endif ++ InterlockedExchange(castptr(mem), val); + } + + APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) +@@ -80,15 +66,13 @@ APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem) + APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with, + apr_uint32_t cmp) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedCompareExchange(mem, with, cmp); +-#else +- return InterlockedCompareExchange((long*)mem, with, cmp); +-#endif ++ return InterlockedCompareExchange(castptr(mem), with, cmp); + } + + APR_DECLARE(void *) apr_atomic_casptr(volatile void **mem, void *with, const void *cmp) + { ++/* The casting in the body of this function diverges from FORWARD(); ++ expand it explicitly. */ + #if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) + return InterlockedCompareExchangePointer((void* volatile*)mem, with, (void*)cmp); + #else +@@ -98,11 +82,7 @@ APR_DECLARE(void *) apr_atomic_casptr(volatile void **mem, void *with, const voi + + APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedExchange(mem, val); +-#else +- return InterlockedExchange((long *)mem, val); +-#endif ++ return InterlockedExchange(castptr(mem), val); + } + + APR_DECLARE(void*) apr_atomic_xchgptr(volatile void **mem, void *with) +diff --git a/file_io/win32/filesys.c b/file_io/win32/filesys.c +index e812139..bdb0e9b 100644 +--- a/file_io/win32/filesys.c ++++ b/file_io/win32/filesys.c +@@ -77,7 +77,7 @@ apr_status_t filepath_root_test(char *path, apr_pool_t *p) + } + else + #endif +- rv = GetDriveType(path); ++ rv = GetDriveTypeA(path); + + if (rv == DRIVE_UNKNOWN || rv == DRIVE_NO_ROOT_DIR) + return APR_EBADPATH; +diff --git a/file_io/win32/pipe.c b/file_io/win32/pipe.c +index dd8ef13..3178a4c 100644 +--- a/file_io/win32/pipe.c ++++ b/file_io/win32/pipe.c +@@ -170,7 +170,8 @@ APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, + pos = apr_snprintf(name, sizeof name, FMT_PIPE_NAME, pid, id++); + apr_escape_hex(name + pos, rand, sizeof rand, 0, NULL); + +- (*in)->filehand = CreateNamedPipe(name, ++ /* Don't bother with utf8_to_unicode_path(): FMT_PIPE_NAME is ASCII */ ++ (*in)->filehand = CreateNamedPipeA(name, + dwOpenMode, + dwPipeMode, + 1, /* nMaxInstances, */ +@@ -195,7 +196,8 @@ APR_DECLARE(apr_status_t) apr_file_pipe_create_pools(apr_file_t **in, + (*out)->timeout = 0; + } + +- (*out)->filehand = CreateFile(name, ++ /* Don't bother with utf8_to_unicode_path(): FMT_PIPE_NAME is ASCII */ ++ (*out)->filehand = CreateFileA(name, + GENERIC_WRITE, /* access mode */ + 0, /* share mode */ + &sa, /* Security attributes */ +diff --git a/file_io/win32/readwrite.c b/file_io/win32/readwrite.c +index 2275f51..e66a1db 100644 +--- a/file_io/win32/readwrite.c ++++ b/file_io/win32/readwrite.c +@@ -468,7 +468,19 @@ APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, a + rv = APR_SUCCESS; + } + else { +- (*nbytes) = 0; ++ /* nat 2012-03-14: This else case used to clear *nbytes to 0. That ++ * makes sense only if WriteFile() guarantees never to return ++ * ERROR_IO_PENDING if any bytes were written. Empirically, ++ * though, we observe that at high data volumes we sometimes get ++ * APR_EAGAIN from this function but duplicate data at the other ++ * end of the pipe. In other words, apparently a WriteFile() call ++ * can (partially) succeed despite the APR_EAGAIN return. If we ++ * unconditionally tell the caller that the APR_EAGAIN call wrote ++ * 0 bytes, that logic can only retry the whole apr_file_write() ++ * call -- hence the duplicate data. This edit expresses my hope ++ * that in the case of a partial write, WriteFile() will properly ++ * update bwrote. */ ++ (*nbytes) = bwrote; + rv = apr_get_os_error(); + + /* XXX: This must be corrected, per the apr_file_read logic!!! */ +diff --git a/include/apr_thread_proc.h b/include/apr_thread_proc.h +index ea3c43f..8806cbe 100644 +--- a/include/apr_thread_proc.h ++++ b/include/apr_thread_proc.h +@@ -502,6 +502,55 @@ APR_DECLARE(apr_status_t) apr_procattr_cmdtype_set(apr_procattr_t *attr, + APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + apr_int32_t detach); + ++/** ++ * Request OS to tie child-process lifespan to parent process. ++ * (Currently supported only on Windows.) ++ * @param attr The procattr we care about. ++ * @param autokill Nonzero means child lifespan will be tied to calling ++ * process lifespan. Default is no. ++ */ ++APR_DECLARE(apr_status_t) apr_procattr_autokill_set(apr_procattr_t *attr, ++ apr_int32_t autokill); ++// APR_HAS_PROCATTR_AUTOKILL_SET actually has three discernable states. Plain ++// APR doesn't define it, so #if ! defined(APR_HAS_PROCATTR_AUTOKILL_SET) can ++// detect if the APR in hand lacks the extension. Further, though, we #define ++// it to 0 on platforms where we happen to know apr_procattr_autokill_set() ++// will return APR_ENOTIMPL. ++// It doesn't seem to work to #define MACRO as defined(OTHERMACRO) because ++// apparently defined() isn't itself a macro; it doesn't get rescanned. From ++// the preprocessor's point of view, MACRO simply has a funny string value. ++#if defined(WIN32) || defined(_WIN32) ++#define APR_HAS_PROCATTR_AUTOKILL_SET 1 // useful implementation ++#else ++#define APR_HAS_PROCATTR_AUTOKILL_SET 0 // placeholder implementation ++#endif ++ ++/** ++ * Request apr_proc_create() to constrain the set of handles passed to the ++ * child process. On Windows, with an ordinary CreateProcess() call, you get ++ * two choices: pass NO handles (bInheritHandles=FALSE), or pass ALL ++ * currently-open handles, from anywhere in the process (including libraries!) ++ * -- except those specifically marked with HANDLE_FLAG_INHERIT 0. ++ * apr_proc_create(), which promises to provide the child process with stdin, ++ * stdout, stderr, normally passes bInheritHandles=TRUE. But std::ofstream et ++ * al. open files as inheritable, and provide no API by which to mark them ++ * otherwise. And since Windows prevents certain operations on files held open ++ * by any process, even if inadvertently, confusing bugs ensue. ++ * Calling apr_procattr_constrain_handle_set(attr, 1) engages obscure ++ * Windows machinery to specifically pass stdin, stdout, stderr -- but no ++ * other handles. ++ * See http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx . ++ * apr_procattr_constrain_handle_set() currently only affects apr_proc_create() ++ * on Windows. ++ * @param attr The procattr we care about. ++ * @param constrain On Windows, nonzero means to explicitly constrain the set ++ * of handles passed to the new child process. Default is 0, like unmodified ++ * APR. ++ */ ++APR_DECLARE(apr_status_t) apr_procattr_constrain_handle_set(apr_procattr_t *attr, ++ apr_int32_t constrain); ++#define APR_HAS_PROCATTR_CONSTRAIN_HANDLE_SET 1 // extension is present ++ + #if APR_HAVE_STRUCT_RLIMIT + /** + * Set the Resource Utilization limits when starting a new process. +diff --git a/include/arch/unix/apr_arch_threadproc.h b/include/arch/unix/apr_arch_threadproc.h +index 7a3b3c0..02f8125 100644 +--- a/include/arch/unix/apr_arch_threadproc.h ++++ b/include/arch/unix/apr_arch_threadproc.h +@@ -113,6 +113,8 @@ struct apr_procattr_t { + apr_uid_t uid; + apr_gid_t gid; + apr_procattr_pscb_t *perms_set_callbacks; ++ apr_int32_t autokill; ++ apr_int32_t constrain; + }; + + #endif /* ! THREAD_PROC_H */ +diff --git a/include/arch/win32/apr_arch_threadproc.h b/include/arch/win32/apr_arch_threadproc.h +index d3ce9c5..f78c75b 100644 +--- a/include/arch/win32/apr_arch_threadproc.h ++++ b/include/arch/win32/apr_arch_threadproc.h +@@ -62,6 +62,8 @@ struct apr_procattr_t { + LPSECURITY_ATTRIBUTES sa; + LPVOID sd; + #endif ++ apr_int32_t autokill; ++ apr_int32_t constrain; + }; + + struct apr_thread_once_t { +diff --git a/include/arch/win32/apr_log.h b/include/arch/win32/apr_log.h +new file mode 100644 +index 0000000..d5bdb37 +--- /dev/null ++++ b/include/arch/win32/apr_log.h +@@ -0,0 +1,31 @@ ++/** ++ * @file apr_log.h ++ * @author Nat Goodspeed ++ * @date 2012-06-15 ++ * @brief Declarations for apr_log() and friends ++ * ++ * $LicenseInfo:firstyear=2012&license=internal$ ++ * Copyright (c) 2012, Linden Research, Inc. ++ * $/LicenseInfo$ ++ */ ++ ++#if ! defined(APR_LOG_H) ++#define APR_LOG_H ++ ++/* ++ * apr_log() is like printf() to an implicit log file. ++ * It's sensitive to APR_LOG environment variable: ++ * - Not set: don't log (default). This state is cached for fast exit. ++ * - Absolute pathname: append to specified log file. ++ * - Relative pathname: prefix with (e.g.) "c:/Users/You/AppData/Roaming". ++ * That means that if you set APR_LOG="SecondLife/logs/apr.log", it should ++ * end up in the same directory as SecondLife.log. ++ * Various errors cause apr_log() to silently fail -- if it's not working, ++ * it's got nowhere to complain! ++ */ ++void apr_log(const char* format, ...); ++/* Return %s suitable for logging a const char* that might be NULL */ ++const char* apr_logstr(const char* str); ++const wchar_t* apr_logwstr(const wchar_t* str); ++ ++#endif /* ! defined(APR_LOG_H) */ +diff --git a/libapr.rc b/libapr.rc +index 604fc7c..9b8db04 100644 +--- a/libapr.rc ++++ b/libapr.rc +@@ -34,7 +34,7 @@ + FILEFLAGS 0x00L + #endif + #endif +-#if defined(WINNT) || defined(WIN64) ++#if defined(WINNT) || defined(_WIN64) + FILEOS 0x40004L + #else + FILEOS 0x4L +diff --git a/misc/win32/log.c b/misc/win32/log.c +new file mode 100644 +index 0000000..c1cccfc +--- /dev/null ++++ b/misc/win32/log.c +@@ -0,0 +1,147 @@ ++/** ++ * @file log.c ++ * @author Nat Goodspeed ++ * @date 2012-06-15 ++ * @brief Add Windows-specific apr_log() function ++ * ++ * I attempted to add this to misc.c, but APR internal headers are a mess -- ++ * it proved impossible to add the requisite Microsoft headers without ++ * breaking things. I tried various orders for the #includes, which changed ++ * the errors without resolving them. :-P ++ * ++ * $LicenseInfo:firstyear=2012&license=internal$ ++ * Copyright (c) 2012, Linden Research, Inc. ++ * $/LicenseInfo$ ++ */ ++ ++#include ++#include ++#include ++#include "apr_time.h" ++#include "apr_file_info.h" ++ ++FILE* apr_open_log(); ++ ++/* I'm amazed that APR doesn't already have GENERAL-PURPOSE logging ++ * infrastructure. ++ * Microsoft's vfprintf() accepts "%ws" or "%ls" (lowercase L) to mean a ++ * wchar_t* string. */ ++void apr_log(const char* format, ...) ++{ ++ /* We could store only a static FILE*, but we must distinguish three cases: ++ - first call, try to open log file ++ - log file successfully opened ++ - open attempt failed, don't bother continually trying to reopen. ++ Hence a separate 'first' flag. No-log behavior should exit quickly so ++ we won't be shy about sprinkling apr_log() calls through the code. */ ++ static int first = 1; ++ static FILE* logf = NULL; ++ ++ if (first) ++ { ++ char date[APR_CTIME_LEN]; ++ apr_ctime(date, apr_time_now()); ++ first = 0; ++ /* Break out apr_open_log() as a separate function because some day we ++ hope to migrate apr_log() to platform-independent source -- but ++ apr_open_log() contains platform-dependent logic. */ ++ logf = apr_open_log(); ++ /* beware, open might fail for any of a number of reasons */ ++ if (logf) ++ { ++ fputs("========================================================================\n", ++ logf); ++ fputs(date, logf); ++ fputs("\n", logf); ++ } ++ } ++ if (logf) ++ { ++ va_list ap; ++ va_start(ap, format); ++ vfprintf(logf, format, ap); ++ va_end(ap); ++ fputs("\n", logf); ++ /* Flush but leave open for next call. If fflush() is working right, ++ we shouldn't actually need to close the file to get all its output. */ ++ fflush(logf); ++ } ++} ++ ++/* apr_open_log() should only be called once per process, so we can perform nontrivial ++ operations as needed. It's sensitive to APR_LOG environment variable: ++ - Not set: don't log (default). ++ - Absolute pathname: append to specified log file. ++ - Relative pathname: prefix with (e.g.) "c:/Users/You/AppData/Roaming". ++ That means that if you set APR_LOG="SecondLife/logs/apr.log", it should ++ end up in the same directory as SecondLife.log. ++*/ ++FILE* apr_open_log() ++{ ++ apr_status_t status = APR_SUCCESS; ++ apr_pool_t* pool = NULL; ++ FILE* logf = NULL; ++ char* APR_LOG = getenv("APR_LOG"); ++ char* APR_LOG_root = APR_LOG; ++ char* APR_LOG_rel = APR_LOG; ++ /* If APR_LOG isn't even set, don't bother with any of the rest of this. */ ++ if (! APR_LOG) ++ return NULL; ++ ++ /* For pathname manipulation, have to get an APR pool. Create and destroy ++ it locally; don't require caller to pass it in. */ ++ if (apr_pool_create(&pool, NULL) != APR_SUCCESS) ++ return NULL; ++ ++ /* Now that pool exists, don't just 'return NULL;' below this point we ++ must 'goto cleanup' instead to destroy the pool. */ ++ ++ /* Is APR_LOG absolute or relative? */ ++ status = apr_filepath_root(&APR_LOG_root, &APR_LOG_rel, 0, pool); ++ /* Skip garbage path. This test is based on code in apr_filepath_merge(). ++ APR_SUCCESS means it's an absolute path; APR_ERELATIVE is obvious; ++ APR_EINCOMPLETE means it starts with slash, which on Windows is an ++ incomplete path because it doesn't specify the drive letter. Anything ++ else means apr_filepath_root() was confused by this pathname. */ ++ if (! (status == APR_SUCCESS || status == APR_ERELATIVE || status == APR_EINCOMPLETE)) ++ goto cleanup; ++ ++ /* If it's a relative pathname, place it within AppData. */ ++ if (status == APR_ERELATIVE || status == APR_EINCOMPLETE) ++ { ++ char appdir[MAX_PATH]; ++ char* abspath = NULL; ++ /* If we can't get the special folder pathname, give up. */ ++ if (S_OK != SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, appdir)) ++ goto cleanup; ++ ++ /* If we can't append APR_LOG to appdir, give up. */ ++ if (APR_SUCCESS != apr_filepath_merge(&abspath, appdir, APR_LOG, 0, pool)) ++ goto cleanup; ++ ++ /* Okay, replace APR_LOG with abspath. */ ++ APR_LOG = abspath; ++ } ++ ++ /* Try to open the file. */ ++ logf = fopen(APR_LOG, "a"); ++ ++cleanup: ++ apr_pool_destroy(pool); /* clean up local temp pool */ ++ return logf; ++} ++ ++/* Return %s suitable for logging a const char* that might be NULL */ ++const char* apr_logstr(const char* str) ++{ ++ if (! str) ++ return "NULL"; ++ return str; ++} ++ ++const wchar_t* apr_logwstr(const wchar_t* str) ++{ ++ if (! str) ++ return L"NULL"; ++ return str; ++} +diff --git a/poll/unix/epoll.c b/poll/unix/epoll.c +index ad3cc0b..f168b54 100644 +--- a/poll/unix/epoll.c ++++ b/poll/unix/epoll.c +@@ -92,7 +92,13 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, + apr_status_t rv; + int fd; + +-#ifdef HAVE_EPOLL_CREATE1 ++ /* Not every system that has epoll_create1() also has EPOLL_CLOEXEC ++ * defined. This conditional depends on systems with EPOLL_CLOEXEC defining ++ * it as a macro. We observe that at least one Linux system which defines ++ * EPOLL_CLOEXEC as an enum value also defines it as a macro -- presumably ++ * for exactly this kind of test. ++ */ ++#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC) + fd = epoll_create1(EPOLL_CLOEXEC); + #else + fd = epoll_create(size); +@@ -343,8 +349,14 @@ static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb, + apr_uint32_t flags) + { + int fd; +- +-#ifdef HAVE_EPOLL_CREATE1 ++ ++ /* Not every system that has epoll_create1() also has EPOLL_CLOEXEC ++ * defined. This conditional depends on systems with EPOLL_CLOEXEC defining ++ * it as a macro. We observe that at least one Linux system which defines ++ * EPOLL_CLOEXEC as an enum value also defines it as a macro -- presumably ++ * for exactly this kind of test. ++ */ ++#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC) + fd = epoll_create1(EPOLL_CLOEXEC); + #else + fd = epoll_create(size); +diff --git a/threadproc/beos/proc.c b/threadproc/beos/proc.c +index e369808..1c47c49 100644 +--- a/threadproc/beos/proc.c ++++ b/threadproc/beos/proc.c +@@ -130,6 +130,17 @@ APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int3 + return APR_SUCCESS; + } + ++APR_DECLARE(apr_status_t) apr_procattr_autokill_set(apr_procattr_t *attr, apr_int32_t autokill) ++{ ++ return APR_ENOTIMPL; ++} ++ ++APR_DECLARE(apr_status_t) apr_procattr_constrain_handle_set(apr_procattr_t *attr, ++ apr_int32_t constrain) ++{ ++ return APR_SUCCESS; ++} ++ + APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) + { + int pid; +diff --git a/threadproc/netware/proc.c b/threadproc/netware/proc.c +index e5306f9..7092715 100644 +--- a/threadproc/netware/proc.c ++++ b/threadproc/netware/proc.c +@@ -217,6 +217,17 @@ APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int3 + return APR_SUCCESS; + } + ++APR_DECLARE(apr_status_t) apr_procattr_autokill_set(apr_procattr_t *attr, apr_int32_t autokill) ++{ ++ return APR_ENOTIMPL; ++} ++ ++APR_DECLARE(apr_status_t) apr_procattr_constrain_handle_set(apr_procattr_t *attr, ++ apr_int32_t constrain) ++{ ++ return APR_SUCCESS; ++} ++ + #if APR_HAS_FORK + APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) + { +diff --git a/threadproc/os2/proc.c b/threadproc/os2/proc.c +index 96f76d6..f617bef 100644 +--- a/threadproc/os2/proc.c ++++ b/threadproc/os2/proc.c +@@ -219,6 +219,17 @@ APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, apr_int3 + return APR_SUCCESS; + } + ++APR_DECLARE(apr_status_t) apr_procattr_autokill_set(apr_procattr_t *attr, apr_int32_t autokill) ++{ ++ return APR_ENOTIMPL; ++} ++ ++APR_DECLARE(apr_status_t) apr_procattr_constrain_handle_set(apr_procattr_t *attr, ++ apr_int32_t constrain) ++{ ++ return APR_SUCCESS; ++} ++ + APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) + { + int pid; +diff --git a/threadproc/unix/proc.c b/threadproc/unix/proc.c +index 004772f..c3a4e1d 100644 +--- a/threadproc/unix/proc.c ++++ b/threadproc/unix/proc.c +@@ -20,11 +20,17 @@ + #include "apr_signal.h" + #include "apr_random.h" + ++#if defined(LINUX) ++#include ++#endif /* LINUX */ ++ + /* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE + * requested for a specific child handle; + */ + static apr_file_t no_file = { NULL, -1, }; + ++static int max_fd(); ++ + APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, + apr_pool_t *pool) + { +@@ -36,6 +42,8 @@ APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, + (*new)->pool = pool; + (*new)->cmdtype = APR_PROGRAM; + (*new)->uid = (*new)->gid = -1; ++ (*new)->autokill = 0; ++ (*new)->constrain = 0; + return APR_SUCCESS; + } + +@@ -216,6 +224,24 @@ APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + return APR_SUCCESS; + } + ++APR_DECLARE(apr_status_t) apr_procattr_autokill_set(apr_procattr_t *attr, apr_int32_t autokill) ++{ ++#if ! defined(LINUX) ++ return APR_ENOTIMPL; ++ ++#else /* LINUX */ ++ attr->autokill = autokill; ++ return APR_SUCCESS; ++#endif /* LINUX */ ++} ++ ++APR_DECLARE(apr_status_t) apr_procattr_constrain_handle_set(apr_procattr_t *attr, ++ apr_int32_t constrain) ++{ ++ attr->constrain = constrain; ++ return APR_SUCCESS; ++} ++ + APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) + { + int pid; +@@ -349,6 +375,7 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + apr_pool_t *pool) + { + int i; ++ pid_t ppid_before_fork = getpid(); + const char * const empty_envp[] = {NULL}; + + if (!env) { /* Specs require an empty array instead of NULL; +@@ -394,6 +421,34 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + else if (new->pid == 0) { + /* child process */ + ++ /* ++ * On Linux, we can request the OS to notify this new child process ++ * with a specified signal when the parent process terminates. We ++ * choose to be "notified" with a SIGKILL: in other words, when the ++ * parent process terminates, Game Over! This setting persists across ++ * execve(). (Thank you John Dubchak for pointing out this feature.) ++ */ ++#if ! defined(LINUX) ++ (void)ppid_before_fork; ++#else /* LINUX */ ++ if (attr->autokill) { ++ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); ++ /* ++ * possible race condition if parent terminated just before our ++ * prctl() call - http://stackoverflow.com/a/36945270/5533635 ++ */ ++ if (getppid() != ppid_before_fork) { ++ /* ++ * If parent terminated, we get reassigned to init, which has ++ * a different ppid. In that case, we should voluntarily exit ++ * immediately, never mind the execve(). Use a high ++ * termination code because we're pretending we were killed. ++ */ ++ exit(255); ++ } ++ } ++#endif /* LINUX */ ++ + /* + * If we do exec cleanup before the dup2() calls to set up pipes + * on 0-2, we accidentally close the pipes used by programs like +@@ -451,6 +506,16 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + apr_file_close(attr->child_err); + } + ++ /* If constrain was requested, explicitly close all file handles above ++ * STDERR_FILENO, up to max_fd(). ++ */ ++ if (attr->constrain) { ++ int fd, last = max_fd(); ++ for (fd = STDERR_FILENO + 1; fd <= last; ++fd) { ++ close(fd); ++ } ++ } ++ + apr_signal(SIGCHLD, SIG_DFL); /* not sure if this is needed or not */ + + if (attr->currdir != NULL) { +@@ -737,3 +802,24 @@ APR_DECLARE(apr_status_t) apr_procattr_perms_set_register(apr_procattr_t *attr, + + return APR_SUCCESS; + } ++ ++static int max_fd() ++{ ++#if ! defined(LINUX) ++ return 0; ++ ++#else /* LINUX */ ++ int up; ++#if defined(F_MAXFD) ++ do ++ { ++ up = fcntl(0, F_MAXFD); ++ } while (up == -1 && errno == EINTR); ++ if (up == -1) ++#endif /* F_MAXFD */ ++ up = sysconf(_SC_OPEN_MAX); ++ if (up == -1) ++ up = 1000; /* completely arbitrary */ ++ return up; ++#endif /* LINUX */ ++} +diff --git a/threadproc/win32/proc.c b/threadproc/win32/proc.c +index b4dfd5f..f55b7ad 100644 +--- a/threadproc/win32/proc.c ++++ b/threadproc/win32/proc.c +@@ -14,6 +14,16 @@ + * limitations under the License. + */ + ++/* At least for this one compilation, we must have access to STARTUPINFOEX. ++ * That's only defined at _WIN32_WINNT >= 0x0600. ++ */ ++#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600 ++#undef _WIN32_WINNT ++#endif ++#if ! defined(_WIN32_WINNT) ++#define _WIN32_WINNT 0x0600 ++#endif ++ + #include "apr_arch_threadproc.h" + #include "apr_arch_file_io.h" + +@@ -31,6 +41,8 @@ + #if APR_HAVE_PROCESS_H + #include + #endif ++#include "apr_log.h" ++#include + + /* Heavy on no'ops, here's what we want to pass if there is APR_NO_FILE + * requested for a specific child handle; +@@ -71,6 +83,8 @@ APR_DECLARE(apr_status_t) apr_procattr_create(apr_procattr_t **new, + (*new) = (apr_procattr_t *)apr_pcalloc(pool, sizeof(apr_procattr_t)); + (*new)->pool = pool; + (*new)->cmdtype = APR_PROGRAM; ++ (*new)->autokill = 0; ++ (*new)->constrain = 0; + return APR_SUCCESS; + } + +@@ -97,9 +111,11 @@ APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + else { + stat = apr_file_pipe_create_ex(&attr->child_in, &attr->parent_in, + in, attr->pool); ++ if (stat == APR_SUCCESS) ++ stat = apr_file_inherit_unset(attr->parent_in); ++ if (stat == APR_SUCCESS) ++ stat = apr_file_inherit_set(attr->child_in); + } +- if (stat == APR_SUCCESS) +- stat = apr_file_inherit_unset(attr->parent_in); + } + if (out && stat == APR_SUCCESS) { + if (out == APR_NO_FILE) +@@ -107,9 +123,11 @@ APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + else { + stat = apr_file_pipe_create_ex(&attr->parent_out, &attr->child_out, + out, attr->pool); ++ if (stat == APR_SUCCESS) ++ stat = apr_file_inherit_unset(attr->parent_out); ++ if (stat == APR_SUCCESS) ++ stat = apr_file_inherit_set(attr->child_out); + } +- if (stat == APR_SUCCESS) +- stat = apr_file_inherit_unset(attr->parent_out); + } + if (err && stat == APR_SUCCESS) { + if (err == APR_NO_FILE) +@@ -117,9 +135,11 @@ APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr, + else { + stat = apr_file_pipe_create_ex(&attr->parent_err, &attr->child_err, + err, attr->pool); ++ if (stat == APR_SUCCESS) ++ stat = apr_file_inherit_unset(attr->parent_err); ++ if (stat == APR_SUCCESS) ++ stat = apr_file_inherit_set(attr->child_err); + } +- if (stat == APR_SUCCESS) +- stat = apr_file_inherit_unset(attr->parent_err); + } + return stat; + } +@@ -226,6 +246,19 @@ APR_DECLARE(apr_status_t) apr_procattr_detach_set(apr_procattr_t *attr, + return APR_SUCCESS; + } + ++APR_DECLARE(apr_status_t) apr_procattr_autokill_set(apr_procattr_t *attr, apr_int32_t autokill) ++{ ++ attr->autokill = autokill; ++ return APR_SUCCESS; ++} ++ ++APR_DECLARE(apr_status_t) apr_procattr_constrain_handle_set(apr_procattr_t *attr, ++ apr_int32_t constrain) ++{ ++ attr->constrain = constrain; ++ return APR_SUCCESS; ++} ++ + #ifndef _WIN32_WCE + static apr_status_t attr_cleanup(void *theattr) + { +@@ -445,6 +478,18 @@ apr_status_t apr_threadproc_init(apr_pool_t *pool) + + #endif + ++static apr_status_t apr_assign_proc_to_jobobject(HANDLE proc); ++/* Pass a pointer to the PROC_THREAD_ATTRIBUTE_LIST pointer to set. Ideally, ++ * pass &lpAttributeList member of a STARTUPINFOEX struct you will pass to ++ * CreateProcess(). This function initializes a PROC_THREAD_ATTRIBUTE_LIST, ++ * stores its pointer into the passed pointer variable and captures the passed ++ * list of handles. ++ */ ++static apr_status_t apr_set_handle_list(LPPROC_THREAD_ATTRIBUTE_LIST* ppattrlist, ++ DWORD cHandlesToInherit, ++ HANDLE* rgHandlesToInherit); ++static void apr_cleanup_handle_list(LPPROC_THREAD_ATTRIBUTE_LIST* ppattrlist); ++ + APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + const char *progname, + const char * const *args, +@@ -452,7 +497,7 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + apr_procattr_t *attr, + apr_pool_t *pool) + { +- apr_status_t rv; ++ apr_status_t rv = APR_SUCCESS; + apr_size_t i; + const char *argv0; + char *cmdline; +@@ -460,6 +505,22 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + PROCESS_INFORMATION pi; + DWORD dwCreationFlags = 0; + ++ apr_log("apr_proc_create(%s):", apr_logstr(progname)); ++ if (args) ++ { ++ size_t i; ++ apr_log(" args:"); ++ for (i = 0; args[i]; ++i) ++ apr_log(" '%s'", args[i]); ++ } ++ if (env) ++ { ++ size_t i; ++ apr_log(" env:"); ++ for (i = 0; env[i]; ++i) ++ apr_log(" '%s'", env[i]); ++ } ++ + new->in = attr->parent_in; + new->out = attr->parent_out; + new->err = attr->parent_err; +@@ -473,6 +534,7 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + * bit executables if the detached attribute is set. + */ + if (apr_os_level >= APR_WIN_NT) { ++ apr_log(" setting DETACHED_PROCESS"); + /* + * XXX DETACHED_PROCESS won't on Win9x at all; on NT/W2K + * 16 bit executables fail (MS KB: Q150956) +@@ -481,6 +543,46 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + } + } + ++#if 0 ++ // Since Windows 8 / Windows Server 2012, jobs can be nested: ++ // https://learn.microsoft.com/en-us/windows/win32/procthread/nested-jobs ++ // Also, CREATE_BREAKAWAY_FROM_JOB requires JOB_OBJECT_LIMIT_BREAKAWAY_OK. ++ // Without that permission, setting CREATE_BREAKAWAY_FROM_JOB causes ++ // CreateProcessW() to fail with "Access is denied." GitHub Windows ++ // runners obviously run actions within a job that does not permit ++ // JOB_OBJECT_LIMIT_BREAKAWAY_OK: setting this flag fails in that way. ++ // While a process can query its own job limits using ++ // QueryInformationJobObject(), the API is intentionally designed to ++ // discourage updating its own job limits: SetInformationJobObject() ++ // requires a non-NULL job object handle. You can open an existing job ++ // object with a known name, but not all job objects even have names. ++ // Bottom line: ++ // - we might or might not be running with JOB_OBJECT_LIMIT_BREAKAWAY_OK ++ // - we can't explicitly set JOB_OBJECT_LIMIT_BREAKAWAY_OK for ourselves ++ // - without JOB_OBJECT_LIMIT_BREAKAWAY_OK, we can't set CREATE_BREAKAWAY_FROM_JOB ++ // - but on any modern Windows system, we shouldn't need to. ++ if (attr->autokill) // && APR_WIN_NT <= apr_os_level && apr_os_level < APR_WIN_8) ++ { ++ // It's important to pass CREATE_BREAKAWAY_FROM_JOB because Windows 7 et ++ // al. tend to implicitly launch new processes already bound to a job. From ++ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms681949%28v=vs.85%29.aspx : ++ // "The process must not already be assigned to a job; if it is, the ++ // function fails with ERROR_ACCESS_DENIED." ... ++ // "If the process is being monitored by the Program Compatibility ++ // Assistant (PCA), it is placed into a compatibility job. Therefore, the ++ // process must be created using CREATE_BREAKAWAY_FROM_JOB before it can ++ // be placed in another job." ++ ++ // Should test apr_os_level as in the attr->detached logic, but at ++ // what point was CREATE_BREAKAWAY_FROM_JOB introduced? ++ //if (apr_os_level >= APR_WIN_NT?) ++ { ++ apr_log(" setting CREATE_BREAKAWAY_FROM_JOB"); ++ dwCreationFlags |= CREATE_BREAKAWAY_FROM_JOB; ++ } ++ } ++#endif ++ + /* progname must be unquoted, in native format, as there are all sorts + * of bugs in the NT library loader code that fault when parsing '/'. + * XXX progname must be NULL if this is a 16 bit app running in WOW +@@ -642,6 +744,8 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + } + } + } ++ apr_log(" progname: '%s'", apr_logstr(progname)); ++ apr_log(" cmdline: '%s'", apr_logstr(cmdline)); + + if (!env || attr->cmdtype == APR_PROGRAM_ENV || + attr->cmdtype == APR_SHELLCMD_ENV) { +@@ -712,13 +816,17 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + } + #endif /* APR_HAS_ANSI_FS */ + } ++ apr_log(" pEnvBlock is%s NULL", (pEnvBlock? " not" : "")); + + new->invoked = cmdline; + + #if APR_HAS_UNICODE_FS + IF_WIN_OS_IS_UNICODE + { +- STARTUPINFOW si; ++ STARTUPINFOEXW si; ++ HANDLE inherit[3]; /* stdin, stdout, stderr */ ++ DWORD inherit_cnt = 0; /* slots used in 'inherit' */ ++ BOOL bInheritHandles = TRUE; /* like vanilla APR */ + DWORD stdin_reset = 0; + DWORD stdout_reset = 0; + DWORD stderr_reset = 0; +@@ -775,13 +883,20 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + return rv; + } + } ++ apr_log(" wprg: '%ws'", apr_logwstr(wprg)); ++ apr_log(" wcmd: '%ws'", apr_logwstr(wcmd)); ++ apr_log(" wcwd: '%ws'", apr_logwstr(wcwd)); + ++ /* clear ALL of STARTUPINFOEXW... */ + memset(&si, 0, sizeof(si)); +- si.cb = sizeof(si); ++ /* but for the moment, only tell CreateProcessW() about its ++ STARTUPINFOW prefix */ ++ si.StartupInfo.cb = sizeof(STARTUPINFOW); + + if (attr->detached) { +- si.dwFlags |= STARTF_USESHOWWINDOW; +- si.wShowWindow = SW_HIDE; ++ si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; ++ si.StartupInfo.wShowWindow = SW_HIDE; ++ apr_log(" setting STARTF_USESHOWWINDOW, SW_HIDE"); + } + + #ifndef _WIN32_WCE +@@ -794,88 +909,137 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + || (attr->child_out && attr->child_out->filehand) + || (attr->child_err && attr->child_err->filehand)) + { +- si.dwFlags |= STARTF_USESTDHANDLES; ++ si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; ++ apr_log(" setting STARTF_USESTDHANDLES"); + +- si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); ++ si.StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + if (attr->child_in && attr->child_in->filehand) + { +- if (GetHandleInformation(si.hStdInput, ++ if (GetHandleInformation(si.StartupInfo.hStdInput, + &stdin_reset) + && (stdin_reset &= HANDLE_FLAG_INHERIT)) +- SetHandleInformation(si.hStdInput, ++ SetHandleInformation(si.StartupInfo.hStdInput, + HANDLE_FLAG_INHERIT, 0); + +- if ( (si.hStdInput = attr->child_in->filehand) ++ if ( (si.StartupInfo.hStdInput = attr->child_in->filehand) + != INVALID_HANDLE_VALUE ) +- SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT, +- HANDLE_FLAG_INHERIT); ++ { ++ SetHandleInformation(si.StartupInfo.hStdInput, HANDLE_FLAG_INHERIT, ++ HANDLE_FLAG_INHERIT); ++ inherit[inherit_cnt++] = si.StartupInfo.hStdInput; ++ } + } +- +- si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); ++ ++ si.StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + if (attr->child_out && attr->child_out->filehand) + { +- if (GetHandleInformation(si.hStdOutput, ++ if (GetHandleInformation(si.StartupInfo.hStdOutput, + &stdout_reset) + && (stdout_reset &= HANDLE_FLAG_INHERIT)) +- SetHandleInformation(si.hStdOutput, ++ SetHandleInformation(si.StartupInfo.hStdOutput, + HANDLE_FLAG_INHERIT, 0); + +- if ( (si.hStdOutput = attr->child_out->filehand) ++ if ( (si.StartupInfo.hStdOutput = attr->child_out->filehand) + != INVALID_HANDLE_VALUE ) +- SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, +- HANDLE_FLAG_INHERIT); ++ { ++ SetHandleInformation(si.StartupInfo.hStdOutput, HANDLE_FLAG_INHERIT, ++ HANDLE_FLAG_INHERIT); ++ inherit[inherit_cnt++] = si.StartupInfo.hStdOutput; ++ } + } + +- si.hStdError = GetStdHandle(STD_ERROR_HANDLE); ++ si.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (attr->child_err && attr->child_err->filehand) + { +- if (GetHandleInformation(si.hStdError, ++ if (GetHandleInformation(si.StartupInfo.hStdError, + &stderr_reset) + && (stderr_reset &= HANDLE_FLAG_INHERIT)) +- SetHandleInformation(si.hStdError, ++ SetHandleInformation(si.StartupInfo.hStdError, + HANDLE_FLAG_INHERIT, 0); + +- if ( (si.hStdError = attr->child_err->filehand) ++ if ( (si.StartupInfo.hStdError = attr->child_err->filehand) + != INVALID_HANDLE_VALUE ) +- SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT, +- HANDLE_FLAG_INHERIT); ++ { ++ SetHandleInformation(si.StartupInfo.hStdError, HANDLE_FLAG_INHERIT, ++ HANDLE_FLAG_INHERIT); ++ inherit[inherit_cnt++] = si.StartupInfo.hStdError; ++ } + } ++ apr_log(" inherit_cnt = %d", inherit_cnt); + } +- if (attr->user_token) { +- /* XXX: for terminal services, handles can't be cannot be +- * inherited across sessions. This process must be created +- * in our existing session. lpDesktop assignment appears +- * to be wrong according to these rules. +- */ +- si.lpDesktop = L"Winsta0\\Default"; +- if (!ImpersonateLoggedOnUser(attr->user_token)) { +- /* failed to impersonate the logged user */ +- rv = apr_get_os_error(); +- CloseHandle(attr->user_token); +- attr->user_token = NULL; +- LeaveCriticalSection(&proc_lock); +- return rv; ++ ++ /* Only mess with apr_set_handle_list() if caller used our ++ apr_procattr_constrain_handle_set() extension */ ++ if (attr->constrain) ++ { ++ /* Caller wants us to strictly constrain handles passed to child */ ++ if (! inherit_cnt) ++ { ++ /* If 'inherit' is empty, simply turn off bInheritHandles. */ ++ apr_log(" attr->constrain but no handles: bInheritHandles = FALSE"); ++ bInheritHandles = FALSE; ++ } ++ else ++ { ++ apr_log(" attr->constrain with %d handles: " ++ "setting EXTENDED_STARTUPINFO_PRESENT", ++ inherit_cnt); ++ /* We need STARTUPINFOEXW::lpAttributeList. Confess to ++ CreateProcessW() that it's really a STARTUPINFOEXW rather ++ than a vanilla STARTUPINFOW. */ ++ dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT; ++ si.StartupInfo.cb = sizeof(si); ++ /* set specific handle list */ ++ rv = apr_set_handle_list(&si.lpAttributeList, inherit_cnt, inherit); ++ apr_log(" apr_set_handle_list(%d) returned %d", inherit_cnt, rv); + } +- rv = CreateProcessAsUserW(attr->user_token, +- wprg, wcmd, +- attr->sa, +- NULL, +- TRUE, +- dwCreationFlags, +- pEnvBlock, +- wcwd, +- &si, &pi); +- +- RevertToSelf(); + } +- else { +- rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */ +- NULL, NULL, /* Proc & thread security attributes */ +- TRUE, /* Inherit handles */ +- dwCreationFlags, /* Creation flags */ +- pEnvBlock, /* Environment block */ +- wcwd, /* Current directory name */ +- &si, &pi); ++ ++ if (rv == APR_SUCCESS) ++ { ++ if (attr->user_token) { ++ /* XXX: for terminal services, handles can't be cannot be ++ * inherited across sessions. This process must be created ++ * in our existing session. lpDesktop assignment appears ++ * to be wrong according to these rules. ++ */ ++ si.StartupInfo.lpDesktop = L"Winsta0\\Default"; ++ if (!ImpersonateLoggedOnUser(attr->user_token)) { ++ /* failed to impersonate the logged user */ ++ rv = apr_get_os_error(); ++ CloseHandle(attr->user_token); ++ attr->user_token = NULL; ++ } ++ else ++ { ++ apr_log(" CreateProcessAsUserW()"); ++ rv = CreateProcessAsUserW(attr->user_token, ++ wprg, wcmd, ++ attr->sa, ++ NULL, ++ bInheritHandles, ++ dwCreationFlags, ++ pEnvBlock, ++ wcwd, ++ (LPSTARTUPINFOW)(&si), ++ &pi); ++ apr_log(" returned %d", rv); ++ ++ RevertToSelf(); ++ } ++ } ++ else { ++ apr_log(" CreateProcessW()"); ++ rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */ ++ NULL, NULL, /* Proc & thread security attributes */ ++ bInheritHandles, /* Inherit handles */ ++ dwCreationFlags, /* Creation flags */ ++ pEnvBlock, /* Environment block */ ++ wcwd, /* Current directory name */ ++ (LPSTARTUPINFOW)(&si), ++ &pi); ++ apr_log(" returned %d", rv); ++ } + } + + if ((attr->child_in && attr->child_in->filehand) +@@ -900,6 +1064,7 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + LeaveCriticalSection(&proc_lock); + + #else /* defined(_WIN32_WCE) */ ++ apr_log(" _WIN32_WCE CreateProcessW()"); + rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */ + NULL, NULL, /* Proc & thread security attributes */ + FALSE, /* must be 0 */ +@@ -908,47 +1073,101 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + NULL, /* Current directory name must be NULL*/ + NULL, /* STARTUPINFO not supported */ + &pi); ++ apr_log(" returned %d", rv); + #endif ++ ++ /* Clean up si.lpAttributeList if we set it */ ++ apr_log(" apr_cleanup_handle_list()"); ++ apr_cleanup_handle_list(&si.lpAttributeList); ++ apr_log(" okay"); + } + #endif /* APR_HAS_UNICODE_FS */ + #if APR_HAS_ANSI_FS + ELSE_WIN_OS_IS_ANSI + { +- STARTUPINFOA si; ++ STARTUPINFOEXA si; ++ HANDLE inherit[3]; /* stdin, stdout, stderr */ ++ DWORD inherit_cnt = 0; /* slots used in 'inherit' */ ++ BOOL bInheritHandles = TRUE; /* like vanilla APR */ ++ /* clear ALL of STARTUPINFOEXA... */ + memset(&si, 0, sizeof(si)); +- si.cb = sizeof(si); ++ /* but for the moment, only tell CreateProcessA() about its ++ STARTUPINFOA prefix */ ++ si.StartupInfo.cb = sizeof(STARTUPINFOA); + + if (attr->detached) { +- si.dwFlags |= STARTF_USESHOWWINDOW; +- si.wShowWindow = SW_HIDE; ++ si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; ++ si.StartupInfo.wShowWindow = SW_HIDE; ++ apr_log(" setting STARTF_USESHOWWINDOW, SW_HIDE"); + } + + if ((attr->child_in && attr->child_in->filehand) + || (attr->child_out && attr->child_out->filehand) + || (attr->child_err && attr->child_err->filehand)) + { +- si.dwFlags |= STARTF_USESTDHANDLES; ++ si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + +- si.hStdInput = (attr->child_in) ++ si.StartupInfo.hStdInput = (attr->child_in) + ? attr->child_in->filehand + : GetStdHandle(STD_INPUT_HANDLE); ++ inherit[inherit_cnt++] = si.StartupInfo.hStdInput; + +- si.hStdOutput = (attr->child_out) ++ si.StartupInfo.hStdOutput = (attr->child_out) + ? attr->child_out->filehand + : GetStdHandle(STD_OUTPUT_HANDLE); ++ inherit[inherit_cnt++] = si.StartupInfo.hStdOutput; + +- si.hStdError = (attr->child_err) ++ si.StartupInfo.hStdError = (attr->child_err) + ? attr->child_err->filehand + : GetStdHandle(STD_ERROR_HANDLE); ++ inherit[inherit_cnt++] = si.StartupInfo.hStdError; + } + +- rv = CreateProcessA(progname, cmdline, /* Command line */ +- NULL, NULL, /* Proc & thread security attributes */ +- TRUE, /* Inherit handles */ +- dwCreationFlags, /* Creation flags */ +- pEnvBlock, /* Environment block */ +- attr->currdir, /* Current directory name */ +- &si, &pi); ++ /* Only mess with apr_set_handle_list() if caller used our ++ apr_procattr_constrain_handle_set() extension */ ++ if (attr->constrain) ++ { ++ /* Caller wants us to strictly constrain handles passed to child */ ++ if (! inherit_cnt) ++ { ++ /* If 'inherit' is empty, simply turn off bInheritHandles. */ ++ apr_log(" attr->constrain but no handles: bInheritHandles = FALSE"); ++ bInheritHandles = FALSE; ++ } ++ else ++ { ++ apr_log(" attr->constrain with %d handles: " ++ "setting EXTENDED_STARTUPINFO_PRESENT", ++ inherit_cnt); ++ /* We need STARTUPINFOEXA::lpAttributeList. Confess to ++ CreateProcessA() that it's really a STARTUPINFOEXA rather ++ than a vanilla STARTUPINFOA. */ ++ dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT; ++ si.StartupInfo.cb = sizeof(si); ++ /* set specific handle list */ ++ rv = apr_set_handle_list(&si.lpAttributeList, inherit_cnt, inherit); ++ apr_log(" apr_set_handle_list(%d) returned %d", inherit_cnt, rv); ++ } ++ } ++ ++ if (rv == APR_SUCCESS) ++ { ++ apr_log(" CreateProcessA()"); ++ rv = CreateProcessA(progname, cmdline, /* Command line */ ++ NULL, NULL, /* Proc & thread security attributes */ ++ bInheritHandles, /* Inherit handles */ ++ dwCreationFlags, /* Creation flags */ ++ pEnvBlock, /* Environment block */ ++ attr->currdir, /* Current directory name */ ++ (LPSTARTUPINFOA)(&si), ++ &pi); ++ apr_log(" returned %d", rv); ++ } ++ ++ /* Clean up si.lpAttributeList if we set it */ ++ apr_log(" apr_cleanup_handle_list()"); ++ apr_cleanup_handle_list(&si.lpAttributeList); ++ apr_log(" okay"); + } + #endif /* APR_HAS_ANSI_FS */ + +@@ -973,9 +1192,184 @@ APR_DECLARE(apr_status_t) apr_proc_create(apr_proc_t *new, + } + CloseHandle(pi.hThread); + ++ if (attr->autokill) ++ { ++ apr_status_t assigned = APR_SUCCESS; ++ apr_log(" apr_assign_proc_to_jobobject()"); ++ assigned = apr_assign_proc_to_jobobject(new->hproc); ++ apr_log(" returned %d", assigned); ++ if (assigned != APR_SUCCESS) ++ return assigned; ++ } ++ ++ return APR_SUCCESS; ++} ++ ++static apr_status_t apr_assign_proc_to_jobobject(HANDLE proc) ++{ ++ // We only need one Job Object for the calling process. May as well make ++ // it static. ++ static HANDLE sJob = 0; ++ if (! sJob) ++ { ++ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; ++ ++ apr_log(" CreateJobObject(NULL, NULL)"); ++ sJob = CreateJobObject(NULL, NULL); ++ apr_log(" returned %08X", sJob); ++ if (! sJob) ++ return apr_get_os_error(); ++ ++ // Configure all child processes associated with this new job object ++ // to terminate when the calling process (us!) terminates. ++ jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; ++ ++ // For anything lower than Windows 8, set JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK ++ // This is so all processes spawned by CEF will not be put into this job group. This is needed ++ // for sandboxing and stopping Flash from creating a console window. ++ // CEF itself will make sure that all child processes are killed when SLPlugin dies, so there's no negative ++ // side effect. ++ if( !IsWindows8OrGreater() ) ++ jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; ++ // ++ ++ apr_log(" SetInformationJobObject()"); ++ if (! SetInformationJobObject(sJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) ++ { ++ apr_status_t failcode = apr_get_os_error(); ++ apr_log(" failed: %d", failcode); ++ // This Job Object is useless to us ++ CloseHandle(sJob); ++ sJob = 0; ++ return failcode; ++ } ++ apr_log(" okay"); ++ } ++ ++ // Here either sJob was already nonzero, or our calls to create it and set ++ // its info were successful. ++ apr_log(" AssignProcessToJobObject()"); ++ if (! AssignProcessToJobObject(sJob, proc)) ++ { ++ apr_log(" failed"); ++ return apr_get_os_error(); ++ } ++ apr_log(" okay"); ++ + return APR_SUCCESS; + } + ++/* This function is liberally derived from Raymond Chen's ++ * http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx ++ */ ++static apr_status_t apr_set_handle_list(LPPROC_THREAD_ATTRIBUTE_LIST* ppattrlist, ++ DWORD cHandlesToInherit, ++ HANDLE* rgHandlesToInherit) ++{ ++ SIZE_T size = 0; ++ DWORD error = 0; ++ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL; ++ ++ *ppattrlist = NULL; ++ ++ apr_log(" cHandlesToInherit = %d", cHandlesToInherit); ++ if (! cHandlesToInherit) ++ return APR_SUCCESS; ++ ++ if (cHandlesToInherit >= (0xFFFFFFFF / sizeof(HANDLE))) { ++ SetLastError(ERROR_INVALID_PARAMETER); ++ return ERROR_INVALID_PARAMETER; ++ } ++ ++ /* "Initializing a PROC_THREAD_ATTRIBUTE_LIST is a two-step affair. First ++ * you call InitializeProcThreadAttributeList() with a NULL attribute list ++ * in order to determine how much memory you need to allocate for a ++ * one-entry attribute list. After allocating the memory, you call ++ * InitializeProcThreadAttributeList() a second time to do the actual ++ * initialization." ++ */ ++ ++ apr_log(" InitializeProcThreadAttributeList() size query"); ++ InitializeProcThreadAttributeList(NULL, 1, 0, &size); ++ error = GetLastError(); ++ if (error != ERROR_INSUFFICIENT_BUFFER) ++ { ++ apr_log(" returned unexpected %d", error); ++ return error; ++ } ++ ++ apr_log(" HeapAlloc(%u)", size); ++ lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)(HeapAlloc(GetProcessHeap(), 0, size)); ++ if (! lpAttributeList) ++ { ++ apr_log(" STATUS_NO_MEMORY"); ++ /* HeapAlloc() is documented to not set GetLastError() info on fail. */ ++ SetLastError(STATUS_NO_MEMORY); ++ return STATUS_NO_MEMORY; ++ } ++ ++ /* Here we have an allocated but uninitialized PROC_THREAD_ATTRIBUTE_LIST. ++ * Do not yet set *ppattrlist: it does our caller no good until ++ * initialized. ++ */ ++ ++ apr_log(" InitializeProcThreadAttributeList() for real"); ++ if (! InitializeProcThreadAttributeList(lpAttributeList, 1, 0, &size)) ++ { ++ error = GetLastError(); ++ apr_log(" returned %d", error); ++ /* clean up allocated but uninitialized memory */ ++ HeapFree(GetProcessHeap(), 0, lpAttributeList); ++ return error; ++ } ++ ++ /* "After creating the attribute list, you set the one entry by calling ++ * UpdateProcThreadAttributeList()." ++ */ ++ ++ apr_log(" UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_HANDLE_LIST, %d)", ++ cHandlesToInherit * sizeof(HANDLE)); ++ if (! UpdateProcThreadAttribute(lpAttributeList, ++ 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, ++ rgHandlesToInherit, ++ cHandlesToInherit * sizeof(HANDLE), NULL, NULL)) ++ { ++ error = GetLastError(); ++ apr_log(" returned %d", error); ++ /* At this point, with lpAttributeList allocated and initialized, we ++ * can use the real cleanup function. ++ */ ++ apr_cleanup_handle_list(&lpAttributeList); ++ return error; ++ } ++ apr_log(" okay"); ++ ++ /* All systems go! Set caller's pointer. */ ++ *ppattrlist = lpAttributeList; ++ return APR_SUCCESS; ++} ++ ++static void apr_cleanup_handle_list(LPPROC_THREAD_ATTRIBUTE_LIST* ppattrlist) ++{ ++ /* An LPPROC_THREAD_ATTRIBUTE_LIST might be in any of three states: ++ * NULL ++ * Allocated but not initialized ++ * Allocated and initialized ++ * We rely on apr_set_handle_list() to only set the caller's ++ * LPPROC_THREAD_ATTRIBUTE_LIST non-NULL if it's both allocated and ++ * initialized. That way we only have to distinguish two cases. ++ */ ++ ++ if (*ppattrlist) ++ { ++ apr_log(" DeleteProcThreadAttributeList()"); ++ DeleteProcThreadAttributeList(*ppattrlist); ++ apr_log(" HeapFree()"); ++ HeapFree(GetProcessHeap(), 0, *ppattrlist); ++ *ppattrlist = NULL; ++ } ++} ++ + static apr_exit_why_e why_from_exit_code(DWORD exit) { + /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how + * this class of failures was determined +diff --git a/user/win32/groupinfo.c b/user/win32/groupinfo.c +index b536569..cd76622 100644 +--- a/user/win32/groupinfo.c ++++ b/user/win32/groupinfo.c +@@ -18,6 +18,7 @@ + #include "apr_portable.h" + #include "apr_user.h" + #include "apr_private.h" ++#include "apr_arch_utf8.h" + #if APR_HAVE_SYS_TYPES_H + #include + #endif +@@ -27,37 +28,44 @@ APR_DECLARE(apr_status_t) apr_gid_get(apr_gid_t *gid, + { + #ifdef _WIN32_WCE + return APR_ENOTIMPL; ++#elif ! UNICODE ++#error Linden apr_gid_get() requires wchar_t support + #else + SID_NAME_USE sidtype; +- char anydomain[256]; +- char *domain; ++ wchar_t anydomain[256]; ++ wchar_t *domain; + DWORD sidlen = 0; +- DWORD domlen = sizeof(anydomain); ++ DWORD domlen = sizeof(anydomain)/sizeof(anydomain[0]); + DWORD rv; +- char *pos; ++ wchar_t *pos; + +- if ((pos = strchr(groupname, '/'))) { +- domain = apr_pstrmemdup(p, groupname, pos - groupname); +- groupname = pos + 1; +- } +- else if ((pos = strchr(groupname, '\\'))) { +- domain = apr_pstrmemdup(p, groupname, pos - groupname); +- groupname = pos + 1; ++ /* convert UTF8 groupname to wchar_t */ ++ wchar_t wgroupname[256], *pgroupname; ++ apr_size_t groupname_len = strlen(groupname); ++ apr_size_t wgroupname_size = sizeof(wgroupname)/sizeof(wgroupname[0]); ++ apr_conv_utf8_to_ucs2(groupname, &groupname_len, wgroupname, &wgroupname_size); ++ ++ if ((pos = wcschr(wgroupname, L'/')) || ++ (pos = wcschr(wgroupname, L'\\'))) { ++ *pos = L'\0'; ++ domain = wgroupname; ++ pgroupname = pos + 1; + } + else { + domain = NULL; ++ pgroupname = wgroupname; + } + /* Get nothing on the first pass ... need to size the sid buffer + */ +- rv = LookupAccountName(domain, groupname, domain, &sidlen, +- anydomain, &domlen, &sidtype); ++ rv = LookupAccountNameW(domain, pgroupname, domain, &sidlen, ++ anydomain, &domlen, &sidtype); + if (sidlen) { + /* Give it back on the second pass + */ + *gid = apr_palloc(p, sidlen); +- domlen = sizeof(anydomain); +- rv = LookupAccountName(domain, groupname, *gid, &sidlen, +- anydomain, &domlen, &sidtype); ++ domlen = sizeof(anydomain)/sizeof(anydomain[0]); ++ rv = LookupAccountNameW(domain, pgroupname, *gid, &sidlen, ++ anydomain, &domlen, &sidtype); + } + if (!sidlen || !rv) { + return apr_get_os_error(); +@@ -70,17 +78,26 @@ APR_DECLARE(apr_status_t) apr_gid_name_get(char **groupname, apr_gid_t groupid, + { + #ifdef _WIN32_WCE + *groupname = apr_pstrdup(p, "Administrators"); ++#elif ! UNICODE ++#error Linden apr_gid_name_get() requires wchar_t support + #else + SID_NAME_USE type; +- char name[MAX_PATH], domain[MAX_PATH]; +- DWORD cbname = sizeof(name), cbdomain = sizeof(domain); ++ wchar_t wname[MAX_PATH], domain[MAX_PATH]; ++ DWORD cbname = sizeof(wname)/sizeof(wname[0]), cbdomain = sizeof(domain)/sizeof(domain[0]); ++ char name[MAX_PATH]; ++ apr_size_t wname_len; ++ apr_size_t name_size = sizeof(name); ++ + if (!groupid) + return APR_EINVAL; +- if (!LookupAccountSid(NULL, groupid, name, &cbname, domain, &cbdomain, &type)) ++ if (!LookupAccountSidW(NULL, groupid, wname, &cbname, domain, &cbdomain, &type)) + return apr_get_os_error(); + if (type != SidTypeGroup && type != SidTypeWellKnownGroup + && type != SidTypeAlias) + return APR_EINVAL; ++ /* convert returned wname from wchar_t to char */ ++ wname_len = wcslen(wname); ++ apr_conv_ucs2_to_utf8(wname, &wname_len, name, &name_size); + *groupname = apr_pstrdup(p, name); + #endif + return APR_SUCCESS; +diff --git a/user/win32/userinfo.c b/user/win32/userinfo.c +index 89f9b8c..0a3b356 100644 +--- a/user/win32/userinfo.c ++++ b/user/win32/userinfo.c +@@ -19,6 +19,7 @@ + #include "apr_portable.h" + #include "apr_user.h" + #include "apr_arch_file_io.h" ++#include "apr_arch_utf8.h" + #if APR_HAVE_SYS_TYPES_H + #include + #endif +@@ -95,10 +96,13 @@ APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + strcpy(regkey, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\" + "ProfileList\\"); + keylen = (DWORD)strlen(regkey); ++ /* Because this code path is only for Windows older than NT, we do not ++ care about the possibility of a non-ASCII username here. */ + apr_cpystrn(regkey + keylen, username, sizeof(regkey) - keylen); + } + +- if ((rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey, 0, ++ /* regkey is specifically char[], so explicitly call RegOpenKeyExA() */ ++ if ((rv = RegOpenKeyExA(HKEY_LOCAL_MACHINE, regkey, 0, + KEY_QUERY_VALUE, &key)) != ERROR_SUCCESS) + return APR_FROM_OS_ERROR(rv); + +@@ -136,7 +140,7 @@ APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + ELSE_WIN_OS_IS_ANSI + { + keylen = sizeof(regkey); +- rv = RegQueryValueEx(key, "ProfileImagePath", NULL, &type, ++ rv = RegQueryValueExA(key, "ProfileImagePath", NULL, &type, + (void*)regkey, &keylen); + RegCloseKey(key); + if (rv != ERROR_SUCCESS) +@@ -146,7 +150,7 @@ APR_DECLARE(apr_status_t) apr_uid_homepath_get(char **dirname, + } + else if (type == REG_EXPAND_SZ) { + char path[MAX_PATH]; +- ExpandEnvironmentStrings(regkey, path, sizeof(path)); ++ ExpandEnvironmentStringsA(regkey, path, sizeof(path)); + *dirname = apr_pstrdup(p, path); + } + else +@@ -213,37 +217,44 @@ APR_DECLARE(apr_status_t) apr_uid_get(apr_uid_t *uid, apr_gid_t *gid, + { + #ifdef _WIN32_WCE + return APR_ENOTIMPL; ++#elif ! UNICODE ++#error Linden apr_uid_get() requires wchar_t support + #else + SID_NAME_USE sidtype; +- char anydomain[256]; +- char *domain; ++ wchar_t anydomain[256]; ++ wchar_t *domain; + DWORD sidlen = 0; +- DWORD domlen = sizeof(anydomain); ++ DWORD domlen = sizeof(anydomain)/sizeof(anydomain[0]); + DWORD rv; +- char *pos; ++ wchar_t *pos; + +- if ((pos = strchr(username, '/'))) { +- domain = apr_pstrmemdup(p, username, pos - username); +- username = pos + 1; +- } +- else if ((pos = strchr(username, '\\'))) { +- domain = apr_pstrmemdup(p, username, pos - username); +- username = pos + 1; ++ /* convert UTF8 username to wchar_t */ ++ wchar_t wusername[256], *pusername; ++ apr_size_t username_len = strlen(username); ++ apr_size_t wusername_size = sizeof(wusername)/sizeof(wusername[0]); ++ apr_conv_utf8_to_ucs2(username, &username_len, wusername, &wusername_size); ++ ++ if ((pos = wcschr(wusername, L'/')) || ++ (pos = wcschr(wusername, L'\\'))) { ++ *pos = L'\0'; ++ domain = wusername; ++ pusername = pos + 1; + } + else { + domain = NULL; ++ pusername = wusername; + } + /* Get nothing on the first pass ... need to size the sid buffer + */ +- rv = LookupAccountName(domain, username, domain, &sidlen, ++ rv = LookupAccountNameW(domain, pusername, domain, &sidlen, + anydomain, &domlen, &sidtype); + if (sidlen) { + /* Give it back on the second pass + */ + *uid = apr_palloc(p, sidlen); +- domlen = sizeof(anydomain); +- rv = LookupAccountName(domain, username, *uid, &sidlen, +- anydomain, &domlen, &sidtype); ++ domlen = sizeof(anydomain)/sizeof(anydomain[0]); ++ rv = LookupAccountNameW(domain, pusername, *uid, &sidlen, ++ anydomain, &domlen, &sidtype); + } + if (!sidlen || !rv) { + return apr_get_os_error(); +@@ -261,16 +272,25 @@ APR_DECLARE(apr_status_t) apr_uid_name_get(char **username, apr_uid_t userid, + #ifdef _WIN32_WCE + *username = apr_pstrdup(p, "Administrator"); + return APR_SUCCESS; ++#elif ! UNICODE ++#error Linden apr_uid_name_get() requires wchar_t support + #else + SID_NAME_USE type; +- char name[MAX_PATH], domain[MAX_PATH]; +- DWORD cbname = sizeof(name), cbdomain = sizeof(domain); ++ wchar_t wname[MAX_PATH], domain[MAX_PATH]; ++ DWORD cbname = sizeof(wname)/sizeof(wname[0]), cbdomain = sizeof(domain)/sizeof(domain[0]); ++ char name[MAX_PATH]; ++ apr_size_t wname_len; ++ apr_size_t name_size = sizeof(name); ++ + if (!userid) + return APR_EINVAL; +- if (!LookupAccountSid(NULL, userid, name, &cbname, domain, &cbdomain, &type)) ++ if (!LookupAccountSidW(NULL, userid, wname, &cbname, domain, &cbdomain, &type)) + return apr_get_os_error(); + if (type != SidTypeUser && type != SidTypeAlias && type != SidTypeWellKnownGroup) + return APR_EINVAL; ++ /* convert returned wname from wchar_t to char */ ++ wname_len = wcslen(wname); ++ apr_conv_ucs2_to_utf8(wname, &wname_len, name, &name_size); + *username = apr_pstrdup(p, name); + return APR_SUCCESS; + #endif diff --git a/indra/vcpkg/ports/apr/portfile.cmake b/indra/vcpkg/ports/apr/portfile.cmake new file mode 100644 index 00000000000..2f29b07f0b4 --- /dev/null +++ b/indra/vcpkg/ports/apr/portfile.cmake @@ -0,0 +1,118 @@ +vcpkg_download_distfile(ARCHIVE + URLS "https://downloads.apache.org/apr/apr-${VERSION}.tar.bz2" + FILENAME "apr-${VERSION}.tar.bz2" + SHA512 629b60680d1244641828019db903a1b199e8a19c8f27a5132b93faacb381ce561f88463345ab019258f1f1e8cfdf8aa986ac815153a8e7e04a22b3932f9fedd2 +) + +vcpkg_extract_source_archive(SOURCE_PATH + ARCHIVE "${ARCHIVE}" + PATCHES + unglue.patch + 0100-add-host-tools-dir.diff + 0200-linden-apr-features.diff +) + +set(CURRENT_HOST_TOOLS_DIR "${CURRENT_HOST_INSTALLED_DIR}/tools/${PORT}") + +set(CROSSCOMPILING_OPTIONS "") +if(VCPKG_CROSSCOMPILING) + list(APPEND CROSSCOMPILING_OPTIONS + "-DUNOFFICIAL_APR_HOST_TOOLS_DIR=${CURRENT_HOST_TOOLS_DIR}" + "-DUNOFFICIAL_APR_HOST_EXECUTABLE_SUFFIX=${VCPKG_HOST_EXECUTABLE_SUFFIX}" + ) +endif() + +if (VCPKG_TARGET_IS_WINDOWS) + vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + private-headers APR_INSTALL_PRIVATE_H + ) + + string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" APR_BUILD_STATIC) + string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" APR_BUILD_SHARED) + + vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DAPR_BUILD_STATIC=${APR_BUILD_STATIC} + -DAPR_BUILD_SHARED=${APR_BUILD_SHARED} + -DAPR_BUILD_TESTAPR=OFF + -DINSTALL_PDB=OFF + -DMIN_WINDOWS_VER=Windows7 + -DAPR_HAVE_IPV6=ON + ${FEATURE_OPTIONS} + ${CROSSCOMPILING_OPTIONS} + ) + + vcpkg_cmake_install() + vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/apr") + file( + INSTALL "${CMAKE_CURRENT_LIST_DIR}/unofficial-apr-config.cmake" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/unofficial-apr" + ) + # There is no way to suppress installation of the headers in debug builds. + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + vcpkg_copy_tools(TOOL_NAMES gen_test_char AUTO_CLEAN) + + vcpkg_copy_pdbs() + + file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage-cmake" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME usage) +else() + # To cross-compile you will need a triplet file that locates the tool chain and sets --host and --cache parameters of "./configure". + # The ${VCPKG_PLATFORM_TOOLSET}.cache file must have been generated on the targeted host using "./configure -C". + # For example, to target aarch64-linux-gnu, triplets/aarch64-linux-gnu.cmake should contain (beyond the standard content): + # set(VCPKG_PLATFORM_TOOLSET aarch64-linux-gnu) + # set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE ${MY_CROSS_DIR}/cmake/Toolchain-${VCPKG_PLATFORM_TOOLSET}.cmake) + # set(CONFIGURE_PARAMETER_1 --host=${VCPKG_PLATFORM_TOOLSET}) + # set(CONFIGURE_PARAMETER_2 --cache-file=${MY_CROSS_DIR}/autoconf/${VCPKG_PLATFORM_TOOLSET}.cache) + if(CONFIGURE_PARAMETER_1) + message(STATUS "Configuring apr with ${CONFIGURE_PARAMETER_1} ${CONFIGURE_PARAMETER_2} ${CONFIGURE_PARAMETER_3}") + else() + message(STATUS "Configuring apr") + endif() + set(ENV{CFLAGS} "$ENV{CFLAGS} -Wno-error=implicit-function-declaration") + vcpkg_configure_make( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + "--prefix=${CURRENT_INSTALLED_DIR}" + "${CONFIGURE_PARAMETER_1}" + "${CONFIGURE_PARAMETER_2}" + "${CONFIGURE_PARAMETER_3}" + ) + + vcpkg_install_make() + + if(NOT VCPKG_BUILD_TYPE) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/apr-1.pc" + "-lapr-\${APR_MAJOR_VERSION}" "-lapr-1" + ) + endif() + + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/apr-1.pc" + "-lapr-\${APR_MAJOR_VERSION}" "-lapr-1" + ) + vcpkg_fixup_pkgconfig(SYSTEM_LIBRARIES pthread rt dl uuid crypt) + + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/tools/${PORT}/bin/apr-1-config" "\"${CURRENT_INSTALLED_DIR}\"" "$(realpath \"`dirname $0`/../../..\")") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/tools/${PORT}/bin/apr-1-config" "APR_SOURCE_DIR=\"${SOURCE_PATH}\"" "") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/tools/${PORT}/bin/apr-1-config" "APR_BUILD_DIR=\"${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel\"" "") + + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/build-1/libtool" "${CURRENT_INSTALLED_DIR}/lib" "" IGNORE_UNCHANGED) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/build-1/libtool" "${CURRENT_INSTALLED_DIR}/debug/lib" "" IGNORE_UNCHANGED) + + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/build-1/apr_rules.mk" "${CURRENT_INSTALLED_DIR}" "$(INCLUDE)/..") + if(NOT VCPKG_BUILD_TYPE) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/tools/${PORT}/debug/bin/apr-1-config" "\"${CURRENT_INSTALLED_DIR}/debug\"" "$(realpath \"`dirname $0`/../../../..\")") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/tools/${PORT}/debug/bin/apr-1-config" "APR_SOURCE_DIR=\"${SOURCE_PATH}\"" "") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/tools/${PORT}/debug/bin/apr-1-config" "APR_BUILD_DIR=\"${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg\"" "") + + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/build-1/libtool" "${CURRENT_INSTALLED_DIR}/lib" "" IGNORE_UNCHANGED) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/build-1/libtool" "${CURRENT_INSTALLED_DIR}/debug/lib" "" IGNORE_UNCHANGED) + + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/build-1/apr_rules.mk" "${CURRENT_INSTALLED_DIR}/debug" "$(INCLUDE)/..") + endif() + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share") +endif() + +# Handle copyright +file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/indra/vcpkg/ports/apr/unglue.patch b/indra/vcpkg/ports/apr/unglue.patch new file mode 100644 index 00000000000..0ce518b8a7c --- /dev/null +++ b/indra/vcpkg/ports/apr/unglue.patch @@ -0,0 +1,17 @@ +diff --git a/include/apr_version.h b/include/apr_version.h +index e96de3835..de3437d71 100644 +--- a/include/apr_version.h ++++ b/include/apr_version.h +@@ -114,9 +114,9 @@ + + /** An alternative formatted string of APR's version */ + /* macro for Win32 .rc files using numeric csv representation */ +-#define APR_VERSION_STRING_CSV APR_MAJOR_VERSION ##, \ +- ##APR_MINOR_VERSION ##, \ +- ##APR_PATCH_VERSION ++#define APR_VERSION_STRING_CSV APR_MAJOR_VERSION , \ ++ APR_MINOR_VERSION , \ ++ APR_PATCH_VERSION + + + #ifndef APR_VERSION_ONLY diff --git a/indra/vcpkg/ports/apr/unofficial-apr-config.cmake b/indra/vcpkg/ports/apr/unofficial-apr-config.cmake new file mode 100644 index 00000000000..6ac78b99b68 --- /dev/null +++ b/indra/vcpkg/ports/apr/unofficial-apr-config.cmake @@ -0,0 +1,19 @@ +message(WARNING "find_package(unofficial-apr) is deprecated.\nUse find_package(apr) instead") +include(CMakeFindDependencyMacro) +find_dependency(apr CONFIG) + +if(TARGET apr::apr-1 AND NOT TARGET unofficial::apr::apr-1) + add_library(unofficial::apr::apr-1 INTERFACE IMPORTED) + target_link_libraries(unofficial::apr::apr-1 INTERFACE apr::apr-1) +elseif(TARGET apr::libapr-1 AND NOT TARGET unofficial::apr::libapr-1) + add_library(unofficial::apr::libapr-1 INTERFACE IMPORTED) + target_link_libraries(unofficial::apr::libapr-1 INTERFACE apr::libapr-1) +endif() + +if(TARGET apr::aprapp-1 AND NOT TARGET unofficial::apr::aprapp-1) + add_library(unofficial::apr::aprapp-1 INTERFACE IMPORTED) + target_link_libraries(unofficial::apr::aprapp-1 INTERFACE apr::aprapp-1) +elseif(TARGET apr::libaprapp-1 AND NOT TARGET unofficial::apr::libaprapp-1) + add_library(unofficial::apr::libaprapp-1 INTERFACE IMPORTED) + target_link_libraries(unofficial::apr::libaprapp-1 INTERFACE apr::libaprapp-1) +endif() diff --git a/indra/vcpkg/ports/apr/usage-cmake b/indra/vcpkg/ports/apr/usage-cmake new file mode 100644 index 00000000000..df70f0ade4b --- /dev/null +++ b/indra/vcpkg/ports/apr/usage-cmake @@ -0,0 +1,19 @@ +APR provides CMake targets whose names will start with the 'lib' prefix in shared configurations, while static configurations will not: + + find_package(apr CONFIG REQUIRED) + + # Use the shared configuration + target_link_libraries(main PRIVATE apr::apr-1 apr::libaprapp-1) + + # Use the static configuration + target_link_libraries(main PRIVATE apr::apr-1 apr::aprapp-1) + +To ensure compatibility with both static and shared configurations: + + find_package(apr CONFIG REQUIRED) + target_link_libraries(main PRIVATE + $<$:apr::apr-1> + $<$:apr::aprapp-1> + $<$:apr::libapr-1> + $<$:apr::libaprapp-1> + ) diff --git a/indra/vcpkg/ports/apr/vcpkg.json b/indra/vcpkg/ports/apr/vcpkg.json new file mode 100644 index 00000000000..13c8e15caa0 --- /dev/null +++ b/indra/vcpkg/ports/apr/vcpkg.json @@ -0,0 +1,30 @@ +{ + "name": "apr", + "version": "1.7.6", + "description": "The Apache Portable Runtime (APR) is a C library that forms a system portability layer that covers many operating systems.", + "homepage": "https://apr.apache.org/", + "license": "Apache-2.0", + "supports": "!uwp & !mingw", + "dependencies": [ + { + "name": "apr", + "host": true, + "platform": "windows" + }, + { + "name": "vcpkg-cmake", + "host": true, + "platform": "windows" + }, + { + "name": "vcpkg-cmake-config", + "host": true, + "platform": "windows" + } + ], + "features": { + "private-headers": { + "description": "Install non-standard files required for building Apache httpd" + } + } +} diff --git a/indra/vcpkg/ports/bugsplat-apple/portfile.cmake b/indra/vcpkg/ports/bugsplat-apple/portfile.cmake new file mode 100644 index 00000000000..1741f534731 --- /dev/null +++ b/indra/vcpkg/ports/bugsplat-apple/portfile.cmake @@ -0,0 +1,42 @@ +set(VCPKG_POLICY_EMPTY_INCLUDE_FOLDER enabled) +set(VCPKG_FIXUP_MACHO_RPATH OFF) + +# fetch 3p-bugsplat for upload scripts +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO secondlife/3p-bugsplat + REF v1.2.6-a475cbb + SHA512 408ff7160c7596e8e005b9e9e85f87b727fc5068c0a7966643ea157fdd7a3ef24a402f1757096ac9078016708281d8727c42e5b8ed067c0c9577a40f6dbce31a + HEAD_REF main +) + +vcpkg_download_distfile( + BUGSPLAT_ARCHIVE + URLS https://github.com/BugSplat-Git/bugsplat-apple/releases/download/v2.0.0/BugSplat.xcframework.zip + FILENAME dullahan-windows64.tar.zst + SHA512 7934435679d021404b3929749008ba6d42725136b1eb156f7e45a915d9c3a728759edf60875e3baa02e54c2a7c90f7a84646ec03b131b500b2213dfed60e08cb +) + +vcpkg_extract_source_archive( + BUGSPLAT_DIR + ARCHIVE ${BUGSPLAT_ARCHIVE} + NO_REMOVE_ONE_LEVEL +) + +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib") +vcpkg_execute_required_process( + COMMAND cp -a "${BUGSPLAT_DIR}/BugSplat.xcframework/macos-arm64_x86_64/BugSplatMac.framework" "${CURRENT_PACKAGES_DIR}/lib/BugSplatMac.framework" + WORKING_DIRECTORY ${CURRENT_BUILDTREES_DIR} + LOGNAME build-${TARGET_TRIPLET}-dbg +) + +vcpkg_execute_required_process( + COMMAND cp -a "${BUGSPLAT_DIR}/BugSplat.xcframework/macos-arm64_x86_64/dSYMs/BugSplatMac.framework.dSYM" "${CURRENT_PACKAGES_DIR}/lib/BugSplatMac.framework.dSYM" + WORKING_DIRECTORY ${CURRENT_BUILDTREES_DIR} + LOGNAME build-${TARGET_TRIPLET}-dbg +) + +file(INSTALL "${SOURCE_PATH}/upload-archive.sh" DESTINATION "${CURRENT_PACKAGES_DIR}/tools/upload-extensions/") +file(INSTALL "${SOURCE_PATH}/upload-mac-symbols.sh" DESTINATION "${CURRENT_PACKAGES_DIR}/tools/upload-extensions/") + +file(INSTALL "${SOURCE_PATH}/BugSplat/BUGSPLAT_LICENSE.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/indra/vcpkg/ports/bugsplat-apple/vcpkg.json b/indra/vcpkg/ports/bugsplat-apple/vcpkg.json new file mode 100644 index 00000000000..2253d61d3e3 --- /dev/null +++ b/indra/vcpkg/ports/bugsplat-apple/vcpkg.json @@ -0,0 +1,7 @@ +{ + "name": "bugsplat-apple", + "version-string": "2.0.0", + "description": "Bugsplat crash reporting framework for windows", + "homepage": "https://github.com/secondlife/3p-bugsplat", + "supports": "osx" +} diff --git a/indra/vcpkg/ports/bugsplat/portfile.cmake b/indra/vcpkg/ports/bugsplat/portfile.cmake new file mode 100644 index 00000000000..d0e04d5355b --- /dev/null +++ b/indra/vcpkg/ports/bugsplat/portfile.cmake @@ -0,0 +1,81 @@ +set(VCPKG_POLICY_DLLS_WITHOUT_EXPORTS enabled) + +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO secondlife/3p-bugsplat + REF v1.2.6-a475cbb + SHA512 408ff7160c7596e8e005b9e9e85f87b727fc5068c0a7966643ea157fdd7a3ef24a402f1757096ac9078016708281d8727c42e5b8ed067c0c9577a40f6dbce31a + HEAD_REF main +) + +file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/inc/" + DESTINATION "${CURRENT_PACKAGES_DIR}/include/bugsplat/" + FILES_MATCHING + PATTERN "*.h" +) + +file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/lib/" + FILES_MATCHING + PATTERN "*.lib" +) + +file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/bin/" + FILES_MATCHING + PATTERN "*.dll" +) + +file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/bin/" + FILES_MATCHING + PATTERN "*.pdb" +) + +file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/tools/" + FILES_MATCHING + PATTERN "*.exe" +) + +if(NOT (VCPKG_BUILD_TYPE STREQUAL "release")) + file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Debug/" + DESTINATION "${CURRENT_PACKAGES_DIR}/debug/lib/" + FILES_MATCHING + PATTERN "*.lib" + ) + + file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Debug/" + DESTINATION "${CURRENT_PACKAGES_DIR}/debug/bin/" + FILES_MATCHING + PATTERN "*.dll" + ) + + file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Debug/" + DESTINATION "${CURRENT_PACKAGES_DIR}/debug/bin/" + FILES_MATCHING + PATTERN "*.pdb" + ) + + file(INSTALL + DIRECTORY "${SOURCE_PATH}/BugSplat/BugSplat/x64/Debug/" + DESTINATION "${CURRENT_PACKAGES_DIR}/debug/tools/" + FILES_MATCHING + PATTERN "*.exe" + ) +endif() + + +file(INSTALL "${SOURCE_PATH}/BugSplat/Tools/symbol-upload-windows.exe" DESTINATION "${CURRENT_PACKAGES_DIR}/tools") +file(INSTALL "${SOURCE_PATH}/upload-windows-symbols.sh" DESTINATION "${CURRENT_PACKAGES_DIR}/tools/upload-extensions/") +file(INSTALL "${SOURCE_PATH}/SendPdbs.bat" DESTINATION "${CURRENT_PACKAGES_DIR}/tools/upload-extensions/") + +file(INSTALL "${SOURCE_PATH}/BugSplat/BUGSPLAT_LICENSE.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/indra/vcpkg/ports/bugsplat/vcpkg.json b/indra/vcpkg/ports/bugsplat/vcpkg.json new file mode 100644 index 00000000000..d9cdd9122bf --- /dev/null +++ b/indra/vcpkg/ports/bugsplat/vcpkg.json @@ -0,0 +1,7 @@ +{ + "name": "bugsplat", + "version-string": "6.1.1.0", + "description": "Bugsplat crash reporting framework for windows", + "homepage": "https://github.com/secondlife/3p-bugsplat", + "supports": "windows & x64" +} diff --git a/indra/vcpkg/ports/collada-dom/portfile.cmake b/indra/vcpkg/ports/collada-dom/portfile.cmake new file mode 100644 index 00000000000..541f27195b2 --- /dev/null +++ b/indra/vcpkg/ports/collada-dom/portfile.cmake @@ -0,0 +1,48 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO RyeMutt/3p-colladadom + REF b8da6cd54083bf24dff3ac03be465e710c135195 + SHA512 bb5e6c09777d0dfd0093ff99f4114873bec7c0094e4ec15594d188c0a2bf44a0fffbcf91dfa3c4f73a924f32e6fe3eb0cf1cbe4053a6bb40979e9c2962f649b1 + HEAD_REF master + # PATCHES + # use-vcpkg-minizip.patch +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + -DCMAKE_CXX_STANDARD=17 +) + +vcpkg_cmake_install() + +if(VCPKG_LIBRARY_LINKAGE MATCHES "dynamic" AND VCPKG_TARGET_IS_WINDOWS) + set(RELEASE_COLLADA_DLL "${CURRENT_PACKAGES_DIR}/lib/collada14dom.dll") + if(EXISTS ${RELEASE_COLLADA_DLL}) + file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/bin") + file(RENAME ${RELEASE_COLLADA_DLL} "${CURRENT_PACKAGES_DIR}/bin/collada14dom.dll") + endif() + set(DEBUG_COLLADA_DLL "${CURRENT_PACKAGES_DIR}/debug/lib/collada14dom.dll") + if(EXISTS ${DEBUG_COLLADA_DLL}) + file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/debug/bin") + file(RENAME ${DEBUG_COLLADA_DLL} "${CURRENT_PACKAGES_DIR}/debug/bin/collada14dom.dll") + endif() +endif() + +if(VCPKG_LIBRARY_LINKAGE MATCHES "static" AND (VCPKG_TARGET_IS_OSX OR VCPKG_TARGET_IS_LINUX)) + if(EXISTS "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/src/1.4/libcollada14dom.a") + file(INSTALL "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/src/1.4/libcollada14dom.a" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") + endif() + if(EXISTS "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg/src/1.4/libcollada14dom.a") + file(INSTALL "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg/src/1.4/libcollada14dom.a" DESTINATION "${CURRENT_PACKAGES_DIR}/debug/lib") + endif() +endif() + +#vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/collada-dom-2.5) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +# Handle copyright +file(INSTALL "${SOURCE_PATH}/license.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) + +vcpkg_fixup_pkgconfig() diff --git a/indra/vcpkg/ports/collada-dom/use-vcpkg-minizip.patch b/indra/vcpkg/ports/collada-dom/use-vcpkg-minizip.patch new file mode 100644 index 00000000000..c1410cc1156 --- /dev/null +++ b/indra/vcpkg/ports/collada-dom/use-vcpkg-minizip.patch @@ -0,0 +1,27 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index db8db6a..896ee27 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -218,7 +218,8 @@ else() + endif() + endif() + +-pkg_check_modules(minizip minizip) ++find_package(minizip NAMES unofficial-minizip REQUIRED) ++add_library(minizip ALIAS unofficial::minizip::minizip) + if(minizip_FOUND) + set(MINIZIP_INCLUDE_DIR ${minizip_INCLUDE_DIRS}) + else() +diff --git a/dom/include/dae/daeZAEUncompressHandler.h b/dom/include/dae/daeZAEUncompressHandler.h +index e9b0e9e..3d120da 100644 +--- a/dom/include/dae/daeZAEUncompressHandler.h ++++ b/dom/include/dae/daeZAEUncompressHandler.h +@@ -9,7 +9,7 @@ + #ifndef __DAE_ZAE_UNCOMPRESS_HANDLER_H__ + #define __DAE_ZAE_UNCOMPRESS_HANDLER_H__ + +-#include ++#include <../minizip/unzip.h> + #include + #include + diff --git a/indra/vcpkg/ports/collada-dom/vcpkg.json b/indra/vcpkg/ports/collada-dom/vcpkg.json new file mode 100644 index 00000000000..6ece87231b2 --- /dev/null +++ b/indra/vcpkg/ports/collada-dom/vcpkg.json @@ -0,0 +1,28 @@ +{ + "name": "collada-dom", + "version": "2.3.2", + "port-version": 1, + "description": "The COLLADA Document Object Model (DOM) is an application programming interface (API) that provides a C++ object representation of a COLLADA XML instance document.", + "homepage": "https://github.com/secondlife/3p-collada-dom", + "license": "MIT", + "dependencies": [ + "boost-filesystem", + "boost-regex", + "boost-uuid", + "libxml2", + "minizip", + { + "name": "pkgconf", + "platform": "windows | osx" + }, + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + }, + "zlib" + ] +} diff --git a/indra/vcpkg/ports/curl/0001_cmake.patch b/indra/vcpkg/ports/curl/0001_cmake.patch new file mode 100644 index 00000000000..db281e122e9 --- /dev/null +++ b/indra/vcpkg/ports/curl/0001_cmake.patch @@ -0,0 +1,13 @@ +diff --git a/CMake/FindLibSSH2.cmake b/CMake/FindLibSSH2.cmake +index 12a7c61..9839c67 100644 +--- a/CMake/FindLibSSH2.cmake ++++ b/CMake/FindLibSSH2.cmake +@@ -12,7 +12,7 @@ endif (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) + FIND_PATH(LIBSSH2_INCLUDE_DIR libssh2.h + ) + +-FIND_LIBRARY(LIBSSH2_LIBRARY NAMES ssh2 ++FIND_LIBRARY(LIBSSH2_LIBRARY NAMES ssh2 libssh2 + ) + + if(LIBSSH2_INCLUDE_DIR) diff --git a/indra/vcpkg/ports/curl/0002_cmake.patch b/indra/vcpkg/ports/curl/0002_cmake.patch new file mode 100644 index 00000000000..307abf06278 --- /dev/null +++ b/indra/vcpkg/ports/curl/0002_cmake.patch @@ -0,0 +1,36 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index d2e1c2bb63..d00237ea97 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -225,7 +225,7 @@ if(ENABLE_MANUAL) + endif() + endif() + # Required for building manual, docs, tests +-find_package(Perl REQUIRED) ++#find_package(Perl REQUIRED) + + # We need ansi c-flags, especially on HP + set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}") +diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt +index eb2de6d87a..b48cc48f00 100644 +--- a/lib/CMakeLists.txt ++++ b/lib/CMakeLists.txt +@@ -96,12 +96,12 @@ endif() + set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") + set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") + +-if(WIN32) +- if(NOT CURL_STATICLIB) +- # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib" +- set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib") +- endif() +-endif() ++# if(WIN32) ++# if(NOT CURL_STATICLIB) ++# # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib" ++# set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib") ++# endif() ++# endif() + + install(TARGETS ${LIB_NAME} + ARCHIVE DESTINATION lib diff --git a/indra/vcpkg/ports/curl/0003_linden_pipeline.patch b/indra/vcpkg/ports/curl/0003_linden_pipeline.patch new file mode 100644 index 00000000000..6a67717d802 --- /dev/null +++ b/indra/vcpkg/ports/curl/0003_linden_pipeline.patch @@ -0,0 +1,93 @@ +diff --git a/lib/multi.c b/lib/multi.c +index c3a0d122cb..a7f870aef5 100644 +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -400,6 +400,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, + /* Point to the multi's connection cache */ + data->state.conn_cache = &multi->conn_cache; + ++ data->state.infilesize = data->set.filesize; ++ + /* This adds the new entry at the 'end' of the doubly-linked circular + list of Curl_easy structs to try and maintain a FIFO queue so + the pipelined requests are in order. */ +@@ -1394,7 +1396,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, + stream_error = TRUE; + } + result = CURLE_OPERATION_TIMEDOUT; +- (void)multi_done(&data->easy_conn, result, TRUE); ++ /* Linden 1420 */ ++ /* https://curl.haxx.se/mail/tracker-2014-10/0040.html */ ++ if(data->easy_conn) { ++ infof(data, "Request timed out. Signal all requests on connection.\n"); ++ data->easy_conn->bits.poisoned_1420 = TRUE; ++ Curl_posttransfer(data); ++ multi_done(&data->easy_conn, result, FALSE); ++ } else { ++ (void)multi_done(&data->easy_conn, result, TRUE); ++ } + /* Skip the statemachine and go directly to error handling section. */ + goto statemachine_end; + } +@@ -1811,6 +1822,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, + multistate(data, CURLM_STATE_PERFORM); + rc = CURLM_CALL_MULTI_PERFORM; + } ++#ifdef DEBUGBUILD ++ else { ++ infof(data, "WAITPERFORM: Conn %ld recv pipe %zu inuse %s\n", ++ data->easy_conn->connection_id, ++ data->easy_conn->recv_pipe.size, ++ data->easy_conn->readchannel_inuse?"TRUE":"FALSE"); ++ } ++#endif + break; + + case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */ +@@ -2688,7 +2707,7 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi, + multi->push_userp = va_arg(param, void *); + break; + case CURLMOPT_PIPELINING: +- multi->pipelining = va_arg(param, long); ++ multi->pipelining = (0 != va_arg(param, long)) ? CURLPIPE_HTTP1 : 0L; + break; + case CURLMOPT_TIMERFUNCTION: + multi->timer_cb = va_arg(param, curl_multi_timer_callback); +diff --git a/lib/url.c b/lib/url.c +index 87446dbca3..f9359ec418 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -3143,8 +3143,8 @@ static int IsPipeliningPossible(const struct Curl_easy *handle, + + /* If a HTTP protocol and pipelining is enabled */ + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && +- (!conn->bits.protoconnstart || !conn->bits.close)) { +- ++ (!conn->bits.protoconnstart || !conn->bits.close) && ++ (!conn->bits.poisoned_1420)) { /* Linden 1420 */ + if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && + (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && + (handle->set.httpreq == HTTPREQ_GET || +@@ -4217,7 +4217,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) + conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE; + conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; + conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; +- ++ conn->bits.poisoned_1420 = FALSE; /* Linden 1420 */ ++ + conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; + conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; + conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; +diff --git a/lib/urldata.h b/lib/urldata.h +index d4a4a98dcd..edd5344b3c 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -574,6 +574,8 @@ struct ConnectBits { + connection */ + bool type_set; /* type= was used in the URL */ + bool multiplex; /* connection is multiplexed */ ++ bool poisoned_1420; /* Linden 1420 - Connection became unusable and must not ++ be considered for pipelining. */ + + bool tcp_fastopen; /* use TCP Fast Open */ + bool tls_enable_npn; /* TLS NPN extension? */ diff --git a/indra/vcpkg/ports/curl/portfile.cmake b/indra/vcpkg/ports/curl/portfile.cmake new file mode 100644 index 00000000000..1a75ac0689d --- /dev/null +++ b/indra/vcpkg/ports/curl/portfile.cmake @@ -0,0 +1,173 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO curl/curl + REF curl-7_54_1 + SHA512 32fe86f7b931ecb2b93742df0e39938bc8bb5bea9fcc1b6d98f9ffd06b7080387cad0b161540130ead656526cdd091feb1c566e72c7d78a9f9c799f2d856704b + HEAD_REF master + PATCHES + 0001_cmake.patch + 0002_cmake.patch + 0003_linden_pipeline.patch +) + +string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" CURL_STATICLIB) + +# Support HTTP2 TLS Download https://curl.haxx.se/ca/cacert.pem rename to curl-ca-bundle.crt, copy it to libcurl.dll location. +set(HTTP2_OPTIONS) +if("http2" IN_LIST FEATURES) + set(HTTP2_OPTIONS -DUSE_NGHTTP2=ON) +endif() + +# SSL +set(USE_OPENSSL OFF) +if("openssl" IN_LIST FEATURES) + set(USE_OPENSSL ON) +endif() + +set(USE_WINSSL OFF) +if("winssl" IN_LIST FEATURES) + if(VCPKG_CMAKE_SYSTEM_NAME AND NOT VCPKG_CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") + message(FATAL_ERROR "winssl is not supported on non-Windows platforms") + endif() + set(USE_WINSSL ON) +endif() + +set(USE_MBEDTLS OFF) +if("mbedtls" IN_LIST FEATURES) + set(USE_MBEDTLS ON) +endif() + +set(USE_SECTRANSP OFF) +set(SECTRANSP_OPTIONS) +if("sectransp" IN_LIST FEATURES) + if(NOT VCPKG_CMAKE_SYSTEM_NAME OR (VCPKG_CMAKE_SYSTEM_NAME AND NOT VCPKG_CMAKE_SYSTEM_NAME STREQUAL "Darwin")) + message(FATAL_ERROR "sectransp is not supported on non-Apple platforms") + endif() + set(USE_SECTRANSP ON) + set(SECTRANSP_OPTIONS + -DCURL_CA_PATH=none + ) +endif() + + +# SSH +set(USE_LIBSSH2 OFF) +if("ssh" IN_LIST FEATURES) + set(USE_LIBSSH2 ON) +endif() + +# HTTP/HTTPS only +# Note that `HTTP_ONLY` curl option disables everything including HTTPS, which is not an option. +set(USE_HTTP_ONLY ON) +if("non-http" IN_LIST FEATURES) + set(USE_HTTP_ONLY OFF) +endif() + +# curl exe +set(BUILD_CURL_EXE OFF) +if("tool" IN_LIST FEATURES) + set(BUILD_CURL_EXE ON) +endif() + +# c-ares +set(USE_ARES OFF) +if("c-ares" IN_LIST FEATURES) + set(USE_ARES ON) +endif() + +# SSPI +set(USE_WINDOWS_SSPI OFF) +if("sspi" IN_LIST FEATURES) + set(USE_WINDOWS_SSPI ON) +endif() + +# UWP targets +set(UWP_OPTIONS) +if(VCPKG_CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") + set(UWP_OPTIONS + -DUSE_WIN32_LDAP=OFF + -DCURL_DISABLE_TELNET=ON + -DENABLE_IPV6=OFF + -DENABLE_UNIX_SOCKETS=OFF + ) +endif() + +vcpkg_configure_cmake( + SOURCE_PATH ${SOURCE_PATH} + PREFER_NINJA + OPTIONS + ${UWP_OPTIONS} + ${SECTRANSP_OPTIONS} + ${HTTP2_OPTIONS} + -DBUILD_TESTING=OFF + -DBUILD_CURL_EXE=${BUILD_CURL_EXE} + -DENABLE_MANUAL=OFF + -DCURL_STATICLIB=${CURL_STATICLIB} + -DCMAKE_USE_OPENSSL=${USE_OPENSSL} + -DCMAKE_USE_WINSSL=${USE_WINSSL} + -DCMAKE_USE_MBEDTLS=${USE_MBEDTLS} + -DCMAKE_USE_LIBSSH2=${USE_LIBSSH2} + -DHTTP_ONLY=${USE_HTTP_ONLY} + -DENABLE_THREADED_RESOLVER=ON + -DCURL_WINDOWS_SSPI=${USE_WINDOWS_SSPI} + OPTIONS_RELEASE + -DBUILD_CURL_EXE=${BUILD_CURL_EXE} + OPTIONS_DEBUG + -DBUILD_CURL_EXE=OFF + -DENABLE_DEBUG=ON +) + +vcpkg_install_cmake() + +# if(EXISTS ${CURRENT_PACKAGES_DIR}/lib/cmake/CURL) +# vcpkg_fixup_cmake_targets(CONFIG_PATH lib/cmake/CURL) +# elseif(EXISTS ${CURRENT_PACKAGES_DIR}/share/curl) +# vcpkg_fixup_cmake_targets() +# else() +# message(FATAL_ERROR "Could not locate the curl config files") +# endif() + +file(INSTALL ${SOURCE_PATH}/COPYING DESTINATION ${CURRENT_PACKAGES_DIR}/share/curl RENAME copyright) +file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/include) + +# the native CMAKE_EXECUTABLE_SUFFIX does not work in portfiles, so emulate it +if(NOT VCPKG_CMAKE_SYSTEM_NAME OR VCPKG_CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") # Windows + set(EXECUTABLE_SUFFIX ".exe") +else() + set(EXECUTABLE_SUFFIX "") +endif() + +if(EXISTS "${CURRENT_PACKAGES_DIR}/bin/curl${EXECUTABLE_SUFFIX}") + file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/tools/curl") + file(RENAME "${CURRENT_PACKAGES_DIR}/bin/curl${EXECUTABLE_SUFFIX}" "${CURRENT_PACKAGES_DIR}/tools/curl/curl${EXECUTABLE_SUFFIX}") + vcpkg_copy_tool_dependencies(${CURRENT_PACKAGES_DIR}/tools/curl) + + if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") + file(READ "${CURRENT_PACKAGES_DIR}/share/curl/CURLTargets-release.cmake" RELEASE_MODULE) + string(REPLACE "\${_IMPORT_PREFIX}/bin/curl${EXECUTABLE_SUFFIX}" "\${_IMPORT_PREFIX}/tools/curl/curl${EXECUTABLE_SUFFIX}" RELEASE_MODULE "${RELEASE_MODULE}") + file(WRITE "${CURRENT_PACKAGES_DIR}/share/curl/CURLTargets-release.cmake" "${RELEASE_MODULE}") + endif() +endif() + +file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/lib/pkgconfig ${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig) +file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/debug/share) + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static") + file(REMOVE_RECURSE ${CURRENT_PACKAGES_DIR}/bin ${CURRENT_PACKAGES_DIR}/debug/bin) +else() + file(REMOVE ${CURRENT_PACKAGES_DIR}/bin/curl-config ${CURRENT_PACKAGES_DIR}/debug/bin/curl-config) +endif() + +file(READ ${CURRENT_PACKAGES_DIR}/include/curl/curl.h CURL_H) +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static") + string(REPLACE "#ifdef CURL_STATICLIB" "#if 1" CURL_H "${CURL_H}") +else() + string(REPLACE "#ifdef CURL_STATICLIB" "#if 0" CURL_H "${CURL_H}") +endif() +file(WRITE ${CURRENT_PACKAGES_DIR}/include/curl/curl.h "${CURL_H}") + +vcpkg_copy_pdbs() + +file(COPY ${CMAKE_CURRENT_LIST_DIR}/usage DESTINATION ${CURRENT_PACKAGES_DIR}/share/${PORT}) + +vcpkg_test_cmake(PACKAGE_NAME CURL MODULE) diff --git a/indra/vcpkg/ports/curl/usage b/indra/vcpkg/ports/curl/usage new file mode 100644 index 00000000000..0b79ebd5571 --- /dev/null +++ b/indra/vcpkg/ports/curl/usage @@ -0,0 +1,5 @@ +The package curl is compatible with built-in CMake targets: + + find_package(CURL REQUIRED) + target_link_libraries(main PRIVATE ${CURL_LIBRARIES}) + target_include_directories(main PRIVATE ${CURL_INCLUDE_DIRS}) diff --git a/indra/vcpkg/ports/curl/vcpkg.json b/indra/vcpkg/ports/curl/vcpkg.json new file mode 100644 index 00000000000..bb0214c7b6b --- /dev/null +++ b/indra/vcpkg/ports/curl/vcpkg.json @@ -0,0 +1,169 @@ +{ + "name": "curl", + "version": "7.54.1", + "description": "A library for transferring data with URLs", + "homepage": "https://curl.se/", + "license": "curl AND ISC AND BSD-3-Clause", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + }, + "zlib" + ], + "default-features": [ + "ssl" + ], + "features": { + "c-ares": { + "description": "c-ares support", + "dependencies": [ + "c-ares" + ] + }, + "http2": { + "description": "HTTP2 support", + "dependencies": [ + { + "name": "curl", + "default-features": false, + "features": [ + "ssl" + ] + }, + "nghttp2" + ] + }, + "httpsrr": { + "description": "enable support for HTTPS RR" + }, + "idn": { + "description": "Default IDN support", + "dependencies": [ + { + "name": "curl", + "default-features": false, + "features": [ + "winidn" + ], + "platform": "windows" + }, + { + "name": "curl", + "default-features": false, + "features": [ + "idn2" + ], + "platform": "!windows" + } + ] + }, + "idn2": { + "description": "idn2 support (libidn2)", + "dependencies": [ + "libidn2" + ] + }, + "ldap": { + "description": "LDAP support", + "supports": "!uwp", + "dependencies": [ + { + "name": "curl", + "default-features": false, + "features": [ + "non-http" + ] + }, + { + "name": "openldap", + "platform": "!windows" + } + ] + }, + "mbedtls": { + "description": "TLS support (mbedTLS)", + "dependencies": [ + "mbedtls" + ] + }, + "non-http": { + "description": "Enables protocols beyond HTTP/HTTPS/HTTP2/HTTP3" + }, + "openssl": { + "description": "TLS support (OpenSSL)", + "dependencies": [ + "openssl" + ] + }, + "rtmp": { + "description": "RTMP support", + "dependencies": [ + "librtmp" + ] + }, + "ssl": { + "description": "Default SSL / TLS implementation.", + "dependencies": [ + { + "$comment": "Defaults to schannel on Windows, unless http3 is also enabled", + "name": "curl", + "default-features": false, + "features": [ + "sspi" + ], + "platform": "(windows & !uwp) | mingw" + }, + { + "$comment": "Otherwise, defaults to OpenSSL.", + "name": "curl", + "default-features": false, + "features": [ + "openssl" + ], + "platform": "(uwp | !windows) & !mingw" + } + ] + }, + "ssls-export": { + "description": "SSL session import/export", + "dependencies": [ + { + "name": "curl", + "default-features": false, + "features": [ + "ssl" + ] + } + ] + }, + "sspi": { + "description": "SSPI support", + "supports": "(windows & !uwp) | mingw" + }, + "tool": { + "description": "Builds curl executable", + "supports": "!uwp" + }, + "winidn": { + "description": "WinIDN support", + "supports": "windows" + }, + "winldap": { + "description": "Obsolete. Use feature 'ldap' instead.", + "dependencies": [ + { + "name": "curl", + "default-features": false, + "features": [ + "ldap" + ] + } + ] + } + } +} diff --git a/indra/vcpkg/ports/dullahan-bin/portfile.cmake b/indra/vcpkg/ports/dullahan-bin/portfile.cmake new file mode 100644 index 00000000000..7903b45d46a --- /dev/null +++ b/indra/vcpkg/ports/dullahan-bin/portfile.cmake @@ -0,0 +1,137 @@ +set(VCPKG_POLICY_ALLOW_EMPTY_FOLDERS enabled) +set(VCPKG_POLICY_MISMATCHED_NUMBER_OF_BINARIES enabled) +set(VCPKG_FIXUP_MACHO_RPATH OFF) +set(VCPKG_FIXUP_ELF_RPATH OFF) + +if(VCPKG_TARGET_IS_WINDOWS) + vcpkg_download_distfile( + DULLAHAN_ARCHIVE + URLS https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161628_139.0.40_g465474a_chromium-139.0.7258.139-windows64-18568015445.tar.zst + FILENAME dullahan-windows64.tar.zst + SHA512 8b2fe2d227c58561ad3159be4feb7682e0a3eece4c8b1ca982759820162d9fcff029ba238219e800296db582370f33d7e02772730f199837b294a58c95aaa36e + ) + + vcpkg_extract_source_archive( + DULLAHAN_DIR + ARCHIVE ${DULLAHAN_ARCHIVE} + NO_REMOVE_ONE_LEVEL + ) + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/include/cef/" + DESTINATION "${CURRENT_PACKAGES_DIR}/include/cef" + FILES_MATCHING + PATTERN "*.h" + ) + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/lib/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/lib" + FILES_MATCHING + PATTERN "*.lib" + ) + + file(INSTALL "${DULLAHAN_DIR}/bin/release/libcef.dll" DESTINATION "${CURRENT_PACKAGES_DIR}/bin") + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/bin/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/bin" + FILES_MATCHING + PATTERN "*.*" + PATTERN "libcef.dll" EXCLUDE + PATTERN "libcef.lib" EXCLUDE + ) + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/resources/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/resources" + FILES_MATCHING + PATTERN "*.*" + ) +elseif(VCPKG_TARGET_IS_OSX) + vcpkg_download_distfile( + DULLAHAN_ARCHIVE + URLS https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139-darwin64-18568015445.tar.zst + FILENAME dullahan-osx.tar.zst + SHA512 e847f119605bd69cc47bf08ca06abfc7e745b5e0e0ccbdd84447b2df5e4852d0de3456ef82ac60fc4cbc4b17622c5300273cbcec496236e1573ed0afa5ea4f3d + ) + + vcpkg_extract_source_archive( + DULLAHAN_DIR + ARCHIVE ${DULLAHAN_ARCHIVE} + NO_REMOVE_ONE_LEVEL + ) + + # Create output directories and move files into place + file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include/") + file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib/") + file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/share/${PORT}/helpers/") + + set(CEF_FRAMEWORK_DIR "${CURRENT_PACKAGES_DIR}/lib/Chromium Embedded Framework.framework") + file(RENAME "${DULLAHAN_DIR}/lib/release/Chromium Embedded Framework.framework" "${CEF_FRAMEWORK_DIR}") + + file(RENAME "${DULLAHAN_DIR}/lib/release/DullahanHelper.app" "${CURRENT_PACKAGES_DIR}/share/${PORT}/helpers/DullahanHelper.app") + file(RENAME "${DULLAHAN_DIR}/lib/release/DullahanHelper (Alerts).app" "${CURRENT_PACKAGES_DIR}/share/${PORT}/helpers/DullahanHelper (Alerts).app") + file(RENAME "${DULLAHAN_DIR}/lib/release/DullahanHelper (GPU).app" "${CURRENT_PACKAGES_DIR}/share/${PORT}/helpers/DullahanHelper (GPU).app") + file(RENAME "${DULLAHAN_DIR}/lib/release/DullahanHelper (Plugin).app" "${CURRENT_PACKAGES_DIR}/share/${PORT}/helpers/DullahanHelper (Plugin).app") + file(RENAME "${DULLAHAN_DIR}/lib/release/DullahanHelper (Renderer).app" "${CURRENT_PACKAGES_DIR}/share/${PORT}/helpers/DullahanHelper (Renderer).app") + + file(INSTALL "${DULLAHAN_DIR}/lib/release/libcef_dll_wrapper.a" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") + file(INSTALL "${DULLAHAN_DIR}/lib/release/libdullahan.a" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/include/cef/" + DESTINATION "${CURRENT_PACKAGES_DIR}/include/cef" + FILES_MATCHING + PATTERN "*.h" + ) +elseif(VCPKG_TARGET_IS_LINUX) + vcpkg_download_distfile( + DULLAHAN_ARCHIVE + URLS https://github.com/secondlife/dullahan/releases/download/v1.26.0-CEF_139.0.40/dullahan-1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139-linux64-18568015445.tar.zst + FILENAME dullahan-osx.tar.zst + SHA512 12177c6dda56a4a91a8cf23748269ce765b794290018c3ae254d0b11430451ead835d9f252cddd7bd258c58502297fafd45252deefdafeb24c8d6e8f7ae6a3ee + ) + + vcpkg_extract_source_archive( + DULLAHAN_DIR + ARCHIVE ${DULLAHAN_ARCHIVE} + NO_REMOVE_ONE_LEVEL + ) + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/lib/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/lib" + USE_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.a" + PATTERN "*.so*" + PATTERN "*.json*" + PATTERN "*.bin*" + ) + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/bin/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/bin" + USE_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "chrome-sandbox" + PATTERN "dullahan_host" + ) + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/include/cef/" + DESTINATION "${CURRENT_PACKAGES_DIR}/include/cef" + FILES_MATCHING + PATTERN "*.h" + ) + + file(INSTALL + DIRECTORY "${DULLAHAN_DIR}/resources/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/resources" + FILES_MATCHING + PATTERN "*.*" + ) +endif() + +vcpkg_install_copyright(FILE_LIST ${DULLAHAN_DIR}/LICENSES/LICENSE.txt ${DULLAHAN_DIR}/LICENSES/CEF_LICENSE.txt) diff --git a/indra/vcpkg/ports/dullahan-bin/vcpkg.json b/indra/vcpkg/ports/dullahan-bin/vcpkg.json new file mode 100644 index 00000000000..49873234378 --- /dev/null +++ b/indra/vcpkg/ports/dullahan-bin/vcpkg.json @@ -0,0 +1,6 @@ +{ + "name": "dullahan-bin", + "version-semver": "1.26.0", + "port-version": 1, + "license": "MIT" +} diff --git a/indra/vcpkg/ports/libndofdev/portfile.cmake b/indra/vcpkg/ports/libndofdev/portfile.cmake new file mode 100644 index 00000000000..bb31644bfa2 --- /dev/null +++ b/indra/vcpkg/ports/libndofdev/portfile.cmake @@ -0,0 +1,17 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO AlchemyViewer/libndofdev + REF "v${VERSION}" + SHA512 113339c2f4a8666284bd297148f46e4c73bca4e9f5e38644805add674377a4eec99c0b91b625fd552d0906a1ca6da0a29fb5a285e36f4e3029ce32ee029dbb93 + HEAD_REF main +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" +) +vcpkg_cmake_install() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") + diff --git a/indra/vcpkg/ports/libndofdev/vcpkg.json b/indra/vcpkg/ports/libndofdev/vcpkg.json new file mode 100644 index 00000000000..0e1235c3b3b --- /dev/null +++ b/indra/vcpkg/ports/libndofdev/vcpkg.json @@ -0,0 +1,17 @@ +{ + "name": "libndofdev", + "version": "1.0.1", + "description": "3DConnexion SDK", + "homepage": "https://github.com/secondlife/3p-libndofdev", + "license": "BSD-3-Clause", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/indra/vcpkg/ports/minizip/dependencies.diff b/indra/vcpkg/ports/minizip/dependencies.diff new file mode 100644 index 00000000000..1e850c19ce6 --- /dev/null +++ b/indra/vcpkg/ports/minizip/dependencies.diff @@ -0,0 +1,69 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index c684e3e..c3b6fff 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -254,7 +254,7 @@ if(MZ_BZIP2) + list(APPEND MINIZIP_LIB ${BZIP2_LIBRARIES}) + list(APPEND MINIZIP_LBD ${BZIP2_LIBRARY_DIRS}) + +- set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lbz2") ++ set(PC_PRIVATE_DEPS "${PC_PRIVATE_DEPS} bzip2") + elseif(MZ_FETCH_LIBS) + clone_repo(bzip2 https://sourceware.org/git/bzip2.git master) + +@@ -298,7 +298,6 @@ if(MZ_LZMA) + if(NOT MZ_FORCE_FETCH_LIBS) + find_package(PkgConfig QUIET) + if(PKGCONFIG_FOUND) +- pkg_check_modules(LIBLZMA liblzma) + endif() + if(NOT LIBLZMA_FOUND) + find_package(LibLZMA QUIET) +@@ -313,7 +312,7 @@ if(MZ_LZMA) + list(APPEND MINIZIP_LIB ${LIBLZMA_LIBRARIES}) + list(APPEND MINIZIP_LBD ${LIBLZMA_LIBRARY_DIRS}) + +- set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -llzma") ++ set(PC_PRIVATE_DEPS "${PC_PRIVATE_DEPS} liblzma") + elseif(MZ_FETCH_LIBS) + set(BUILD_TESTING OFF CACHE BOOL "Build lzma tests" FORCE) + +@@ -344,10 +343,9 @@ if(MZ_ZSTD) + if(NOT MZ_FORCE_FETCH_LIBS) + find_package(PkgConfig QUIET) + if(PKGCONFIG_FOUND) +- pkg_check_modules(ZSTD libzstd) + endif() + if(NOT ZSTD_FOUND) +- find_package(ZSTD QUIET) ++ find_package(ZSTD NAMES zstd REQUIRED) + if(ZSTD_FOUND) + if(TARGET zstd::libzstd_static) + list(APPEND ZSTD_LIBRARIES zstd::libzstd_static) +@@ -365,7 +363,7 @@ if(MZ_ZSTD) + list(APPEND MINIZIP_LIB ${ZSTD_LIBRARIES}) + list(APPEND MINIZIP_LBD ${ZSTD_LIBRARY_DIRS}) + +- set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lzstd") ++ set(PC_PRIVATE_DEPS "${PC_PRIVATE_DEPS} libzstd") + elseif(MZ_FETCH_LIBS) + set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "Build zstd programs") + +@@ -405,7 +403,6 @@ if(MZ_OPENSSL) + # Check to see if openssl installation is present + find_package(PkgConfig) + if(PKGCONFIG_FOUND) +- pkg_check_modules(OPENSSL openssl) + endif() + if(NOT OPENSSL_FOUND) + find_package(OpenSSL) +@@ -426,8 +423,8 @@ if(MZ_OPENSSL) + endif() + + foreach(i ${OPENSSL_LIBRARIES}) +- set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -l${i}") + endforeach() ++ set(PC_PRIVATE_DEPS "${PC_PRIVATE_DEPS} openssl") + else() + message(STATUS "OpenSSL library not found") + diff --git a/indra/vcpkg/ports/minizip/portfile.cmake b/indra/vcpkg/ports/minizip/portfile.cmake new file mode 100644 index 00000000000..c0f4a503d4d --- /dev/null +++ b/indra/vcpkg/ports/minizip/portfile.cmake @@ -0,0 +1,46 @@ +if (VCPKG_TARGET_IS_WINDOWS) + vcpkg_check_linkage(ONLY_STATIC_LIBRARY) +endif() + +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO zlib-ng/minizip-ng + REF "${VERSION}" + SHA512 9ea5dde14acd2f7d1efd0e38b11017b679d3aaabac61552f9c5f4c7f45f2563543e0fbb2d74429c6b1b9c37d8728ebc4f1cf0efad5f71807c11bb8a2a681a556 + HEAD_REF master + PATCHES + dependencies.diff +) + +vcpkg_check_features( + OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + pkcrypt MZ_PKCRYPT + wzaes MZ_WZAES + openssl MZ_OPENSSL + bzip2 MZ_BZIP2 + lzma MZ_LZMA + zlib MZ_ZLIB + zstd MZ_ZSTD +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + ${FEATURE_OPTIONS} + -DMZ_FETCH_LIBS=OFF + -DMZ_ICONV=OFF + -DMZ_COMPAT=ON + -DMZ_ZLIB_FLAVOR="zlib" +) + +vcpkg_cmake_install() + +vcpkg_fixup_pkgconfig() +vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/minizip) +vcpkg_copy_pdbs() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/indra/vcpkg/ports/minizip/vcpkg.json b/indra/vcpkg/ports/minizip/vcpkg.json new file mode 100644 index 00000000000..0376e389335 --- /dev/null +++ b/indra/vcpkg/ports/minizip/vcpkg.json @@ -0,0 +1,70 @@ +{ + "name": "minizip", + "version": "4.1.0", + "description": "minizip-ng is a zip manipulation library written in C that is supported on Windows, macOS, and Linux.", + "homepage": "https://github.com/zlib-ng/minizip-ng", + "license": "Zlib", + "supports": "!uwp", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "default-features": [ + "bzip2", + "zlib" + ], + "features": { + "bzip2": { + "description": "Enables BZIP2 compression", + "dependencies": [ + "bzip2" + ] + }, + "lzma": { + "description": "Enables LZMA compression", + "dependencies": [ + "liblzma" + ] + }, + "openssl": { + "description": "Enables OpenSSL for encryption", + "dependencies": [ + "openssl" + ] + }, + "pkcrypt": { + "description": "Enables PKWARE traditional encryption" + }, + "wzaes": { + "description": "Enables WinZIP AES encryption", + "dependencies": [ + { + "name": "minizip-ng", + "default-features": false, + "features": [ + "openssl" + ], + "platform": "!windows & !osx" + } + ] + }, + "zlib": { + "description": "Enables ZLIB compression", + "dependencies": [ + "zlib" + ] + }, + "zstd": { + "description": "Enables ZSTD compression", + "dependencies": [ + "zstd" + ] + } + } +} diff --git a/indra/vcpkg/ports/nvapi/portfile.cmake b/indra/vcpkg/ports/nvapi/portfile.cmake new file mode 100644 index 00000000000..8fb77f2e82f --- /dev/null +++ b/indra/vcpkg/ports/nvapi/portfile.cmake @@ -0,0 +1,23 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO NVIDIA/nvapi + REF 3d34a4faf095996663321646ebe003539a908f89 + SHA512 56a4633cbdf388448397ae6482d6bce32644119bc809b709f019dad62dbfce95c83edb0f2a2c577431fe5f6b1cc89330550a27b0a8b74d3d835b53b46ce869c0 + HEAD_REF main +) + +file(INSTALL + DIRECTORY "${SOURCE_PATH}/" + DESTINATION "${CURRENT_PACKAGES_DIR}/include/nvapi" + FILES_MATCHING + PATTERN "*.c" + PATTERN "*.h" + PATTERN "amd64" EXCLUDE + PATTERN "docs" EXCLUDE + PATTERN "Sample_Code" EXCLUDE + PATTERN "x86" EXCLUDE +) + +file(INSTALL "${SOURCE_PATH}/amd64/nvapi64.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") + +file(INSTALL "${SOURCE_PATH}/License.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/indra/vcpkg/ports/nvapi/vcpkg.json b/indra/vcpkg/ports/nvapi/vcpkg.json new file mode 100644 index 00000000000..231abebb28a --- /dev/null +++ b/indra/vcpkg/ports/nvapi/vcpkg.json @@ -0,0 +1,8 @@ +{ + "name": "nvapi", + "version-string": "R580", + "description": "NVAPI is NVIDIA's core software development kit that allows direct access to NVIDIA GPUs and drivers on supported platforms.", + "homepage": "https://github.com/NVIDIA/nvapi", + "license": "MIT", + "supports": "windows & x64" +} diff --git a/indra/vcpkg/ports/open-libndofdev/portfile.cmake b/indra/vcpkg/ports/open-libndofdev/portfile.cmake new file mode 100644 index 00000000000..6b9f5f6bdd0 --- /dev/null +++ b/indra/vcpkg/ports/open-libndofdev/portfile.cmake @@ -0,0 +1,17 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO RyeMutt/3p-open-libndofdev + REF "v${VERSION}" + SHA512 e5676a36a1b16f18649221104ec9326e7e37e547bfef23a96bebb2af9fe5e9794697600924ca355d3fb98ec2d4e0e58f432d7690aa42bf7e7394e90eea0daa34 + HEAD_REF main +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}/libndofdev" +) +vcpkg_cmake_install() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/libndofdev/LICENSES/libndofdev.txt") + diff --git a/indra/vcpkg/ports/open-libndofdev/vcpkg.json b/indra/vcpkg/ports/open-libndofdev/vcpkg.json new file mode 100644 index 00000000000..022c567df47 --- /dev/null +++ b/indra/vcpkg/ports/open-libndofdev/vcpkg.json @@ -0,0 +1,18 @@ +{ + "name": "open-libndofdev", + "version": "0.14-r7", + "description": "Linux support for the 3Dconnexion SpaceBall, SpaceNavigator and joysticks in the SecondLife clients", + "homepage": "https://github.com/secondlife/3p-open-libndofdev", + "license": "BSD-3-Clause", + "dependencies": [ + "sdl3", + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/indra/vcpkg/ports/openal-soft/devendor-fmt.diff b/indra/vcpkg/ports/openal-soft/devendor-fmt.diff new file mode 100644 index 00000000000..246a83385f3 --- /dev/null +++ b/indra/vcpkg/ports/openal-soft/devendor-fmt.diff @@ -0,0 +1,45 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index d2a69d4..14fc9b8 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -159,7 +159,8 @@ if(MSVC) + endif() + endif() + +-add_subdirectory(fmt-11.1.1 EXCLUDE_FROM_ALL) ++find_package(fmt CONFIG REQUIRED) ++add_library(alsoft::fmt ALIAS fmt::fmt) + + + set(CPP_DEFS ) # C pre-processor, not C++ +@@ -1440,7 +1441,7 @@ if(LIBTYPE STREQUAL "STATIC") + add_library(${IMPL_TARGET} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS} ${CORE_OBJS}) + target_compile_definitions(${IMPL_TARGET} PUBLIC AL_LIBTYPE_STATIC) + target_link_libraries(${IMPL_TARGET} PRIVATE ${LINKER_FLAGS} ${EXTRA_LIBS} ${MATH_LIB} +- $) ++ alsoft::fmt) + + if(WIN32) + # This option is for static linking OpenAL Soft into another project +diff --git a/OpenALConfig.cmake.in b/OpenALConfig.cmake.in +index 9704d3c..ddabb81 100644 +--- a/OpenALConfig.cmake.in ++++ b/OpenALConfig.cmake.in +@@ -1,3 +1,5 @@ ++include(CMakeFindDependencyMacro) ++find_dependency(fmt CONFIG) + cmake_minimum_required(VERSION 3.1...3.18) + + include("${CMAKE_CURRENT_LIST_DIR}/OpenALTargets.cmake") +diff --git a/openal.pc.in b/openal.pc.in +index dfa6f57..e04e807 100644 +--- a/openal.pc.in ++++ b/openal.pc.in +@@ -6,6 +6,7 @@ includedir=@includedir@ + Name: OpenAL + Description: OpenAL is a cross-platform 3D audio API + Requires: @PKG_CONFIG_REQUIRES@ ++Requires.private: fmt + Version: @PACKAGE_VERSION@ + Libs: -L${libdir} -l@LIBNAME@ @PKG_CONFIG_LIBS@ + Libs.private:@PKG_CONFIG_PRIVATE_LIBS@ diff --git a/indra/vcpkg/ports/openal-soft/pkgconfig-cxx.diff b/indra/vcpkg/ports/openal-soft/pkgconfig-cxx.diff new file mode 100644 index 00000000000..9bc09f83d6d --- /dev/null +++ b/indra/vcpkg/ports/openal-soft/pkgconfig-cxx.diff @@ -0,0 +1,20 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 060a740..d2a69d4 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1379,6 +1379,15 @@ if(LIBTYPE STREQUAL "STATIC") + set(PKG_CONFIG_PRIVATE_LIBS "${PKG_CONFIG_PRIVATE_LIBS} -l${FLAG}") + endif() + endforeach() ++ foreach(lib IN LISTS CMAKE_CXX_IMPLICIT_LINK_LIBRARIES) ++ if(lib IN_LIST CMAKE_C_IMPLICIT_LINK_LIBRARIES) ++ continue() ++ elseif(EXISTS "${lib}") ++ string(APPEND PKG_CONFIG_PRIVATE_LIBS " ${CMAKE_LINK_LIBRARY_FILE_FLAG}${lib}") ++ else() ++ string(APPEND PKG_CONFIG_PRIVATE_LIBS " ${CMAKE_LINK_LIBRARY_FLAG}${lib}") ++ endif() ++ endforeach() + endif() + + # End configuration diff --git a/indra/vcpkg/ports/openal-soft/portfile.cmake b/indra/vcpkg/ports/openal-soft/portfile.cmake new file mode 100644 index 00000000000..d6fdb4af67a --- /dev/null +++ b/indra/vcpkg/ports/openal-soft/portfile.cmake @@ -0,0 +1,115 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO kcat/openal-soft + REF ${VERSION} + SHA512 3eebd18de4984691136738e8fe5851ac5dbdc8f17916cc9dcc599bd3bafc400c9dad9dc88844a9b77b1e8e372a041af342421bdf23746dffe4760f8385bd1e53 + HEAD_REF master + PATCHES + pkgconfig-cxx.diff + devendor-fmt.diff +) + +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + pipewire ALSOFT_BACKEND_PIPEWIRE + pipewire ALSOFT_REQUIRE_PIPEWIRE + pulseaudio ALSOFT_BACKEND_PULSEAUDIO + pulseaudio ALSOFT_REQUIRE_PULSEAUDIO +) + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + set(OPENAL_LIBTYPE "SHARED") +else() + set(OPENAL_LIBTYPE "STATIC") +endif() + +set(ALSOFT_REQUIRE_LINUX OFF) +set(ALSOFT_REQUIRE_WINDOWS OFF) +set(ALSOFT_REQUIRE_WINDOWS_NOT_UWP OFF) +set(ALSOFT_REQUIRE_APPLE OFF) +set(ALSOFT_CPUEXT_NEON OFF) + +if(VCPKG_TARGET_IS_LINUX) + set(ALSOFT_REQUIRE_LINUX ON) +endif() +if(VCPKG_TARGET_IS_WINDOWS) + set(ALSOFT_REQUIRE_WINDOWS ON) + if(NOT VCPKG_TARGET_IS_UWP) + set(ALSOFT_REQUIRE_WINDOWS_NOT_UWP ON) + endif() +endif() +if(VCPKG_TARGET_IS_OSX OR VCPKG_TARGET_IS_IOS) + set(ALSOFT_REQUIRE_APPLE ON) +endif() +if(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm64") + set(ALSOFT_CPUEXT_NEON ON) +endif() + +vcpkg_find_acquire_program(PKGCONFIG) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + ${FEATURE_OPTIONS} + -DALSOFT_CPUEXT_NEON=${ALSOFT_CPUEXT_NEON} + -DALSOFT_EXAMPLES=OFF + -DALSOFT_INSTALL_AMBDEC_PRESETS=OFF + -DALSOFT_INSTALL_CONFIG=OFF + -DALSOFT_INSTALL_HRTF_DATA=OFF + -DALSOFT_NO_CONFIG_UTIL=ON + -DALSOFT_UPDATE_BUILD_VERSION=OFF + -DALSOFT_UTILS=OFF + -DLIBTYPE=${OPENAL_LIBTYPE} + "-DPKG_CONFIG_EXECUTABLE=${PKGCONFIG}" + # order by CMakeLists.txt + -DALSOFT_BACKEND_ALSA=${ALSOFT_REQUIRE_LINUX} + -DALSOFT_REQUIRE_ALSA=${ALSOFT_REQUIRE_LINUX} + -DALSOFT_BACKEND_OSS=OFF + -DALSOFT_BACKEND_SOLARIS=OFF + -DALSOFT_BACKEND_SNDIO=OFF + -DALSOFT_BACKEND_WINMM=OFF + -DALSOFT_BACKEND_DSOUND=${ALSOFT_REQUIRE_WINDOWS_NOT_UWP} + -DALSOFT_REQUIRE_DSOUND=${ALSOFT_REQUIRE_WINDOWS_NOT_UWP} + -DALSOFT_BACKEND_WASAPI=${ALSOFT_REQUIRE_WINDOWS} + -DALSOFT_REQUIRE_WASAPI=${ALSOFT_REQUIRE_WINDOWS} + -DALSOFT_BACKEND_JACK=OFF + -DALSOFT_BACKEND_COREAUDIO=${ALSOFT_REQUIRE_APPLE} + -DALSOFT_REQUIRE_COREAUDIO=${ALSOFT_REQUIRE_APPLE} + -DALSOFT_BACKEND_OBOE=OFF + -DALSOFT_BACKEND_OPENSL=${VCPKG_TARGET_IS_ANDROID} + -DALSOFT_REQUIRE_OPENSL=${VCPKG_TARGET_IS_ANDROID} + -DALSOFT_BACKEND_PORTAUDIO=OFF + -DALSOFT_BACKEND_WAVE=ON + MAYBE_UNUSED_VARIABLES + # NOT WIN32 + ALSOFT_BACKEND_ALSA + ALSOFT_REQUIRE_ALSA + ALSOFT_BACKEND_OSS + ALSOFT_BACKEND_SOLARIS + ALSOFT_BACKEND_SNDIO + # WIN32 + ALSOFT_BACKEND_WINMM + ALSOFT_BACKEND_DSOUND + ALSOFT_REQUIRE_DSOUND + ALSOFT_BACKEND_WASAPI + ALSOFT_REQUIRE_WASAPI +) + +vcpkg_cmake_install() +vcpkg_copy_pdbs() +vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/OpenAL") +vcpkg_fixup_pkgconfig() + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static") + foreach(HEADER IN ITEMS al.h alc.h) + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/AL/${HEADER}" "defined(AL_LIBTYPE_STATIC)" "1") + endforeach() +endif() + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share") + +file(READ "${SOURCE_PATH}/common/pffft.cpp" pffft_license) +string(REGEX REPLACE "[*]/.*" "*/\n" pffft_license "${pffft_license}") +file(WRITE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/pffft Notice" "${pffft_license}") +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/COPYING" "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/pffft Notice") diff --git a/indra/vcpkg/ports/openal-soft/vcpkg.json b/indra/vcpkg/ports/openal-soft/vcpkg.json new file mode 100644 index 00000000000..3d6d6a935ba --- /dev/null +++ b/indra/vcpkg/ports/openal-soft/vcpkg.json @@ -0,0 +1,42 @@ +{ + "name": "openal-soft", + "version": "1.24.3", + "port-version": 1, + "description": "OpenAL Soft is an LGPL-licensed, cross-platform, software implementation of the OpenAL 3D audio API.", + "homepage": "https://github.com/kcat/openal-soft", + "license": "LGPL-2.0-or-later", + "supports": "!xbox", + "dependencies": [ + { + "name": "alsa", + "platform": "linux" + }, + { + "name": "cppwinrt", + "platform": "uwp" + }, + "fmt", + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "features": { + "pipewire": { + "description": "Enable PipeWire backend", + "dependencies": [ + "pipewire" + ] + }, + "pulseaudio": { + "description": "Enable PulseAudio backend", + "dependencies": [ + "pulseaudio" + ] + } + } +} diff --git a/indra/vcpkg/ports/secondlife-certificates/ca-license.txt b/indra/vcpkg/ports/secondlife-certificates/ca-license.txt new file mode 100644 index 00000000000..d0bd7f053be --- /dev/null +++ b/indra/vcpkg/ports/secondlife-certificates/ca-license.txt @@ -0,0 +1,4 @@ +The Certificate Authority bundle included in this package is built +from the data provided by the Mozilla NSS Project: + +https://www.mozilla.org/en-US/about/governance/policies/security-group/certs/ diff --git a/indra/vcpkg/ports/secondlife-certificates/mk-ca-bundle.pl b/indra/vcpkg/ports/secondlife-certificates/mk-ca-bundle.pl new file mode 100644 index 00000000000..d52edbe734b --- /dev/null +++ b/indra/vcpkg/ports/secondlife-certificates/mk-ca-bundle.pl @@ -0,0 +1,675 @@ +#!/usr/bin/env perl +# *************************************************************************** +# * _ _ ____ _ +# * Project ___| | | | _ \| | +# * / __| | | | |_) | | +# * | (__| |_| | _ <| |___ +# * \___|\___/|_| \_\_____| +# * +# * Copyright (C) Daniel Stenberg, , et al. +# * +# * This software is licensed as described in the file COPYING, which +# * you should have received as part of this distribution. The terms +# * are also available at https://curl.se/docs/copyright.html. +# * +# * You may opt to use, copy, modify, merge, publish, distribute and/or sell +# * copies of the Software, and permit persons to whom the Software is +# * furnished to do so, under the terms of the COPYING file. +# * +# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +# * KIND, either express or implied. +# * +# * SPDX-License-Identifier: curl +# * +# *************************************************************************** +# This Perl script creates a fresh ca-bundle.crt file for use with libcurl. +# It downloads certdata.txt from Mozilla's source tree (see URL below), +# then parses certdata.txt and extracts CA Root Certificates into PEM format. +# These are then processed with the OpenSSL commandline tool to produce the +# final ca-bundle.crt file. +# The script is based on the parse-certs script written by Roland Krikava. +# This Perl script works on almost any platform since its only external +# dependency is the OpenSSL commandline tool for optional text listing. +# Hacked by Guenter Knauf. +# +use Encode; +use Getopt::Std; +use MIME::Base64; +use strict; +use warnings; +use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); +use List::Util; +use Text::Wrap; +use Time::Local; +my $MOD_SHA = "Digest::SHA"; +eval "require $MOD_SHA"; +if($@) { + $MOD_SHA = "Digest::SHA::PurePerl"; + eval "require $MOD_SHA"; +} +eval "require LWP::UserAgent"; + +my %urls = ( + 'autoland' => 'https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/autoland/security/nss/lib/ckfw/builtins/certdata.txt', + 'beta' => 'https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/beta/security/nss/lib/ckfw/builtins/certdata.txt', + 'release' => 'https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt', +); + +$opt_d = 'release'; + +# If the OpenSSL commandline is not in search path you can configure it here! +my $openssl = 'openssl'; + +my $version = '1.30'; + +$opt_w = 76; # default base64 encoded lines length + +# default cert types to include in the output (default is to include CAs which +# may issue SSL server certs) +my $default_mozilla_trust_purposes = "SERVER_AUTH"; +my $default_mozilla_trust_levels = "TRUSTED_DELEGATOR"; +$opt_p = $default_mozilla_trust_purposes . ":" . $default_mozilla_trust_levels; + +my @valid_mozilla_trust_purposes = ( + "DIGITAL_SIGNATURE", + "NON_REPUDIATION", + "KEY_ENCIPHERMENT", + "DATA_ENCIPHERMENT", + "KEY_AGREEMENT", + "KEY_CERT_SIGN", + "CRL_SIGN", + "SERVER_AUTH", + "CLIENT_AUTH", + "CODE_SIGNING", + "EMAIL_PROTECTION", + "IPSEC_END_SYSTEM", + "IPSEC_TUNNEL", + "IPSEC_USER", + "TIME_STAMPING", + "STEP_UP_APPROVED" +); + +my @valid_mozilla_trust_levels = ( + "TRUSTED_DELEGATOR", # CAs + "NOT_TRUSTED", # Do not trust these certs. + "MUST_VERIFY_TRUST", # This explicitly tells us that it IS NOT a CA but is + # otherwise ok. In other words, this should tell the + # app to ignore any other sources that claim this is + # a CA. + "TRUSTED" # This cert is trusted, but only for itself and not + # for delegates (i.e. it is not a CA). +); + +my $default_signature_algorithms = $opt_s = "SHA256"; + +my @valid_signature_algorithms = ( + "MD5", + "SHA1", + "SHA256", + "SHA384", + "SHA512" +); + +$0 =~ s@.*(/|\\)@@; +$Getopt::Std::STANDARD_HELP_VERSION = 1; +getopts('bd:fhiklmnp:qs:tuvw:'); + +if(!defined($opt_d)) { + # to make plain "-d" use not cause warnings, and actually still work + $opt_d = 'release'; +} + +# Use predefined URL or else custom URL specified on command line. +my $url; +if(defined($urls{$opt_d})) { + $url = $urls{$opt_d}; + if(!$opt_k && $url !~ /^https:\/\//i) { + die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n"; + } +} +else { + $url = $opt_d; +} + +if($opt_i) { + print ("=" x 78 . "\n"); + print "Script Version : $version\n"; + print "Perl Version : $]\n"; + print "Operating System Name : $^O\n"; + print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; + print "Encode::Encoding.pm Version : ${Encode::Encoding::VERSION}\n"; + print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; + print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n" if($LWP::UserAgent::VERSION); + print "LWP.pm Version : ${LWP::VERSION}\n" if($LWP::VERSION); + print "Digest::SHA.pm Version : ${Digest::SHA::VERSION}\n" if($Digest::SHA::VERSION); + print "Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION}\n" if($Digest::SHA::PurePerl::VERSION); + print ("=" x 78 . "\n"); +} + +sub warning_message() { + if($opt_d =~ m/^risk$/i) { # Long Form Warning and Exit + print "Warning: Use of this script may pose some risk:\n"; + print "\n"; + print " 1) If you use HTTP URLs they are subject to a man in the middle attack\n"; + print " 2) Default to 'release', but more recent updates may be found in other trees\n"; + print " 3) certdata.txt file format may change, lag time to update this script\n"; + print " 4) Generally unwise to blindly trust CAs without manual review & verification\n"; + print " 5) Mozilla apps use additional security checks are not represented in certdata\n"; + print " 6) Use of this script will make a security engineer grind his teeth and\n"; + print " swear at you. ;)\n"; + exit; + } else { # Short Form Warning + print "Warning: Use of this script may pose some risk, -d risk for more details.\n"; + } +} + +sub HELP_MESSAGE() { + print "Usage:\t${0} [-b] [-d] [-f] [-i] [-k] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; + print "\t-b\tbackup an existing version of ca-bundle.crt\n"; + print "\t-d\tspecify Mozilla tree to pull certdata.txt or custom URL\n"; + print "\t\t Valid names are:\n"; + print "\t\t ", join( ", ", map { ( $_ =~ m/$opt_d/ ) ? "$_ (default)" : "$_" } sort keys %urls ), "\n"; + print "\t-f\tforce rebuild even if certdata.txt is current\n"; + print "\t-i\tprint version info about used modules\n"; + print "\t-k\tallow URLs other than HTTPS, enable HTTP fallback (insecure)\n"; + print "\t-l\tprint license info about certdata.txt\n"; + print "\t-m\tinclude meta data in output\n"; + print "\t-n\tno download of certdata.txt (to use existing)\n"; + print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; + print "\t\t Valid purposes are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_purposes ) ), "\n"; + print "\t\t Valid levels are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_mozilla_trust_levels ) ), "\n"; + print "\t-q\tbe really quiet (no progress output at all)\n"; + print wrap("\t","\t\t", "-s\tcomma separated list of certificate signatures/hashes to output in plain text mode. (default: $default_signature_algorithms)\n"); + print "\t\t Valid signature algorithms are:\n"; + print wrap("\t\t ","\t\t ", join( ", ", "ALL", @valid_signature_algorithms ) ), "\n"; + print "\t-t\tinclude plain text listing of certificates\n"; + print "\t-u\tunlink (remove) certdata.txt after processing\n"; + print "\t-v\tbe verbose and print out processed CAs\n"; + print "\t-w \twrap base64 output lines after chars (default: ${opt_w})\n"; + exit; +} + +sub VERSION_MESSAGE() { + print "${0} version ${version} running Perl ${]} on ${^O}\n"; +} + +warning_message() unless ($opt_q || $url =~ m/^(ht|f)tps:/i ); +HELP_MESSAGE() if($opt_h); + +sub report($@) { + my $output = shift; + + print STDERR $output . "\n" unless $opt_q; +} + +sub is_in_list($@) { + my $target = shift; + + return defined(List::Util::first { $target eq $_ } @_); +} + +# Parses $param_string as a case insensitive comma separated list with optional +# whitespace validates that only allowed parameters are supplied +sub parse_csv_param($$@) { + my $description = shift; + my $param_string = shift; + my @valid_values = @_; + + my @values = map { + s/^\s+//; # strip leading spaces + s/\s+$//; # strip trailing spaces + uc $_ # return the modified string as upper case + } split( ',', $param_string ); + + # Find all values which are not in the list of valid values or "ALL" + my @invalid = grep { !is_in_list($_,"ALL",@valid_values) } @values; + + if(scalar(@invalid) > 0) { + # Tell the user which parameters were invalid and print the standard help + # message which will exit + print "Error: Invalid ", $description, scalar(@invalid) == 1 ? ": " : "s: ", join( ", ", map { "\"$_\"" } @invalid ), "\n"; + HELP_MESSAGE(); + } + + @values = @valid_values if(is_in_list("ALL",@values)); + + return @values; +} + +sub sha256 { + my $result; + if($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION) { + open(FILE, $_[0]) or die "Could not open '$_[0]': $!"; + binmode(FILE); + $result = $MOD_SHA->new(256)->addfile(*FILE)->hexdigest; + close(FILE); + } else { + # Use OpenSSL command if Perl Digest::SHA modules not available + open(my $fh, '-|', $openssl, 'dgst', '-r', '-sha256', $_[0]) or die "Failed running openssl on '$_[0]': $!"; + $result = <$fh>; # read first line + close $fh; + $result =~ s/^([0-9a-f]{64}) .+/$1/is; + } + return $result; +} + + +sub oldhash { + my $hash = ""; + open(C, "<$_[0]") || return 0; + while() { + chomp; + if($_ =~ /^\#\# SHA256: (.*)/) { + $hash = $1; + last; + } + } + close(C); + return $hash; +} + +if($opt_p !~ m/:/) { + print "Error: Mozilla trust identifier list must include both purposes and levels\n"; + HELP_MESSAGE(); +} + +(my $included_mozilla_trust_purposes_string, my $included_mozilla_trust_levels_string) = split( ':', $opt_p ); +my @included_mozilla_trust_purposes = parse_csv_param( "trust purpose", $included_mozilla_trust_purposes_string, @valid_mozilla_trust_purposes ); +my @included_mozilla_trust_levels = parse_csv_param( "trust level", $included_mozilla_trust_levels_string, @valid_mozilla_trust_levels ); + +my @included_signature_algorithms = parse_csv_param( "signature algorithm", $opt_s, @valid_signature_algorithms ); + +sub should_output_cert(%) { + my %trust_purposes_by_level = @_; + + foreach my $level (@included_mozilla_trust_levels) { + # for each level we want to output, see if any of our desired purposes are + # included + return 1 if(defined( List::Util::first { is_in_list( $_, @included_mozilla_trust_purposes ) } @{$trust_purposes_by_level{$level}} )); + } + + return 0; +} + +my $crt = $ARGV[0] || 'ca-bundle.crt'; +(my $txt = $url) =~ s@(.*/|\?.*)@@g; + +my $stdout = $crt eq '-'; +my $resp; +my $fetched; + +my $oldhash = oldhash($crt); + +report "SHA256 of old file: $oldhash"; + +if(!$opt_n) { + report "Downloading $txt ..."; + + # If we have an HTTPS URL then use curl + if($url =~ /^https:\/\//i) { + my $curl = `curl -V`; + if($curl) { + if($curl =~ /^Protocols:.* https( |$)/m) { + report "Get certdata with curl!"; + my @opts = (); + push @opts, '--proto', '=https' if !$opt_k; + push @opts, '-s' if $opt_q; + my $out = ''; + if(open(my $fh, '-|', 'curl', '-Lw', '%{response_code}', (@opts), '-o', $txt, $url)) { + $out = <$fh>; # read first line + chomp $out; + close $fh; + } + if($out && $out == 200) { + $fetched = 1; + report "Downloaded $txt"; + } + else { + report "Failed downloading via HTTPS with curl"; + if(-e $txt && !unlink($txt)) { + report "Failed to remove '$txt': $!"; + } + } + } + else { + report "curl lacks https support"; + } + } + else { + report "curl not found"; + } + } + + # If nothing was fetched then use LWP + if(!$fetched) { + if($url =~ /^https:\/\//i) { + report "Falling back to HTTP"; + $url =~ s/^https:\/\//http:\/\//i; + } + if(!$opt_k) { + report "URLs other than HTTPS are disabled by default, to enable use -k"; + exit 1; + } + report "Get certdata with LWP!"; + if(!defined(${LWP::UserAgent::VERSION})) { + report "LWP is not available (LWP::UserAgent not found)"; + exit 1; + } + my $ua = new LWP::UserAgent(agent => "$0/$version"); + $ua->env_proxy(); + $resp = $ua->mirror($url, $txt); + if($resp && $resp->code eq '304') { + report "Not modified"; + exit 0 if -e $crt && !$opt_f; + } + else { + $fetched = 1; + report "Downloaded $txt"; + } + if(!$resp || $resp->code !~ /^(?:200|304)$/) { + report "Unable to download latest data: " + . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed"); + exit 1 if -e $crt || ! -r $txt; + } + } +} + +my $filedate = $resp ? $resp->last_modified : (stat($txt))[9]; +my $datesrc = "as of"; +if(!$filedate) { + # mxr.mozilla.org gave us a time, hg.mozilla.org does not! + $filedate = time(); + $datesrc="downloaded on"; +} + +# get the hash from the download file +my $newhash= sha256($txt); + +if(!$opt_f && $oldhash eq $newhash) { + report "Downloaded file identical to previous run\'s source file. Exiting"; + if($opt_u && -e $txt && !unlink($txt)) { + report "Failed to remove $txt: $!\n"; + } + exit; +} + +report "SHA256 of new file: $newhash"; + +my $currentdate = scalar gmtime($filedate); + +my $format = $opt_t ? "plain text and " : ""; +if($stdout) { + open(CRT, '> -') or die "Could not open STDOUT: $!\n"; +} else { + open(CRT,">$crt.~") or die "Could not open $crt.~: $!\n"; +} +print CRT <) { + if(/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { + print CRT; + print if($opt_l); + while() { + print CRT; + print if($opt_l); + last if(/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); + } + next; + } + # The input file format consists of blocks of Mozilla objects. + # The blocks are separated by blank lines but may be related. + elsif(/^\s*$/) { + $main_block = 0; + $trust_block = 0; + next; + } + # Each certificate has a main block. + elsif(/^# Certificate "(.*)"/) { + (!$main_block && !$trust_block) or die "Unexpected certificate block"; + $main_block = 1; + $main_block_name = $1; + # Reset all other certificate variables. + $trust_block = 0; + $trust_block_name = ""; + $valid = 0; + $start_of_cert = 0; + $caname = ""; + $cka_value = ""; + undef @precert; + next; + } + # Each certificate's main block is followed by a trust block. + elsif(/^# Trust for (?:Certificate )?"(.*)"/) { + (!$main_block && !$trust_block) or die "Unexpected trust block"; + $trust_block = 1; + $trust_block_name = $1; + if($main_block_name ne $trust_block_name) { + die "cert name \"$main_block_name\" != trust name \"$trust_block_name\""; + } + next; + } + # Ignore other blocks. + # + # There is a documentation comment block, a BEGINDATA block, and a bunch of + # blocks starting with "# Explicitly Distrust ". + # + # The latter is for certificates that have already been removed and are not + # included. Not all explicitly distrusted certificates are ignored at this + # point, just those without an actual certificate. + elsif(!$main_block && !$trust_block) { + next; + } + elsif(/^#/) { + # The commented lines in a main block are plaintext metadata that describes + # the certificate. Issuer, Subject, Fingerprint, etc. + if($main_block) { + push @precert, $_ if not /^#$/; + if(/^# Not Valid After : (.*)/) { + my $stamp = $1; + use Time::Piece; + # Not Valid After : Thu Sep 30 14:01:15 2021 + my $t = Time::Piece->strptime($stamp, "%a %b %d %H:%M:%S %Y"); + my $delta = ($t->epoch - time()); # negative means no longer valid + if($delta < 0) { + $skipnum++; + report "Skipping: $main_block_name is not valid anymore" if($opt_v); + $valid = 0; + } + else { + $valid = 1; + } + } + } + next; + } + elsif(!$valid) { + next; + } + + chomp; + + if($main_block) { + if(/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { + !$start_of_cert or die "Duplicate CKO_CERTIFICATE object"; + $start_of_cert = 1; + next; + } + elsif(!$start_of_cert) { + next; + } + elsif(/^CKA_LABEL UTF8 \"(.*)\"/) { + ($caname eq "") or die "Duplicate CKA_LABEL attribute"; + $caname = $1; + if($caname ne $main_block_name) { + die "caname \"$caname\" != cert name \"$main_block_name\""; + } + next; + } + elsif(/^CKA_VALUE MULTILINE_OCTAL/) { + ($cka_value eq "") or die "Duplicate CKA_VALUE attribute"; + while() { + last if(/^END/); + chomp; + my @octets = split(/\\/); + shift @octets; + for(@octets) { + $cka_value .= chr(oct); + } + } + next; + } + else { + next; + } + } + + if(!$trust_block || !$start_of_cert || $caname eq "" || $cka_value eq "") { + die "Certificate extraction failed"; + } + + my %trust_purposes_by_level; + + if(/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/) { + # now scan the trust part to determine how we should trust this cert + while() { + if(/^\s*$/) { + $trust_block = 0; + last; + } + if(/^CKA_TRUST_([A-Z_]+)\s+CK_TRUST\s+CKT_NSS_([A-Z_]+)\s*$/) { + if(!is_in_list($1,@valid_mozilla_trust_purposes)) { + report "Warning: Unrecognized trust purpose for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } elsif(!is_in_list($2,@valid_mozilla_trust_levels)) { + report "Warning: Unrecognized trust level for cert: $caname. Trust purpose: $1. Trust Level: $2"; + } else { + push @{$trust_purposes_by_level{$2}}, $1; + } + } + } + + # Sanity check that an explicitly distrusted certificate only has trust + # purposes with a trust level of NOT_TRUSTED. + # + # Certificate objects that are explicitly distrusted are in a certificate + # block that starts # Certificate "Explicitly Distrust(ed) ", + # where "Explicitly Distrust(ed) " was prepended to the original cert name. + if($caname =~ /distrust/i || + $main_block_name =~ /distrust/i || + $trust_block_name =~ /distrust/i) { + my @levels = keys %trust_purposes_by_level; + if(scalar(@levels) != 1 || $levels[0] ne "NOT_TRUSTED") { + die "\"$caname\" must have all trust purposes at level NOT_TRUSTED."; + } + } + + if(!should_output_cert(%trust_purposes_by_level)) { + $skipnum ++; + report "Skipping: $caname lacks acceptable trust level" if($opt_v); + } else { + my $encoded = MIME::Base64::encode_base64($cka_value, ''); + $encoded =~ s/(.{1,${opt_w}})/$1\n/g; + my $pem = "-----BEGIN CERTIFICATE-----\n" + . $encoded + . "-----END CERTIFICATE-----\n"; + print CRT "\n$caname\n"; + my $maxStringLength = length(decode('UTF-8', $caname, Encode::FB_CROAK | Encode::LEAVE_SRC)); + print CRT ("=" x $maxStringLength . "\n"); + if($opt_t) { + foreach my $key (sort keys %trust_purposes_by_level) { + my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); + print CRT $string . "\n"; + } + } + if($opt_m) { + print CRT for @precert; + } + if(!$opt_t) { + print CRT $pem; + } else { + my $pipe = ""; + foreach my $hash (@included_signature_algorithms) { + $pipe = "|$openssl x509 -" . $hash . " -fingerprint -noout -inform PEM"; + if(!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Could not close $crt.~: $!"; + } + open(TMP, $pipe) or die "Could not open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Could not close openssl pipe: $!"; + if(!$stdout) { + open(CRT, ">>$crt.~") or die "Could not open $crt.~: $!"; + } + } + $pipe = "|$openssl x509 -text -inform PEM"; + if(!$stdout) { + $pipe .= " >> $crt.~"; + close(CRT) or die "Could not close $crt.~: $!"; + } + open(TMP, $pipe) or die "Could not open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Could not close openssl pipe: $!"; + if(!$stdout) { + open(CRT, ">>$crt.~") or die "Could not open $crt.~: $!"; + } + } + report "Processed: $caname" if($opt_v); + $certnum++; + } + } +} +close(TXT) or die "Could not close $txt: $!\n"; +close(CRT) or die "Could not close $crt.~: $!\n"; +unless($stdout) { + if($opt_b && -e $crt) { + my $bk = 1; + while(-e "$crt.~${bk}~") { + $bk++; + } + rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n"; + } elsif(-e $crt) { + unlink($crt) or die "Failed to remove $crt: $!\n"; + } + rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; +} +if($opt_u && -e $txt && !unlink($txt)) { + report "Failed to remove $txt: $!\n"; +} +report "Done ($certnum CA certs processed, $skipnum skipped)."; diff --git a/indra/vcpkg/ports/secondlife-certificates/portfile.cmake b/indra/vcpkg/ports/secondlife-certificates/portfile.cmake new file mode 100644 index 00000000000..f167a64f58e --- /dev/null +++ b/indra/vcpkg/ports/secondlife-certificates/portfile.cmake @@ -0,0 +1,43 @@ +set(VCPKG_POLICY_EMPTY_INCLUDE_FOLDER enabled) + +vcpkg_download_distfile( + LLCA_ARCHIVE + URLS "https://github.com/secondlife/llca/releases/download/v202407221723.0-a0fd5b9/llca-202407221423.0-common-10042698865.tar.zst" + FILENAME llca.tar.zst + SHA512 8abfb35394a4c32ad0c6d0b042c0bad44be84f60cab5c170fa8a965b45eb5baf21559c4840be41422cf95ad26803f3314fc1a2a0e3391460cc29de32c051d246 +) + +vcpkg_extract_source_archive(LLCA_DIR ARCHIVE ${LLCA_ARCHIVE} NO_REMOVE_ONE_LEVEL) + +file(INSTALL "${LLCA_DIR}/ca-bundle.crt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") +message(STATUS "Importing certstore done") + +vcpkg_install_copyright(FILE_LIST "${LLCA_DIR}/LICENSES/ca-license.txt") + +# Below is the routine required to generate this package using vcpkg +# vcpkg_find_acquire_program(PERL) +# get_filename_component(PERL_EXE_PATH ${PERL} DIRECTORY) +# set(ENV{PATH} "$ENV{PATH};${PERL_EXE_PATH}") + +# vcpkg_find_acquire_program(PERL) + +# vcpkg_download_distfile( +# LLCA_ARCHIVE +# URLS "https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/tags/FIREFOX_147_0_1_BUILD1/security/nss/lib/ckfw/builtins/certdata.txt" +# FILENAME certdata.txt +# SHA512 64fb1e7912fa5d2379728038563635161983ee7a0ca4a79c6a61b71d808d28a93ef768e5b15c8b408ec62c0e6dfafd449de0d3eb14468cd34b615265f2ed7a91 +# ) + +# file(COPY ${LLCA_ARCHIVE} DESTINATION "${CURRENT_BUILDTREES_DIR}") +# file(COPY "${CMAKE_CURRENT_LIST_DIR}/mk-ca-bundle.pl" DESTINATION "${CURRENT_BUILDTREES_DIR}") + +# vcpkg_execute_required_process( +# COMMAND ${PERL} ${CURRENT_BUILDTREES_DIR}/mk-ca-bundle.pl -n ${CURRENT_BUILDTREES_DIR}/ca-bundle.crt +# WORKING_DIRECTORY ${CURRENT_BUILDTREES_DIR} +# LOGNAME ca-bundle +# ) + +# file(INSTALL "${CURRENT_BUILDTREES_DIR}/ca-bundle.crt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") +# message(STATUS "Importing certstore done") + +# vcpkg_install_copyright(FILE_LIST ${CMAKE_CURRENT_LIST_DIR}/ca-license.txt) diff --git a/indra/vcpkg/ports/secondlife-certificates/vcpkg.json b/indra/vcpkg/ports/secondlife-certificates/vcpkg.json new file mode 100644 index 00000000000..2e4a955e61c --- /dev/null +++ b/indra/vcpkg/ports/secondlife-certificates/vcpkg.json @@ -0,0 +1,5 @@ +{ + "name": "secondlife-certificates", + "version-string": "2024.0722.1723", + "license": "MPL-2.0" +} diff --git a/indra/vcpkg/ports/secondlife-dictionaries/portfile.cmake b/indra/vcpkg/ports/secondlife-dictionaries/portfile.cmake new file mode 100644 index 00000000000..fef811f6cef --- /dev/null +++ b/indra/vcpkg/ports/secondlife-dictionaries/portfile.cmake @@ -0,0 +1,37 @@ +# vcpkg_from_github( +# OUT_SOURCE_PATH SOURCE_PATH +# REPO secondlife/3p-dictionaries +# REF "v${VERSION}" +# SHA512 0 +# HEAD_REF main +# ) + +vcpkg_download_distfile( + DICTIONARIES_ARCHIVE + URLS https://github.com/secondlife/3p-dictionaries/releases/download/v1-a01bb6c/dictionaries-1.a01bb6c-common-a01bb6c.tar.zst + FILENAME dictionaries.tar.zst + SHA512 95c0f27727ea7b9e6af3f2fd25e560d93edd678fc6104ca74c0765ef9ae957cceacf029d159b1eb25571fdde0a721b956a59483e1820d1357e42a5c94a72ae86 +) + +vcpkg_extract_source_archive( + DICTIONARIES_DIR + ARCHIVE ${DICTIONARIES_ARCHIVE} + NO_REMOVE_ONE_LEVEL +) + +file(INSTALL + DIRECTORY "${DICTIONARIES_DIR}/dictionaries/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/dictionaries/" + FILES_MATCHING + PATTERN "*.xml" + PATTERN "*.aff" + PATTERN "*.dic" +) + +vcpkg_install_copyright(FILE_LIST + "${DICTIONARIES_DIR}/LICENSES/dictionaries.txt" + "${DICTIONARIES_DIR}/LICENSES/en_gb-dictionary-license.txt" + "${DICTIONARIES_DIR}/LICENSES/en_us-dictionary-license.txt" + "${DICTIONARIES_DIR}/LICENSES/es_es-dictionary-license.txt" + "${DICTIONARIES_DIR}/LICENSES/pt_br-dictionary-license.txt" +) diff --git a/indra/vcpkg/ports/secondlife-dictionaries/vcpkg.json b/indra/vcpkg/ports/secondlife-dictionaries/vcpkg.json new file mode 100644 index 00000000000..b40eaa338a1 --- /dev/null +++ b/indra/vcpkg/ports/secondlife-dictionaries/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "secondlife-dictionaries", + "version-string": "1.0.0-a01bb6c" +} diff --git a/indra/vcpkg/ports/secondlife-emoji-shortcodes/gen_emoji_characters.py b/indra/vcpkg/ports/secondlife-emoji-shortcodes/gen_emoji_characters.py new file mode 100644 index 00000000000..394cc1ca8fd --- /dev/null +++ b/indra/vcpkg/ports/secondlife-emoji-shortcodes/gen_emoji_characters.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +"""\ +@file gen_emoji_characters.py + +$LicenseInfo:firstyear=2025&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2025, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" +import argparse +import json +import os +import glob + +parser = argparse.ArgumentParser(description='Generate per-language emoji character list') +parser.add_argument('root_path', help='Path to the root directory containing subfolders with JSON files.') +parser.add_argument('output_dir', help='Path to the output directory where generated XML files will be stored.') +args = parser.parse_args() + +ROOT_PATH = args.root_path +OUTPUT_DIR = args.output_dir + +print(ROOT_PATH) +print(OUTPUT_DIR) + +# Constants +# Note: There is no support for Turkish (TR) characters currently +# si SL Viewer short-code support will be limited to English +ALLOWED_FOLDERS = {'da', 'de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'pt', 'ru', 'tr', 'zh'} + +# Create output directory if it don't exist +output_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), OUTPUT_DIR) +os.makedirs(output_path, exist_ok=True) + +def process_folder(data_file, cldr_file, emojibase_file, messages_file, output_file, folder_name): + # Read and parse JSON files with specified encoding + with open(data_file, 'r', encoding='utf-8') as f1: + data = json.load(f1) + + with open(cldr_file, 'r', encoding='utf-8') as f2: + cldr = json.load(f2) + + if os.path.isfile(emojibase_file): + with open(emojibase_file, 'r', encoding='utf-8') as f3: + emojibase = json.load(f3) + else: + emojibase = None + + with open(messages_file, 'r', encoding='utf-8') as f4: + messages = json.load(f4) + + # Generate the desired output + output = [] + + groups = messages['groups'] + subgroups = messages['subgroups'] + + for item in data: + hexcode = item['hexcode'] + short_code = emojibase.get(hexcode) if emojibase else None + if not short_code: + short_code = cldr.get(hexcode) + + if '-' in hexcode: + # Log unsupported multi-character emojis to the console + #print(f"Unsupported multi-character emoji '{hexcode}' with shortcode ':{short_code}:' in folder {folder_name}") + continue + + if not short_code: + print(f"Error: Shortcode not found for hexcode '{hexcode}' in folder {folder_name}") + continue + + # Convert hexcode to Unicode character + character = chr(int(hexcode, 16)) + + # Get categories from groups and subgroups if they exist + group = next((g['message'] for g in groups if item.get('group') is not None and g['order'] == item['group']), '') + subgroup = next((sg['message'] for sg in subgroups if item.get('subgroup') is not None and sg['order'] == item['subgroup']), '') + + # The ampersand character is illegal in an XML file outside + # of the CDATA section. They appear frequently in the groups/subgroup + # tags - "smileys & emotions" for example - so we must replace them + group=group.replace(" & ", " & ") + subgroup=subgroup.replace(" & ", " & ") + + xml_shortcodes = ("".join([f'\t\t\t\t:{code}:\n' for code in short_code]) if isinstance(short_code, list) else f'\t\t\t\t:{short_code}:\n') + + map_element = ( + '\t\t\n' + '\t\t\tCharacter\n' + f'\t\t\t{character}\n' + '\t\t\tShortCodes\n' + '\t\t\t\n' + f'{xml_shortcodes}' + '\t\t\t\n' + '\t\t\tCategories\n' + '\t\t\t\n' + + (f'\t\t\t\t{group}\n' if group else '') + + (f'\t\t\t\t{subgroup}\n' if subgroup else '') + + '\t\t\t\n' + '\t\t' + ) + output.append(map_element) + + # Header + xml_header = '\n\n' + + # Warning against editing manually at the top of each file + # Ideally, this would be right at the top but it seems like + # comments can only appear after the initial tag. + xml_header += '\t\n' + xml_header += '\t\n' + + # Footer + xml_footer = '\t\n' + + output_str = xml_header + '\n'.join(output) + xml_footer + + # Write the output to a file with specified encoding + with open(output_file, 'w', encoding='utf-8') as outfile: + outfile.write(output_str) + +# Add allowed folder names +allowed_folders = {'da', 'de', 'en', 'es', 'fr', 'it', 'ja', 'pl', 'pt', 'ru', 'tr', 'zh'} + +# Process each subfolder +for subfolder in glob.glob(os.path.join(ROOT_PATH, '*')): + if os.path.isdir(subfolder): + folder_name = os.path.basename(subfolder) + + # Skip processing if folder_name not in allowed_folders + if folder_name not in ALLOWED_FOLDERS: + continue + + print(f"Processing folder: {folder_name}") + + data_file = os.path.join(subfolder, 'data.raw.json') + cldr_file = os.path.join(subfolder, 'shortcodes', 'cldr.raw.json') + emojibase_file = os.path.join(subfolder, 'shortcodes', 'emojibase.raw.json') + messages_file = os.path.join(subfolder, 'messages.raw.json') + + # Create output subfolder if it doesn't exist + output_subfolder = os.path.join(output_path, folder_name) + os.makedirs(output_subfolder, exist_ok=True) + + output_file = os.path.join(output_subfolder, 'emoji_characters.xml') + + if os.path.isfile(data_file) and os.path.isfile(cldr_file) and os.path.isfile(messages_file): + process_folder(data_file, cldr_file, emojibase_file, messages_file, output_file, folder_name) diff --git a/indra/vcpkg/ports/secondlife-emoji-shortcodes/portfile.cmake b/indra/vcpkg/ports/secondlife-emoji-shortcodes/portfile.cmake new file mode 100644 index 00000000000..f901671270d --- /dev/null +++ b/indra/vcpkg/ports/secondlife-emoji-shortcodes/portfile.cmake @@ -0,0 +1,16 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO milesj/emojibase + REF emojibase-data@${VERSION} + SHA512 59e51c16f6580085b4ef80ff79ec164ebc9c982f302ba7677daf65097ceed78cfad17cf865d0e3194aa2115733112eb8d09c6b4b2397cbdb993d90c90c9a4826 + HEAD_REF master +) + +vcpkg_find_acquire_program(PYTHON3) + +vcpkg_execute_required_process( + COMMAND ${PYTHON3} "${CURRENT_PORT_DIR}/gen_emoji_characters.py" "${SOURCE_PATH}/packages/data" "${CURRENT_PACKAGES_DIR}/share/${PORT}/xui" + WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}" + LOGNAME "build-${TARGET_TRIPLET}-dbg") + +vcpkg_install_copyright(FILE_LIST ${SOURCE_PATH}/LICENSE) diff --git a/indra/vcpkg/ports/secondlife-emoji-shortcodes/vcpkg.json b/indra/vcpkg/ports/secondlife-emoji-shortcodes/vcpkg.json new file mode 100644 index 00000000000..e0c5ff53506 --- /dev/null +++ b/indra/vcpkg/ports/secondlife-emoji-shortcodes/vcpkg.json @@ -0,0 +1,6 @@ +{ + "name": "secondlife-emoji-shortcodes", + "version": "16.0.3", + "homepage": "https://github.com/milesj/emojibase", + "license": "MIT" +} diff --git a/indra/vcpkg/ports/secondlife-fonts/portfile.cmake b/indra/vcpkg/ports/secondlife-fonts/portfile.cmake new file mode 100644 index 00000000000..2f57be291f6 --- /dev/null +++ b/indra/vcpkg/ports/secondlife-fonts/portfile.cmake @@ -0,0 +1,17 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO secondlife/3p-viewer-fonts + REF "v${VERSION}" + SHA512 d78571fe96a6b8bb102c07dc7efea4c61d01e27891b94465d741f169ccb107633c7764aa92101cb01be50964d28845c99b67c103952a0a758cc55f88d07a6537 + HEAD_REF main +) + +file(INSTALL + DIRECTORY "${SOURCE_PATH}/src/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/fonts" + FILES_MATCHING + PATTERN "*.ttf" + PATTERN "*.otf" +) + +vcpkg_install_copyright(FILE_LIST ${SOURCE_PATH}/src/DejaVu-license.txt ${SOURCE_PATH}/src/Twemoji-Artwork-CC-BY-license.txt ${SOURCE_PATH}/src/Twemoji-MIT-license.txt) diff --git a/indra/vcpkg/ports/secondlife-fonts/vcpkg.json b/indra/vcpkg/ports/secondlife-fonts/vcpkg.json new file mode 100644 index 00000000000..d8284d75090 --- /dev/null +++ b/indra/vcpkg/ports/secondlife-fonts/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "secondlife-fonts", + "version-semver": "1.1.0-r1" +} diff --git a/indra/vcpkg/ports/slvoice/portfile.cmake b/indra/vcpkg/ports/slvoice/portfile.cmake new file mode 100644 index 00000000000..788f88ef00f --- /dev/null +++ b/indra/vcpkg/ports/slvoice/portfile.cmake @@ -0,0 +1,90 @@ +set(VCPKG_POLICY_ALLOW_OBSOLETE_MSVCRT enabled) +set(VCPKG_POLICY_MISMATCHED_NUMBER_OF_BINARIES enabled) +set(VCPKG_FIXUP_MACHO_RPATH OFF) +set(VCPKG_FIXUP_ELF_RPATH OFF) + +if(VCPKG_TARGET_IS_WINDOWS) + vcpkg_download_distfile( + SLVOICE_ARCHIVE + URLS https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-windows64-5942f08.tar.zst + FILENAME slvoice-win64.tar.zst + SHA512 4bd5cd37e07f03e1e94f67189499cb8283cfa70804b6d83d5ff821fdc1cb6ecc7b6d3fdde5413ce161918a1d9b40eb7ce76c7c5fe45b068b0a3adee42f231dde + ) + + vcpkg_extract_source_archive( + SLVOICE_DIR + ARCHIVE ${SLVOICE_ARCHIVE} + NO_REMOVE_ONE_LEVEL + ) + + file(INSTALL + DIRECTORY "${SLVOICE_DIR}/bin/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/windows64" + FILES_MATCHING + PATTERN "*.exe" + PATTERN "*.pdb" + ) + + file(INSTALL + DIRECTORY "${SLVOICE_DIR}/lib/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/windows64" + FILES_MATCHING + PATTERN "*.dll" + PATTERN "*.pdb" + ) + + vcpkg_install_copyright(FILE_LIST ${SLVOICE_DIR}/LICENSES/vivox_licenses.txt ${SLVOICE_DIR}/LICENSES/vivox_sdk_license.txt) +elseif(VCPKG_TARGET_IS_OSX) + vcpkg_download_distfile( + SLVOICE_ARCHIVE + URLS https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-darwin64-5942f08.tar.zst + FILENAME slvoice-darwin64.tar.zst + SHA512 cc686f685d324ddeda86e68dca732adadb31dd6c6fa0ecc1d879f3321a6bb37561170da27d7d46f77a2609b1999384f67a2909ed626196e8732e7e32ca4a8ae5 + ) + + vcpkg_extract_source_archive( + SLVOICE_DIR + ARCHIVE ${SLVOICE_ARCHIVE} + NO_REMOVE_ONE_LEVEL + ) + + file(INSTALL + DIRECTORY "${SLVOICE_DIR}/bin/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/darwin64" + FILES_MATCHING + PATTERN "SLVoice" + ) + + file(INSTALL + DIRECTORY "${SLVOICE_DIR}/lib/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/darwin64" + FILES_MATCHING + PATTERN "*.dylib" + ) + + vcpkg_install_copyright(FILE_LIST ${SLVOICE_DIR}/LICENSES/vivox_licenses.txt ${SLVOICE_DIR}/LICENSES/vivox_sdk_license.txt) +elseif(VCPKG_TARGET_IS_LINUX) + vcpkg_download_distfile( + SLVOICE_ARCHIVE + URLS http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/613/1289/slvoice-3.2.0002.10426.500605-linux64-500605.tar.bz2 + FILENAME slvoice-linux.tar.zst + SHA512 2941da523a5495fc56e841d2ef855d8eefaf74795e809adf09cc91924599ba38974963d937d9d529c153619c92e30a12aa24d7e4baa7d0a4cee859ba4a59996e + ) + + vcpkg_extract_source_archive( + SLVOICE_DIR + ARCHIVE ${SLVOICE_ARCHIVE} + NO_REMOVE_ONE_LEVEL + ) + + file(INSTALL + DIRECTORY "${SLVOICE_DIR}/lib/release/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/linux" + USE_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.so*" + PATTERN "SLVoice" + ) + + vcpkg_install_copyright(FILE_LIST ${SLVOICE_DIR}/LICENSES/slvoice.txt) +endif() diff --git a/indra/vcpkg/ports/slvoice/vcpkg.json b/indra/vcpkg/ports/slvoice/vcpkg.json new file mode 100644 index 00000000000..cc32af80b19 --- /dev/null +++ b/indra/vcpkg/ports/slvoice/vcpkg.json @@ -0,0 +1,4 @@ +{ + "name": "slvoice", + "version-string": "4.10.0000.32327" +} diff --git a/indra/vcpkg/ports/tracy/build-tools.patch b/indra/vcpkg/ports/tracy/build-tools.patch new file mode 100644 index 00000000000..8c0cb2ee33d --- /dev/null +++ b/indra/vcpkg/ports/tracy/build-tools.patch @@ -0,0 +1,38 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 72901a8c..365724a8 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -193,3 +193,15 @@ if(TRACY_CLIENT_PYTHON) + + add_subdirectory(python) + endif() ++ ++option(VCPKG_CLI_TOOLS "library" OFF) ++option(VCPKG_GUI_TOOLS "library" OFF) ++if(VCPKG_CLI_TOOLS) ++ add_subdirectory(csvexport) ++ add_subdirectory(capture) ++ add_subdirectory(import) ++ add_subdirectory(update) ++endif() ++if(VCPKG_GUI_TOOLS) ++ add_subdirectory(profiler) ++endif() +diff --git a/cmake/server.cmake b/cmake/server.cmake +index c12a3408..0d55cf91 100644 +--- a/cmake/server.cmake ++++ b/cmake/server.cmake +@@ -1,3 +1,4 @@ ++include_guard(GLOBAL) + set(TRACY_COMMON_DIR ${CMAKE_CURRENT_LIST_DIR}/../public/common) + + set(TRACY_COMMON_SOURCES +diff --git a/cmake/vendor.cmake b/cmake/vendor.cmake +index 29f12cfa..40b3e078 100644 +--- a/cmake/vendor.cmake ++++ b/cmake/vendor.cmake +@@ -1,3 +1,4 @@ ++include_guard(GLOBAL) + # Vendor Specific CMake + # The Tracy project keeps most vendor source locally + diff --git a/indra/vcpkg/ports/tracy/portfile.cmake b/indra/vcpkg/ports/tracy/portfile.cmake new file mode 100644 index 00000000000..d09c390cf66 --- /dev/null +++ b/indra/vcpkg/ports/tracy/portfile.cmake @@ -0,0 +1,74 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO wolfpld/tracy + REF "v${VERSION}" + SHA512 18c0c589a1d97d0760958c8ab00ba2135bc602fd359d48445b5d8ed76e5b08742d818bb8f835b599149030f455e553a92db86fb7bae049b47820e4401cf9f935 + HEAD_REF master + PATCHES + build-tools.patch +) + +vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS + FEATURES + ipv4-only TRACY_ONLY_IPV4 + localhost TRACY_ONLY_LOCALHOST + no-broadcast TRACY_NO_BROADCAST + on-demand TRACY_ON_DEMAND + fibers TRACY_FIBERS + verbose TRACY_VERBOSE + INVERTED_FEATURES + crash-handler TRACY_NO_CRASH_HANDLER +) + +vcpkg_check_features(OUT_FEATURE_OPTIONS TOOLS_OPTIONS + FEATURES + cli-tools VCPKG_CLI_TOOLS + gui-tools VCPKG_GUI_TOOLS +) + +if("cli-tools" IN_LIST FEATURES OR "gui-tools" IN_LIST FEATURES) + vcpkg_find_acquire_program(PKGCONFIG) + list(APPEND TOOLS_OPTIONS "-DPKG_CONFIG_EXECUTABLE=${PKGCONFIG}") +endif() + +vcpkg_cmake_configure( + SOURCE_PATH ${SOURCE_PATH} + OPTIONS + -DDOWNLOAD_CAPSTONE=OFF + -DLEGACY=ON + ${FEATURE_OPTIONS} + OPTIONS_RELEASE + ${TOOLS_OPTIONS} + MAYBE_UNUSED_VARIABLES + DOWNLOAD_CAPSTONE + LEGACY +) +vcpkg_cmake_install() +# Need to manually fix debug file locations on windows +if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_BUILD_TYPE STREQUAL "release") + file(COPY_FILE "${CURRENT_PACKAGES_DIR}/debug/bin/Debug/TracyClient.dll" "${CURRENT_PACKAGES_DIR}/debug/bin/TracyClient.dll") +endif() + +vcpkg_copy_pdbs() +vcpkg_cmake_config_fixup(PACKAGE_NAME Tracy CONFIG_PATH "lib/cmake/Tracy") + +function(tracy_copy_tool tool_name tool_dir) + vcpkg_copy_tools( + TOOL_NAMES "${tool_name}" + SEARCH_DIR "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/${tool_dir}" + ) +endfunction() + +if("cli-tools" IN_LIST FEATURES) + tracy_copy_tool(tracy-capture capture) + tracy_copy_tool(tracy-csvexport csvexport) + tracy_copy_tool(tracy-import-chrome import) + tracy_copy_tool(tracy-import-fuchsia import) + tracy_copy_tool(tracy-update update) +endif() +if("gui-tools" IN_LIST FEATURES) + tracy_copy_tool(tracy-profiler profiler) +endif() + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") diff --git a/indra/vcpkg/ports/tracy/vcpkg.json b/indra/vcpkg/ports/tracy/vcpkg.json new file mode 100644 index 00000000000..e94836d1397 --- /dev/null +++ b/indra/vcpkg/ports/tracy/vcpkg.json @@ -0,0 +1,99 @@ +{ + "name": "tracy", + "version": "0.13.1", + "port-version": 2, + "description": "A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.", + "homepage": "https://github.com/wolfpld/tracy", + "license": "BSD-3-Clause", + "supports": "!(windows & (arm | uwp))", + "dependencies": [ + { + "name": "pthreads", + "platform": "!windows" + }, + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ], + "default-features": [ + "crash-handler" + ], + "features": { + "cli-tools": { + "description": "Build Tracy command-line tools: `capture`, `csvexport`, `import-chrome`, `import-fuchsia` and `update`", + "supports": "!(windows & x86)", + "dependencies": [ + { + "name": "capstone", + "features": [ + "arm", + "arm64", + "x86" + ] + }, + { + "name": "dbus", + "default-features": false, + "platform": "!windows" + }, + "freetype", + "glfw3", + { + "name": "tbb", + "platform": "!windows" + } + ] + }, + "crash-handler": { + "description": "Enable crash handler" + }, + "fibers": { + "description": "Enable fibers support" + }, + "gui-tools": { + "description": "Build Tracy GUI tool: `profiler` (aka `Tracy` executable)", + "supports": "!(windows & x86)", + "dependencies": [ + { + "name": "capstone", + "features": [ + "arm", + "arm64", + "x86" + ] + }, + { + "name": "dbus", + "default-features": false, + "platform": "!windows" + }, + "freetype", + "glfw3", + { + "name": "tbb", + "platform": "!windows" + } + ] + }, + "ipv4-only": { + "description": "Disable ipv6 networking support" + }, + "localhost": { + "description": "Enable tracy for localhost usage only" + }, + "no-broadcast": { + "description": "Disable network broadcast of tracy clients" + }, + "on-demand": { + "description": "Enable on-demand profiling" + }, + "verbose": { + "description": "Enables verbose logging" + } + } +} diff --git a/indra/vcpkg/ports/v-hacd/portfile.cmake b/indra/vcpkg/ports/v-hacd/portfile.cmake new file mode 100644 index 00000000000..4338bbad9b8 --- /dev/null +++ b/indra/vcpkg/ports/v-hacd/portfile.cmake @@ -0,0 +1,11 @@ +# Header-only library +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO kmammou/v-hacd + REF "v${VERSION}" + SHA512 b974c490897a1901d6975c75222a167a70f9e2a37e0c548aeb6a346cb0154ec1415947d47d69a729c0c4d9345aed70d3c09d4bf297beacfae66ceb4c8c89c6d0 + HEAD_REF master +) + +file(INSTALL "${SOURCE_PATH}/include/VHACD.h" DESTINATION "${CURRENT_PACKAGES_DIR}/include") +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/indra/vcpkg/ports/v-hacd/vcpkg.json b/indra/vcpkg/ports/v-hacd/vcpkg.json new file mode 100644 index 00000000000..5240db2e06e --- /dev/null +++ b/indra/vcpkg/ports/v-hacd/vcpkg.json @@ -0,0 +1,6 @@ +{ + "name": "v-hacd", + "version": "4.1.0", + "description": "The V-HACD library decomposes a 3D surface into a set of \"near\" convex parts.", + "homepage": "https://github.com/kmammou/v-hacd" +} diff --git a/indra/vcpkg/ports/viewer-manager/portfile.cmake b/indra/vcpkg/ports/viewer-manager/portfile.cmake new file mode 100644 index 00000000000..3d37dfba532 --- /dev/null +++ b/indra/vcpkg/ports/viewer-manager/portfile.cmake @@ -0,0 +1,36 @@ +set(VCPKG_POLICY_ALLOW_OBSOLETE_MSVCRT enabled) +set(VCPKG_POLICY_MISMATCHED_NUMBER_OF_BINARIES enabled) +set(VCPKG_FIXUP_MACHO_RPATH OFF) + +if(VCPKG_TARGET_IS_WINDOWS) + vcpkg_download_distfile( + VMP_ARCHIVE + URLS https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-windows64-f14b5ec.tar.zst + FILENAME vmp-win64.tar.zst + SHA512 e9faccde36989b4bc177b3eca1f4c5d183d812038b2cf2022e716622474f9aa4c6d5fbbc6e2e02c75465590dcea7e34439b15aedb8eb378a7dd345d7ff7463cf + ) +elseif(VCPKG_TARGET_IS_OSX) + vcpkg_download_distfile( + VMP_ARCHIVE + URLS https://github.com/secondlife/viewer-manager/releases/download/v3.0-f14b5ec-D591/viewer_manager-3.0-f14b5ec-darwin64-f14b5ec.tar.zst + FILENAME vmp-darwin64.tar.zst + SHA512 3b311bf3722493f8f2c6520356f7b299e50d90fd4f90eacf33281d2af9676c24ec288b0af795ad3c9cd86a64efdf25a06cfd61fb5e0c23fdcc7770c77ae8cd5e + ) +endif() + +vcpkg_extract_source_archive( + VMP_DIR + ARCHIVE ${VMP_ARCHIVE} + NO_REMOVE_ONE_LEVEL +) + +file(INSTALL + DIRECTORY "${VMP_DIR}/VMP/" + DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}/" + USE_SOURCE_PERMISSIONS + FILES_MATCHING + PATTERN "*.exe" + PATTERN "SLVersionChecker" +) + +vcpkg_install_copyright(FILE_LIST ${VMP_DIR}/LICENSE) diff --git a/indra/vcpkg/ports/viewer-manager/vcpkg.json b/indra/vcpkg/ports/viewer-manager/vcpkg.json new file mode 100644 index 00000000000..bf1ff12a738 --- /dev/null +++ b/indra/vcpkg/ports/viewer-manager/vcpkg.json @@ -0,0 +1,5 @@ +{ + "name": "viewer-manager", + "version-string": "3.0.1", + "license": "LGPL-2.1-only" +} diff --git a/indra/vcpkg/ports/vlc-bin/portfile.cmake b/indra/vcpkg/ports/vlc-bin/portfile.cmake new file mode 100644 index 00000000000..71b90bcaddb --- /dev/null +++ b/indra/vcpkg/ports/vlc-bin/portfile.cmake @@ -0,0 +1,59 @@ +set(VCPKG_POLICY_ALLOW_OBSOLETE_MSVCRT enabled) +set(VCPKG_POLICY_MISMATCHED_NUMBER_OF_BINARIES enabled) +set(VCPKG_FIXUP_MACHO_RPATH OFF) + +if(VCPKG_TARGET_IS_WINDOWS) + vcpkg_download_distfile( + VLC_ARCHIVE + URLS https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.296d9f4/vlc_bin-3.0.21.11968962952-windows64-11968962952.tar.zst + FILENAME vlc-win64.tar.zst + SHA512 22641ec278317b3a00549aa4b8b1e0606e5c8e2ca9c5a830c4254adc3fe0674bce15d8bbff51aa40f3c48482553ff9a5d654fa69a6a23d7a10abfa8236d1dce5 + ) +elseif(VCPKG_TARGET_IS_OSX) + vcpkg_download_distfile( + VLC_ARCHIVE + URLS https://github.com/secondlife/3p-vlc-bin/releases/download/v3.0.21.296d9f4/vlc_bin-3.0.21.11968962952-darwin64-11968962952.tar.zst + FILENAME vlc-darwin64.tar.zst + SHA512 f6ce2fa90d07a2a3f229f28516e9e77f180cb9783217c4a6b790e03f90a81efdc890dce422f5e4a584d04f7f3b73089a4d7bc04cf2129268feee6243e69bc1bf + ) +endif() + +vcpkg_extract_source_archive(VLC_DIR ARCHIVE ${VLC_ARCHIVE} NO_REMOVE_ONE_LEVEL) + +file(INSTALL + DIRECTORY "${VLC_DIR}/include/vlc/" + DESTINATION "${CURRENT_PACKAGES_DIR}/include/vlc" + FILES_MATCHING + PATTERN "*.h" +) + +if(VCPKG_TARGET_IS_WINDOWS) + file(INSTALL "${VLC_DIR}/lib/release/libvlc.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") + file(INSTALL "${VLC_DIR}/lib/release/libvlccore.lib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib") + + file(INSTALL "${VLC_DIR}/bin/release/libvlc.dll" DESTINATION "${CURRENT_PACKAGES_DIR}/bin") + file(INSTALL "${VLC_DIR}/bin/release/libvlccore.dll" DESTINATION "${CURRENT_PACKAGES_DIR}/bin") + + file(INSTALL + DIRECTORY "${VLC_DIR}/bin/release/plugins/" + DESTINATION "${CURRENT_PACKAGES_DIR}/plugins/${PORT}/plugins" + FILES_MATCHING + PATTERN "*.dll" + PATTERN "*.so" + PATTERN "*.dat" + ) +elseif(VCPKG_TARGET_IS_OSX) + file(INSTALL "${VLC_DIR}/lib/release/libvlc.dylib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib" FOLLOW_SYMLINK_CHAIN) + file(INSTALL "${VLC_DIR}/lib/release/libvlccore.dylib" DESTINATION "${CURRENT_PACKAGES_DIR}/lib" FOLLOW_SYMLINK_CHAIN) + + file(INSTALL + DIRECTORY "${VLC_DIR}/lib/release/plugins/" + DESTINATION "${CURRENT_PACKAGES_DIR}/plugins/${PORT}/plugins" + FILES_MATCHING + PATTERN "*.dylib" + PATTERN "*.so" + PATTERN "*.dat" + ) +endif() + +vcpkg_install_copyright(FILE_LIST "${VLC_DIR}/LICENSES/vlc.txt") diff --git a/indra/vcpkg/ports/vlc-bin/vcpkg.json b/indra/vcpkg/ports/vlc-bin/vcpkg.json new file mode 100644 index 00000000000..8ecaef7ed96 --- /dev/null +++ b/indra/vcpkg/ports/vlc-bin/vcpkg.json @@ -0,0 +1,5 @@ +{ + "name": "vlc-bin", + "version-semver": "3.0.21", + "license": "LGPL-2.1-only" +} diff --git a/indra/vcpkg/ports/webrtc-bin/portfile.cmake b/indra/vcpkg/ports/webrtc-bin/portfile.cmake new file mode 100644 index 00000000000..87104fba75d --- /dev/null +++ b/indra/vcpkg/ports/webrtc-bin/portfile.cmake @@ -0,0 +1,50 @@ +set(VCPKG_POLICY_ALLOW_EMPTY_FOLDERS enabled) +set(VCPKG_POLICY_ALLOW_OBSOLETE_MSVCRT enabled) +set(VCPKG_POLICY_MISMATCHED_NUMBER_OF_BINARIES enabled) + +if(VCPKG_TARGET_IS_WINDOWS) + set(WEBRTC_LIBNAME "webrtc.lib") + + vcpkg_download_distfile( + WEBRTC_ARCHIVE + URLS https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-windows64-18609120431.tar.zst + FILENAME webrtc-windows64.tar.zst + SHA512 810c6bfaec734c48d799c603aed5843ba8600fb6221d08437f73c382af5d86b46e75ea3957ae7b242032756008c202ea73cfc2a0c0070227bd77b33bc48a56d4 + ) +elseif(VCPKG_TARGET_IS_OSX) + set(WEBRTC_LIBNAME "libwebrtc.a") + + vcpkg_download_distfile( + WEBRTC_ARCHIVE + URLS https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-darwin64-18609120431.tar.zst + FILENAME webrtc-osx.tar.zst + SHA512 0c037b32ed5fedff0e2afe480f08983afe7d72dbfd2fa01e6749678e14ae94bff1ef402a0246feb5977eaa43467748fc729c1ab9c410465a03679b9dcac5f38a + ) +elseif(VCPKG_TARGET_IS_LINUX) + set(WEBRTC_LIBNAME "libwebrtc.a") + + vcpkg_download_distfile( + WEBRTC_ARCHIVE + URLS https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.21/webrtc-m137.7151.04.21.18609120431-linux64-18609120431.tar.zst + FILENAME webrtc-linux64.tar.zst + SHA512 44f52c8c0fc3efe64428c90da3f4ac322ba3c107a5ab42851b59b27e324d984cbeed7aefa8e1ff83b3cf5e3092ca86214ed4bacc0c13ea2836f6e53ce6f38ecd + ) +endif() + +vcpkg_extract_source_archive( + WEBRTC_DIR + ARCHIVE ${WEBRTC_ARCHIVE} + NO_REMOVE_ONE_LEVEL +) + +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/include/") +file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/lib/") +file(RENAME "${WEBRTC_DIR}/include/webrtc/" "${CURRENT_PACKAGES_DIR}/include/webrtc/") +if (VCPKG_TARGET_IS_LINUX) + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/include/webrtc/build/linux/debian_bullseye_i386-sysroot") + file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/include/webrtc/build/linux/debian_bullseye_amd64-sysroot") +endif() + +file(RENAME "${WEBRTC_DIR}/lib/release/${WEBRTC_LIBNAME}" "${CURRENT_PACKAGES_DIR}/lib/${WEBRTC_LIBNAME}") + +vcpkg_install_copyright(FILE_LIST ${WEBRTC_DIR}/LICENSES/webrtc-license.txt) diff --git a/indra/vcpkg/ports/webrtc-bin/vcpkg.json b/indra/vcpkg/ports/webrtc-bin/vcpkg.json new file mode 100644 index 00000000000..32ca41b1566 --- /dev/null +++ b/indra/vcpkg/ports/webrtc-bin/vcpkg.json @@ -0,0 +1,5 @@ +{ + "name": "webrtc-bin", + "version-string": "137.7151.0421", + "license": "MIT" +} diff --git a/indra/vcpkg/ports/zlib/portfile.cmake b/indra/vcpkg/ports/zlib/portfile.cmake new file mode 100644 index 00000000000..5ec9f3e96ab --- /dev/null +++ b/indra/vcpkg/ports/zlib/portfile.cmake @@ -0,0 +1,74 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO zlib-ng/zlib-ng + REF "${VERSION}" + SHA512 e2057c764f1d5aaee738edee7e977182c5b097e3c95489dcd8de813f237d92a05daaa86d68d44b331d9fec5d1802586a8f6cfb658ba849874aaa14e72a8107f5 + HEAD_REF develop +) + +# Set ZLIB_COMPAT in the triplet file to turn on +if(NOT DEFINED ZLIB_COMPAT) + set(ZLIB_COMPAT ON) +endif() + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" + OPTIONS + "-DZLIB_FULL_VERSION=${ZLIB_FULL_VERSION}" + -DZLIB_ENABLE_TESTS=OFF + -DWITH_NEW_STRATEGIES=ON + -DZLIB_COMPAT=${ZLIB_COMPAT} + OPTIONS_RELEASE + -DWITH_OPTIM=ON +) +vcpkg_cmake_install() +file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") + +# Condition in `WIN32`, from https://github.com/zlib-ng/zlib-ng/blob/2.1.5/CMakeLists.txt#L1081-L1100 +# (dynamic) for `zlib` or (static `MSVC) for `zlibstatic` or default `z` +# i.e. (windows) and not (static mingw) https://learn.microsoft.com/en-us/vcpkg/maintainers/variables#vcpkg_target_is_system +if(VCPKG_TARGET_IS_WINDOWS AND (NOT (VCPKG_LIBRARY_LINKAGE STREQUAL static AND VCPKG_TARGET_IS_MINGW))) + set(_port_suffix) + if(ZLIB_COMPAT) + set(_port_suffix "") + else() + set(_port_suffix "-ng") + endif() + + set(_port_output_name) + if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic") + set(_port_output_name "zlib${_port_suffix}") + else() + set(_port_output_name "zlibstatic${_port_suffix}") + endif() + + # CMAKE_DEBUG_POSTFIX from https://github.com/zlib-ng/zlib-ng/blob/2.1.5/CMakeLists.txt#L494 + if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/zlib${_port_suffix}.pc" " -lz${_port_suffix}" " -l${_port_output_name}") + endif() + if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/zlib${_port_suffix}.pc" " -lz${_port_suffix}" " -l${_port_output_name}d") + endif() +endif() + +vcpkg_fixup_pkgconfig() +vcpkg_copy_pdbs() + +if(VCPKG_LIBRARY_LINKAGE STREQUAL "static") + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/zconf.h" "ifdef ZLIB_DLL" "if 0") +else() + vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/zconf.h" "ifdef ZLIB_DLL" "if 1") +endif() + +if(ZLIB_COMPAT) + set(_cmake_dir "ZLIB") +else() + set(_cmake_dir "zlib-ng") +endif() +vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/${_cmake_dir}) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share" + "${CURRENT_PACKAGES_DIR}/debug/include" +) +file(COPY "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE.md") diff --git a/indra/vcpkg/ports/zlib/usage b/indra/vcpkg/ports/zlib/usage new file mode 100644 index 00000000000..0dfed74930f --- /dev/null +++ b/indra/vcpkg/ports/zlib/usage @@ -0,0 +1,4 @@ +The package zlib is compatible with built-in CMake targets: + + find_package(ZLIB REQUIRED) + target_link_libraries(main PRIVATE ZLIB::ZLIB) diff --git a/indra/vcpkg/ports/zlib/vcpkg-cmake-wrapper.cmake b/indra/vcpkg/ports/zlib/vcpkg-cmake-wrapper.cmake new file mode 100644 index 00000000000..868a41851a4 --- /dev/null +++ b/indra/vcpkg/ports/zlib/vcpkg-cmake-wrapper.cmake @@ -0,0 +1,12 @@ +find_path(ZLIB_INCLUDE_DIR NAMES zlib.h PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include" NO_DEFAULT_PATH) +find_library(ZLIB_LIBRARY_RELEASE NAMES zlib z PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib" NO_DEFAULT_PATH) +find_library(ZLIB_LIBRARY_DEBUG NAMES zlibd z PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib" NO_DEFAULT_PATH) +if(NOT ZLIB_INCLUDE_DIR OR NOT (ZLIB_LIBRARY_RELEASE OR ZLIB_LIBRARY_DEBUG)) + message(FATAL_ERROR "Broken installation of vcpkg port zlib") +endif() +if(CMAKE_VERSION VERSION_LESS 3.4) + include(SelectLibraryConfigurations) + select_library_configurations(ZLIB) + unset(ZLIB_FOUND) +endif() +_find_package(${ARGS}) diff --git a/indra/vcpkg/ports/zlib/vcpkg.json b/indra/vcpkg/ports/zlib/vcpkg.json new file mode 100644 index 00000000000..f64fa3a361f --- /dev/null +++ b/indra/vcpkg/ports/zlib/vcpkg.json @@ -0,0 +1,17 @@ +{ + "name": "zlib", + "version": "2.3.3", + "description": "zlib replacement with optimizations for 'next generation' systems", + "homepage": "https://github.com/zlib-ng/zlib-ng", + "license": "Zlib", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/indra/vcpkg/triplets/arm64-osx-secondlife-release.cmake b/indra/vcpkg/triplets/arm64-osx-secondlife-release.cmake new file mode 100644 index 00000000000..01414fb3505 --- /dev/null +++ b/indra/vcpkg/triplets/arm64-osx-secondlife-release.cmake @@ -0,0 +1,17 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_BUILD_TYPE release) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES arm64) + +set(VCPKG_OSX_DEPLOYMENT_TARGET 12.0) + +if(PORT MATCHES "hunspell") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() + +if(PORT MATCHES "freealut" OR PORT MATCHES "openal-soft") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() diff --git a/indra/vcpkg/triplets/arm64-osx-secondlife.cmake b/indra/vcpkg/triplets/arm64-osx-secondlife.cmake new file mode 100644 index 00000000000..f54ed0e8541 --- /dev/null +++ b/indra/vcpkg/triplets/arm64-osx-secondlife.cmake @@ -0,0 +1,16 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES arm64) + +set(VCPKG_OSX_DEPLOYMENT_TARGET 12.0) + +if(PORT MATCHES "hunspell") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() + +if(PORT MATCHES "freealut" OR PORT MATCHES "openal-soft") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() diff --git a/indra/vcpkg/triplets/x64-linux-secondlife-release.cmake b/indra/vcpkg/triplets/x64-linux-secondlife-release.cmake new file mode 100644 index 00000000000..e2a19057f91 --- /dev/null +++ b/indra/vcpkg/triplets/x64-linux-secondlife-release.cmake @@ -0,0 +1,6 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_BUILD_TYPE release) + +set(VCPKG_CMAKE_SYSTEM_NAME Linux) diff --git a/indra/vcpkg/triplets/x64-linux-secondlife.cmake b/indra/vcpkg/triplets/x64-linux-secondlife.cmake new file mode 100644 index 00000000000..5196184638b --- /dev/null +++ b/indra/vcpkg/triplets/x64-linux-secondlife.cmake @@ -0,0 +1,5 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +set(VCPKG_CMAKE_SYSTEM_NAME Linux) diff --git a/indra/vcpkg/triplets/x64-osx-secondlife-release.cmake b/indra/vcpkg/triplets/x64-osx-secondlife-release.cmake new file mode 100644 index 00000000000..fe65d7db4aa --- /dev/null +++ b/indra/vcpkg/triplets/x64-osx-secondlife-release.cmake @@ -0,0 +1,17 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) +set(VCPKG_BUILD_TYPE release) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES x86_64) + +set(VCPKG_OSX_DEPLOYMENT_TARGET 12.0) + +if(PORT MATCHES "hunspell") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() + +if(PORT MATCHES "freealut" OR PORT MATCHES "openal-soft") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() diff --git a/indra/vcpkg/triplets/x64-osx-secondlife.cmake b/indra/vcpkg/triplets/x64-osx-secondlife.cmake new file mode 100644 index 00000000000..a1071c5b238 --- /dev/null +++ b/indra/vcpkg/triplets/x64-osx-secondlife.cmake @@ -0,0 +1,16 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +set(VCPKG_CMAKE_SYSTEM_NAME Darwin) +set(VCPKG_OSX_ARCHITECTURES x86_64) + +set(VCPKG_OSX_DEPLOYMENT_TARGET 12.0) + +if(PORT MATCHES "hunspell") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() + +if(PORT MATCHES "freealut" OR PORT MATCHES "openal-soft") + set(VCPKG_LIBRARY_LINKAGE dynamic) +endif() diff --git a/indra/vcpkg/triplets/x64-windows-secondlife-release.cmake b/indra/vcpkg/triplets/x64-windows-secondlife-release.cmake new file mode 100644 index 00000000000..ca4b17c96bc --- /dev/null +++ b/indra/vcpkg/triplets/x64-windows-secondlife-release.cmake @@ -0,0 +1,7 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE dynamic) +set(VCPKG_BUILD_TYPE release) + +set(VCPKG_C_FLAGS_RELEASE "") +set(VCPKG_CXX_FLAGS_RELEASE "/std:c++20 /Zc:__cplusplus") diff --git a/indra/vcpkg/triplets/x64-windows-secondlife.cmake b/indra/vcpkg/triplets/x64-windows-secondlife.cmake new file mode 100644 index 00000000000..036dc813c2c --- /dev/null +++ b/indra/vcpkg/triplets/x64-windows-secondlife.cmake @@ -0,0 +1,6 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE dynamic) + +set(VCPKG_C_FLAGS_RELEASE "") +set(VCPKG_CXX_FLAGS_RELEASE "/std:c++20 /Zc:__cplusplus") diff --git a/indra/viewer_components/login/CMakeLists.txt b/indra/viewer_components/login/CMakeLists.txt index 8381803b038..0b4404768ed 100644 --- a/indra/viewer_components/login/CMakeLists.txt +++ b/indra/viewer_components/login/CMakeLists.txt @@ -1,14 +1,5 @@ # -*- cmake -*- -project(login) - -include(00-Common) -if(LL_TESTS) - include(LLAddBuildTest) -endif(LL_TESTS) -include(LLCommon) -include(LLCoreHttp) - set(login_SOURCE_FILES lllogin.cpp ) @@ -17,12 +8,12 @@ set(login_HEADER_FILES lllogin.h ) -list(APPEND - login_SOURCE_FILES - ${login_HEADER_FILES} +list(APPEND + login_SOURCE_FILES + ${login_HEADER_FILES} ) -add_library(lllogin +add_library(lllogin STATIC ${login_SOURCE_FILES} ) target_include_directories( lllogin INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) @@ -35,7 +26,7 @@ target_link_libraries(lllogin llxml ) -if(LL_TESTS) +if(BUILD_TESTING) SET(lllogin_TEST_SOURCE_FILES lllogin.cpp ) @@ -46,4 +37,4 @@ if(LL_TESTS) ) LL_ADD_PROJECT_UNIT_TESTS(lllogin "${lllogin_TEST_SOURCE_FILES}") -endif(LL_TESTS) +endif() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000000..210cbe5dbd0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# Python modules required by the viewer build and test suite +llsd